diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9d52191..fc4e192 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,12 +21,10 @@ jobs: node-version: 18 - name: Build run: | - sbt test sdk/fullLinkJS + sbt sdk/fullLinkJS cp modules/sdk/target/scala-3.3.1/sdk-opt/main.js modules/sdk/src/main/typescript/index.js cd modules/sdk/src/main/typescript npm install - find model -name "*-ti.ts" -type f -delete - `npm bin`/ts-interface-builder model/*.ts npm link cd ../../../../../frontend npm install diff --git a/build.sbt b/build.sbt index 3c53c8d..09c0fed 100644 --- a/build.sbt +++ b/build.sbt @@ -106,4 +106,6 @@ lazy val backend = (project in file("modules/backend")) fork := true ) -lazy val root = (project in file(".")).aggregate(domain.jvm, backend) +lazy val root = (project in file(".")) + .aggregate(domain.jvm, backend) + .settings(name := "bastoni") diff --git a/frontend/.gitignore b/frontend/.gitignore index c73cf95..a7cc6dc 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -11,6 +11,7 @@ # production /build +/dist # misc .DS_Store diff --git a/frontend/src/App.css b/frontend/src/App.css index de0012e..84102c2 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,10 +1,10 @@ html, body { margin: 0 !important; padding: 0 !important; + overflow: hidden; } body { - background: black; color: white; font-family: 'Open Sans', sans-serif; } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6bdc42c..5553b6f 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,45 +1,39 @@ -import React, {useEffect, useState} from 'react'; +import {useEffect, useState} from 'react'; import './App.css'; -import {fetchAuthToken} from "bastoni/authClient"; -import {GameClientBuilder} from "bastoni/gameClient"; -import {authenticateMessage, connectMessage, joinTableMessage, OutboxMessage} from "bastoni/model/outboxMessage"; -import Card from "./components/Card"; +import {OutboxMessage, pongMessage} from "bastoni/model/outboxMessage"; +import {GameRoom} from "./components/GameRoom"; import {GameType} from "bastoni/model/gameType" -import {CardStyle} from "./view/CardStyle"; -import {Stage} from "@pixi/react"; import {playAgainstComputer} from "bastoni" -import {Room, RoomId} from "bastoni/model/room" -import {CardSuit, CardRank} from "bastoni/model/card" +import {Room} from "bastoni/model/room" import {InboxMessage} from "bastoni/model/inboxMessage" -async function connect() { - const roomId: RoomId = 'ab24cf47-505a-4794-85a6-2866749eb4f5'; - const playerName = 'John Doe'; - const authToken = await fetchAuthToken(playerName, 'localhost:9000', false); - return new GameClientBuilder() - .onReady((client) => client.send(authenticateMessage(authToken))) - .onAuthenticated((user, client) => client.send(connectMessage)) - .onConnected((room, client) => client.send(joinTableMessage)) - .onPlayerJoinedTable((event) => console.log(`${event.user.name} joined the room`)) - .onPlayerLeftTable((event) => console.log(`${event.user.name} left the room`)) - .build(roomId); -} +// async function connect() { +// const roomId: RoomId = 'ab24cf47-505a-4794-85a6-2866749eb4f5'; +// const playerName = 'John Doe'; +// const authToken = await fetchAuthToken(playerName, 'localhost:9000', false); +// return new GameClientBuilder() +// .onReady((client) => client.send(authenticateMessage(authToken))) +// .onAuthenticated((user, client) => client.send(connectMessage)) +// .onConnected((room, client) => client.send(joinTableMessage)) +// .onPlayerJoinedTable((event) => console.log(`${event.user.name} joined the room`)) +// .onPlayerLeftTable((event) => console.log(`${event.user.name} left the room`)) +// .build(roomId); +// } export function App() { const [room, setRoom] = useState(undefined) - const [controller, setController] = useState<(message: OutboxMessage) => void>((message: OutboxMessage) => { - }) useEffect(() => { const cleanup: () => void = playAgainstComputer( 'Me', GameType.Briscola, - (message: InboxMessage, room: Room) => { + (message: InboxMessage, room?: Room) => { console.log(message) + console.log(room) setRoom(room) }, - (sendMessage: (message: OutboxMessage) => void) => setController(sendMessage) + (sendMessage: (message: OutboxMessage) => void) => sendMessage(pongMessage) ) console.info("Game loaded") return () => { @@ -56,45 +50,9 @@ export function App() { // }) return ( - - - - - - //
- //
- // logo - //

- // Edit src/App.tsx and save to reload. - //

- // - //
- //
+ <> + {room ? :

loading

} + ); } diff --git a/frontend/src/components/Card.tsx b/frontend/src/components/Card.tsx index d23222d..503264a 100644 --- a/frontend/src/components/Card.tsx +++ b/frontend/src/components/Card.tsx @@ -1,8 +1,9 @@ import {Sprite} from "@pixi/react"; import CardLayout from "../view/CardLayout"; import {isVisible} from "bastoni/model/card"; -import napoletane from "../view/cards/napoletane/resources"; -import piacentine from "../view/cards/piacentine/resources"; +import napoletane from "../view/cards/napoletane"; +import piacentine from "../view/cards/piacentine"; +import retro from "../view/cards/retro.tsx"; import {CardStyle} from "../view/CardStyle"; import {useEffect, useState} from "react"; import {Texture} from "pixi.js"; @@ -10,12 +11,12 @@ import {Texture} from "pixi.js"; export default function Card(layout: CardLayout) { - const [card, setCard] = useState(null); + const [card, setCard] = useState(undefined); const svgs = layout.style === CardStyle.Piacentine ? piacentine : napoletane; useEffect(() => { async function loadCard() { - const uri = isVisible(layout.card) ? svgs[layout.card.suit][layout.card.rank] : './cards/retro.svg'; + const uri = isVisible(layout.card) ? svgs[layout.card.suit][layout.card.rank] : retro; setCard(await Texture.fromURL(uri)); } diff --git a/frontend/src/components/Deck.tsx b/frontend/src/components/Deck.tsx deleted file mode 100644 index 6ed5a03..0000000 --- a/frontend/src/components/Deck.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import CardLayout from "../view/CardLayout"; - -export default function Deck(cards: CardLayout[]) { - -} \ No newline at end of file diff --git a/frontend/src/components/GameRoom.tsx b/frontend/src/components/GameRoom.tsx new file mode 100644 index 0000000..2994f2e --- /dev/null +++ b/frontend/src/components/GameRoom.tsx @@ -0,0 +1,52 @@ +import {Room} from "bastoni/model/room" +import {CardSuit, CardRank} from "bastoni/model/card" +import {Stage, Text} from "@pixi/react"; +import Card from "./Card.tsx"; +import {CardStyle} from "../view/CardStyle.ts"; +import {TextStyle} from "pixi.js"; + +interface RoomProps { + room: Room +} + +export function GameRoom({room}: RoomProps) { + return ( + + + + + + + + ) +} \ No newline at end of file diff --git a/frontend/src/view/RoomLayout.ts b/frontend/src/view/RoomLayout.ts index 79eca48..dd9ffec 100644 --- a/frontend/src/view/RoomLayout.ts +++ b/frontend/src/view/RoomLayout.ts @@ -1,7 +1,7 @@ import {Room} from "bastoni/model/room"; import CardLayout from "./CardLayout"; import {CardStyle} from "./CardStyle"; -import {isActing, PlayerState} from "bastoni/model/player"; +import {isActing} from "bastoni/model/player"; export default class RoomLayout { deck: CardLayout[] diff --git a/frontend/src/view/cards/napoletane/resources.tsx b/frontend/src/view/cards/napoletane.tsx similarity index 100% rename from frontend/src/view/cards/napoletane/resources.tsx rename to frontend/src/view/cards/napoletane.tsx diff --git a/frontend/src/view/cards/piacentine/resources.tsx b/frontend/src/view/cards/piacentine.tsx similarity index 100% rename from frontend/src/view/cards/piacentine/resources.tsx rename to frontend/src/view/cards/piacentine.tsx diff --git a/frontend/src/view/cards/retro.tsx b/frontend/src/view/cards/retro.tsx new file mode 100644 index 0000000..cefb695 --- /dev/null +++ b/frontend/src/view/cards/retro.tsx @@ -0,0 +1,3 @@ +const retro = './cards/retro.svg' + +export default retro \ No newline at end of file diff --git a/modules/domain/src/main/scala/bastoni/domain/logic/GameController.scala b/modules/domain/src/main/scala/bastoni/domain/logic/GameController.scala index d6e5753..51c7922 100644 --- a/modules/domain/src/main/scala/bastoni/domain/logic/GameController.scala +++ b/modules/domain/src/main/scala/bastoni/domain/logic/GameController.scala @@ -4,9 +4,7 @@ import bastoni.domain.model.* import bastoni.domain.model.Command.* import bastoni.domain.model.Event.* import bastoni.domain.view.{FromPlayer, ToPlayer} -import bastoni.domain.view.FromPlayer.GameCommand -import cats.effect.{Resource, Sync} -import cats.effect.syntax.all.* +import cats.effect.Sync import cats.syntax.all.* import cats.Monad import org.typelevel.log4cats.Logger @@ -20,7 +18,21 @@ trait GamePublisher[F[_]]: def publish(me: User, roomId: RoomId)(input: fs2.Stream[F, FromPlayer]): fs2.Stream[F, Unit] def publish1(me: User, roomId: RoomId)(input: FromPlayer): F[Unit] -trait GameController[F[_]] extends GameSubscriber[F] with GamePublisher[F] +trait GameController[F[_]] extends GameSubscriber[F] with GamePublisher[F]: + def connectPlayer(me: User, roomId: RoomId): fs2.Stream[F, (ToPlayer, Option[RoomPlayerView])] = + subscribe(me, roomId) + .takeThrough { + case ToPlayer.Disconnected(_) => false + case _ => true + } + .zipWithScan1(Option.empty[RoomPlayerView]) { + case (_, ToPlayer.Connected(room)) => Some(room) + case (_, ToPlayer.Disconnected(_)) => None + case (room, ToPlayer.Request(request)) => room.map(_.withRequest(request)) + case (room, ToPlayer.GameEvent(event)) => room.map(_.update(event)) + case (room, ToPlayer.Authenticated(_)) => room + case (room, ToPlayer.Ping) => room + } object GameController: diff --git a/modules/domain/src/test/scala/bastoni/domain/logic/IntegrationSpec.scala b/modules/domain/src/test/scala/bastoni/domain/logic/IntegrationSpec.scala index 1d7acae..06f6b9f 100644 --- a/modules/domain/src/test/scala/bastoni/domain/logic/IntegrationSpec.scala +++ b/modules/domain/src/test/scala/bastoni/domain/logic/IntegrationSpec.scala @@ -62,7 +62,7 @@ class IntegrationSpec extends AsyncIOFreeSpec: delayDuration = if realSpeed then Delay.default else { - case Delay.ActionTimeout => 100.millis + case Delay.ActionTimeout => 2.hours case _ => 2.millis } ) diff --git a/modules/domain/src/test/scala/bastoni/domain/logic/PlayerConnectionSpec.scala b/modules/domain/src/test/scala/bastoni/domain/logic/PlayerConnectionSpec.scala new file mode 100644 index 0000000..3954074 --- /dev/null +++ b/modules/domain/src/test/scala/bastoni/domain/logic/PlayerConnectionSpec.scala @@ -0,0 +1,54 @@ +package bastoni.domain.logic + +import bastoni.domain.AsyncIOFreeSpec +import bastoni.domain.model.Event.{PlayerJoinedTable, PlayerLeftTable} +import bastoni.domain.model.{RoomId, User, UserId} +import bastoni.domain.view.{FromPlayer, ToPlayer} +import cats.effect.IO + +class PlayerConnectionSpec extends AsyncIOFreeSpec: + private val me = User(UserId.newId, "me") + private val roomId = RoomId.newId + + "A player can connect and join a table" in { + val input = fs2.Stream( + FromPlayer.Connect, + FromPlayer.JoinTable, + FromPlayer.LeaveTable + ) + + Services + .inMemory[IO] + .use { case (controller, run) => + controller + .connectPlayer(me, roomId) + .take(3) + .concurrently(controller.publish(me, roomId)(input)) + .concurrently(run) + .compile + .toList + } + .asserting { + case (msg1, room1) :: (msg2, room2) :: (msg3, room3) :: Nil => + msg1 shouldBe a[ToPlayer.Connected] + msg2 match + case ToPlayer.GameEvent(PlayerJoinedTable(joiner, _)) => + joiner shouldBe me + case _ => + fail("Unexpected message #2") + msg3 match + case ToPlayer.GameEvent(PlayerLeftTable(leaver, _)) => + leaver shouldBe me + case _ => + fail("Unexpected message #3") + + room1.fold(fail("Room not returned"))(_.players.get(me.id) shouldBe None) + room2.fold(fail("Room not returned"))(_.players.get(me.id) shouldBe Some(me)) + room2.fold(fail("Room not returned"))(_.seatFor(me) shouldBe defined) + room3.fold(fail("Room not returned"))(_.players.get(me.id) shouldBe Some(me)) + room3.fold(fail("Room not returned"))(_.seatFor(me) should not be defined) + + case msgs => fail(s"Unexpected number of messages produced: ${msgs.length}") + } + } +end PlayerConnectionSpec diff --git a/modules/domain/src/test/scala/bastoni/domain/model/RoomViewSpec.scala b/modules/domain/src/test/scala/bastoni/domain/model/RoomViewSpec.scala new file mode 100644 index 0000000..c6eab7c --- /dev/null +++ b/modules/domain/src/test/scala/bastoni/domain/model/RoomViewSpec.scala @@ -0,0 +1,26 @@ +package bastoni.domain.model + +import bastoni.domain.model.Event.PlayerJoinedTable +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should.Matchers + +class RoomViewSpec extends AnyFreeSpec with Matchers: + + val me: User = User(UserId.newId, "me") + val emptyRoom: RoomPlayerView = RoomPlayerView( + me.id, + List( + EmptySeat(1, Nil, Nil), + EmptySeat(2, Nil, Nil) + ), + Nil, + Nil, + None, + None, + Map.empty + ) + + "Player joining an empty table" in { + val room: RoomPlayerView = emptyRoom.update(PlayerJoinedTable(me, 1)) + room.players.get(me.id) shouldBe Some(me) + } diff --git a/modules/sdk/src/main/scala/bastoni/sdk/ConsoleLogger.scala b/modules/sdk/src/main/scala/bastoni/sdk/ConsoleLogger.scala index ff476fd..dcef8e7 100644 --- a/modules/sdk/src/main/scala/bastoni/sdk/ConsoleLogger.scala +++ b/modules/sdk/src/main/scala/bastoni/sdk/ConsoleLogger.scala @@ -4,35 +4,36 @@ import cats.effect.IO import org.scalajs.dom.window.console import org.typelevel.log4cats.Logger as CatsLogger -object ConsoleLogger: - given CatsLogger[IO] = new CatsLogger[IO]: - override def error(message: => String): IO[Unit] = - IO(console.error(message)) +object ConsoleLogger extends CatsLogger[IO]: + override def error(message: => String): IO[Unit] = + IO(console.error(message)) - override def warn(message: => String): IO[Unit] = - IO(console.warn(message)) + override def warn(message: => String): IO[Unit] = + IO(console.warn(message)) - override def info(message: => String): IO[Unit] = - IO(console.info(message)) + override def info(message: => String): IO[Unit] = + IO(console.info(message)) - override def debug(message: => String): IO[Unit] = - IO(console.debug(message)) + override def debug(message: => String): IO[Unit] = + IO(console.debug(message)) - override def trace(message: => String): IO[Unit] = - IO.unit + override def trace(message: => String): IO[Unit] = + IO.unit - override def error(t: Throwable)(message: => String): IO[Unit] = - IO(console.error(message, t)) + override def error(t: Throwable)(message: => String): IO[Unit] = + IO(console.error(message, t)) - override def warn(t: Throwable)(message: => String): IO[Unit] = - IO(console.warn(message, t)) + override def warn(t: Throwable)(message: => String): IO[Unit] = + IO(console.warn(message, t)) - override def info(t: Throwable)(message: => String): IO[Unit] = - IO(console.info(message, t)) + override def info(t: Throwable)(message: => String): IO[Unit] = + IO(console.info(message, t)) - override def debug(t: Throwable)(message: => String): IO[Unit] = - IO(console.debug(message, t)) + override def debug(t: Throwable)(message: => String): IO[Unit] = + IO(console.debug(message, t)) - override def trace(t: Throwable)(message: => String): IO[Unit] = - IO.unit + override def trace(t: Throwable)(message: => String): IO[Unit] = + IO.unit + + given CatsLogger[IO] = ConsoleLogger end ConsoleLogger diff --git a/modules/sdk/src/main/scala/bastoni/sdk/GameSdk.scala b/modules/sdk/src/main/scala/bastoni/sdk/GameSdk.scala index 2e4afbf..e6ec2a3 100644 --- a/modules/sdk/src/main/scala/bastoni/sdk/GameSdk.scala +++ b/modules/sdk/src/main/scala/bastoni/sdk/GameSdk.scala @@ -5,14 +5,13 @@ import bastoni.domain.logic.Services import bastoni.domain.model.* import bastoni.domain.view.* import bastoni.sdk.ConsoleLogger.given -import cats.effect.unsafe.IORuntime import cats.effect.IO +import cats.effect.unsafe.IORuntime import io.circe import io.circe.parser.decode import io.circe.syntax.EncoderOps import scala.concurrent.duration.DurationInt -import scala.concurrent.Future import scala.scalajs.js import scala.scalajs.js.annotation.JSExportTopLevel @@ -57,29 +56,16 @@ object GameSdk: val me = User(UserId.newId, playerName) val virtualPlayer = VirtualPlayer(controller, GreedyPlayer, pause = 1.second) val opponent = virtualPlayer.play(User(UserId.newId, "Tony"), roomId) + val connectMe = controller.publish(me, roomId)( + fs2.Stream[IO, FromPlayer](FromPlayer.Connect, FromPlayer.JoinTable) ++ + fs2.Stream.awakeEvery[IO](2.seconds).map(_ => FromPlayer.StartMatch(GameType.valueOf(gameType))) + ) val bg = controller - .subscribe(me, roomId) - .takeThrough { - case ToPlayer.Disconnected(_) => false - case _ => true - } - .zipWithScan1(Option.empty[RoomPlayerView]) { - case (_, ToPlayer.Connected(room)) => Some(room) - case (_, ToPlayer.Disconnected(_)) => None - case (room, ToPlayer.Request(request)) => room.map(_.withRequest(request)) - case (room, ToPlayer.GameEvent(event)) => room.map(_.update(event)) - case (room, ToPlayer.Authenticated(_)) => room - case (room, ToPlayer.Ping) => room - } + .connectPlayer(me, roomId) .evalMap { (msg, room) => IO(onMessage(ToPlayerJs(msg), RoomJs(room))) } .concurrently(runner) + .concurrently(connectMe) .concurrently(opponent) - .concurrently( - controller.publish(me, roomId)( - fs2.Stream[IO, FromPlayer](FromPlayer.Connect, FromPlayer.JoinTable).delayBy(1.second) ++ - fs2.Stream.awakeEvery[IO](2.seconds).map(_ => FromPlayer.StartMatch(GameType.valueOf(gameType))) - ) - ) val control = (message: FromPlayer) => controller.publish1(me, roomId)(message) control -> bg } diff --git a/modules/sdk/src/main/typescript/gameClient.ts b/modules/sdk/src/main/typescript/gameClient.ts index a8850b2..3707c70 100644 --- a/modules/sdk/src/main/typescript/gameClient.ts +++ b/modules/sdk/src/main/typescript/gameClient.ts @@ -276,7 +276,7 @@ export class GameClientBuilder { } } - ws.onopen = (event) => { + ws.onopen = () => { this.ready(client); }; ws.onmessage = (event) => { @@ -285,7 +285,7 @@ export class GameClientBuilder { ws.onerror = (event) => { console.error(JSON.stringify(event.type)); }; - ws.onclose = (event) => { + ws.onclose = () => { console.log(`Connection closed`); } diff --git a/modules/sdk/src/main/typescript/index.d.ts b/modules/sdk/src/main/typescript/index.d.ts index 4d0c63e..8514ffe 100644 --- a/modules/sdk/src/main/typescript/index.d.ts +++ b/modules/sdk/src/main/typescript/index.d.ts @@ -1,11 +1,11 @@ import {OutboxMessage} from "./model/outboxMessage"; import {InboxMessage} from "./model/inboxMessage"; -import {Room, RoomId} from "./model/room"; +import {Room} from "./model/room"; import {GameType} from "./model/gameType"; export function playAgainstComputer( playerName: string, gameType: GameType, - onMesage: (message: InboxMessage, room: Room) => void, + onMesage: (message: InboxMessage, room?: Room) => void, onInt: (sendMessage: (message: OutboxMessage) => void) => void ): () => void diff --git a/modules/sdk/src/main/typescript/package-lock.json b/modules/sdk/src/main/typescript/package-lock.json deleted file mode 100644 index 3cc4daa..0000000 --- a/modules/sdk/src/main/typescript/package-lock.json +++ /dev/null @@ -1,360 +0,0 @@ -{ - "name": "bastoni", - "version": "0.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "bastoni", - "version": "0.1.0", - "dependencies": { - "ts-interface-checker": "^1.0.2", - "typescript": "^4.9.5" - }, - "devDependencies": { - "ts-interface-builder": "^0.3.3" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/fs-extra": { - "version": "4.0.3", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ts-interface-builder": { - "version": "0.3.3", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/ts-interface-builder/-/ts-interface-builder-0.3.3.tgz", - "integrity": "sha512-WHQwVBy0+Sv/jcHhKlyFgTyEVTM0GEPEw+gLmOYlZiJC1/eh5ah2EHSw7o+RUrl2grjEAMU6MTOItCuQIVJvnQ==", - "dev": true, - "dependencies": { - "commander": "^2.12.2", - "fs-extra": "^4.0.3", - "glob": "^7.1.6", - "typescript": "^3.0.0" - }, - "bin": { - "ts-interface-builder": "bin/ts-interface-builder" - } - }, - "node_modules/ts-interface-builder/node_modules/typescript": { - "version": "3.9.10", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/ts-interface-checker": { - "version": "1.0.2", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/ts-interface-checker/-/ts-interface-checker-1.0.2.tgz", - "integrity": "sha512-4IKKvhZRXhvtYF/mtu+OCfBqJKV6LczUq4kQYcpT+iSB7++R9+giWnp2ecwWMIcnG16btVOkXFnoxLSYMN1Q1g==" - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - } - }, - "dependencies": { - "balanced-match": { - "version": "1.0.2", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "fs-extra": { - "version": "4.0.3", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "glob": { - "version": "7.2.3", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "ts-interface-builder": { - "version": "0.3.3", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/ts-interface-builder/-/ts-interface-builder-0.3.3.tgz", - "integrity": "sha512-WHQwVBy0+Sv/jcHhKlyFgTyEVTM0GEPEw+gLmOYlZiJC1/eh5ah2EHSw7o+RUrl2grjEAMU6MTOItCuQIVJvnQ==", - "dev": true, - "requires": { - "commander": "^2.12.2", - "fs-extra": "^4.0.3", - "glob": "^7.1.6", - "typescript": "^3.0.0" - }, - "dependencies": { - "typescript": { - "version": "3.9.10", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", - "dev": true - } - } - }, - "ts-interface-checker": { - "version": "1.0.2", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/ts-interface-checker/-/ts-interface-checker-1.0.2.tgz", - "integrity": "sha512-4IKKvhZRXhvtYF/mtu+OCfBqJKV6LczUq4kQYcpT+iSB7++R9+giWnp2ecwWMIcnG16btVOkXFnoxLSYMN1Q1g==" - }, - "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://cpartifactory.corp.siriusxm.com:443/artifactory/api/npm/npm/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - } - } -}