@hellacardgames/speed 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/client/index.cjs.map +1 -1
  2. package/dist/client/index.d.cts +2 -3
  3. package/dist/client/index.d.cts.map +1 -1
  4. package/dist/client/index.d.mts +2 -3
  5. package/dist/client/index.d.mts.map +1 -1
  6. package/dist/client/index.mjs.map +1 -1
  7. package/dist/index-BilCO_4a.d.cts +216 -0
  8. package/dist/index-BilCO_4a.d.cts.map +1 -0
  9. package/dist/index-BilCO_4a.d.mts +216 -0
  10. package/dist/index-BilCO_4a.d.mts.map +1 -0
  11. package/dist/{startGame-5InkAgEp.d.cts → index-DSPZZlhq.d.cts} +39 -4
  12. package/dist/index-DSPZZlhq.d.cts.map +1 -0
  13. package/dist/{startGame-ayp8a-Cl.d.mts → index-S-oO1z9X.d.mts} +39 -4
  14. package/dist/index-S-oO1z9X.d.mts.map +1 -0
  15. package/dist/manager/index.cjs +12 -32
  16. package/dist/manager/index.d.cts +2 -109
  17. package/dist/manager/index.d.mts +2 -109
  18. package/dist/manager/index.mjs +1 -21
  19. package/dist/{startGame-BC9XfFzG.mjs → manager-CPmezdJa.mjs} +21 -2
  20. package/dist/manager-CPmezdJa.mjs.map +1 -0
  21. package/dist/{startGame-Bhk__XWk.cjs → manager-DErQ_XUq.cjs} +20 -19
  22. package/dist/manager-DErQ_XUq.cjs.map +1 -0
  23. package/dist/server/index.cjs +12 -12
  24. package/dist/server/index.cjs.map +1 -1
  25. package/dist/server/index.d.cts +3 -40
  26. package/dist/server/index.d.mts +3 -40
  27. package/dist/server/index.mjs +1 -1
  28. package/dist/server/index.mjs.map +1 -1
  29. package/package.json +1 -1
  30. package/dist/GameEvent-DDQ4jXxt.d.cts +0 -111
  31. package/dist/GameEvent-DDQ4jXxt.d.cts.map +0 -1
  32. package/dist/GameEvent-DDQ4jXxt.d.mts +0 -111
  33. package/dist/GameEvent-DDQ4jXxt.d.mts.map +0 -1
  34. package/dist/manager/index.cjs.map +0 -1
  35. package/dist/manager/index.d.cts.map +0 -1
  36. package/dist/manager/index.d.mts.map +0 -1
  37. package/dist/manager/index.mjs.map +0 -1
  38. package/dist/server/index.d.cts.map +0 -1
  39. package/dist/server/index.d.mts.map +0 -1
  40. package/dist/startGame-5InkAgEp.d.cts.map +0 -1
  41. package/dist/startGame-BC9XfFzG.mjs.map +0 -1
  42. package/dist/startGame-Bhk__XWk.cjs.map +0 -1
  43. package/dist/startGame-ayp8a-Cl.d.mts.map +0 -1
@@ -1,111 +0,0 @@
1
- //#region src/manager/types/Card.d.ts
2
- type Card = {
3
- readonly id: string;
4
- readonly rank: 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14;
5
- readonly suite: "clubs" | "diamonds" | "hearts" | "spades";
6
- };
7
- //#endregion
8
- //#region src/manager/types/ChatMessage.d.ts
9
- type ChatMessage = {
10
- readonly id: string;
11
- readonly username: string;
12
- readonly text: string;
13
- };
14
- //#endregion
15
- //#region src/manager/types/ClientState.d.ts
16
- type ClientState = {
17
- readonly status: "open" | "started" | "completed" | "forfeited";
18
- readonly gameId: string;
19
- readonly playerId: string;
20
- readonly username: string;
21
- readonly players: readonly Player[];
22
- readonly expiresAt: number;
23
- readonly chatMessages: readonly ChatMessage[];
24
- readonly hand: readonly Card[];
25
- readonly canPlayAt: number | null;
26
- };
27
- type Player = {
28
- readonly username: string;
29
- readonly handSize: number;
30
- readonly drawPileSize: number;
31
- readonly sidePileSize: number;
32
- readonly centerPileTopCard: Card | null;
33
- };
34
- //#endregion
35
- //#region src/manager/types/GameEvent.d.ts
36
- type GameEvent = {
37
- readonly type: "canPlayAtUpdated";
38
- readonly id: string;
39
- readonly canPlayAt: number;
40
- } | {
41
- readonly type: "cardDrawnFromSidePileToCenterPile";
42
- readonly id: string;
43
- readonly username: string;
44
- readonly card: Card;
45
- } | {
46
- readonly type: "cardPlayed";
47
- readonly id: string;
48
- readonly username: string;
49
- readonly card: Card;
50
- readonly isForOtherPlayerPile: boolean;
51
- } | {
52
- readonly type: "chat";
53
- readonly id: string;
54
- readonly message: ChatMessage;
55
- } | {
56
- readonly type: "drewCard";
57
- readonly id: string;
58
- readonly card: Card;
59
- } | {
60
- readonly type: "expirationUpdated";
61
- readonly id: string;
62
- readonly expiresAt: number;
63
- } | {
64
- readonly type: "gameCompleted";
65
- readonly id: string;
66
- } | {
67
- readonly type: "gameForfeited";
68
- readonly id: string;
69
- } | {
70
- readonly type: "gameStarted";
71
- readonly id: string;
72
- } | {
73
- readonly type: "handInitialized";
74
- readonly id: string;
75
- readonly cards: readonly Card[];
76
- } | {
77
- readonly type: "playerCenterPileInitialized";
78
- readonly id: string;
79
- readonly username: string;
80
- readonly card: Card;
81
- } | {
82
- readonly type: "playerDrawPileInitialized";
83
- readonly id: string;
84
- readonly username: string;
85
- readonly numCards: number;
86
- } | {
87
- readonly type: "playerDrewCard";
88
- readonly id: string;
89
- readonly username: string;
90
- } | {
91
- readonly type: "playerHandInitialized";
92
- readonly id: string;
93
- readonly username: string;
94
- readonly numCards: number;
95
- } | {
96
- readonly type: "playerJoined";
97
- readonly id: string;
98
- readonly username: string;
99
- } | {
100
- readonly type: "playerLeft";
101
- readonly id: string;
102
- readonly username: string;
103
- } | {
104
- readonly type: "playerSidePileInitialized";
105
- readonly id: string;
106
- readonly username: string;
107
- readonly numCards: number;
108
- };
109
- //#endregion
110
- export { Card as i, ClientState as n, ChatMessage as r, GameEvent as t };
111
- //# sourceMappingURL=GameEvent-DDQ4jXxt.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"GameEvent-DDQ4jXxt.d.mts","names":[],"sources":["../src/manager/types/Card.ts","../src/manager/types/ChatMessage.ts","../src/manager/types/ClientState.ts","../src/manager/types/GameEvent.ts"],"mappings":";KAAY,IAAA;EAAA,SACD,EAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA;AAAA;;;KCHC,WAAA;EAAA,SACD,EAAA;EAAA,SACA,QAAA;EAAA,SACA,IAAA;AAAA;;;KCAC,WAAA;EAAA,SACD,MAAA;EAAA,SACA,MAAA;EAAA,SACA,QAAA;EAAA,SACA,QAAA;EAAA,SACA,OAAA,WAAkB,MAAA;EAAA,SAClB,SAAA;EAAA,SACA,YAAA,WAAuB,WAAA;EAAA,SACvB,IAAA,WAAe,IAAA;EAAA,SACf,SAAA;AAAA;AAAA,KAGN,MAAA;EAAA,SACM,QAAA;EAAA,SACA,QAAA;EAAA,SACA,YAAA;EAAA,SACA,YAAA;EAAA,SACA,iBAAA,EAAmB,IAAI;AAAA;;;KCjBtB,SAAA;EAAA,SAEG,IAAA;EAAA,SACA,EAAA;EAAA,SACA,SAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,QAAA;EAAA,SACA,IAAA,EAAM,IAAA;AAAA;EAAA,SAGN,IAAA;EAAA,SACA,EAAA;EAAA,SACA,QAAA;EAAA,SACA,IAAA,EAAM,IAAA;EAAA,SACN,oBAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,OAAA,EAAS,WAAA;AAAA;EAAA,SAGT,IAAA;EAAA,SACA,EAAA;EAAA,SACA,IAAA,EAAM,IAAA;AAAA;EAAA,SAGN,IAAA;EAAA,SACA,EAAA;EAAA,SACA,SAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,EAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,EAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,EAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,KAAA,WAAgB,IAAA;AAAA;EAAA,SAGhB,IAAA;EAAA,SACA,EAAA;EAAA,SACA,QAAA;EAAA,SACA,IAAA,EAAM,IAAA;AAAA;EAAA,SAGN,IAAA;EAAA,SACA,EAAA;EAAA,SACA,QAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,QAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,QAAA;EAAA,SACA,QAAA;AAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","names":["GAME_KEY","WATCHDOG_INTERVAL_MS","games"],"sources":["../../src/manager/watchdog.ts","../../src/manager/index.ts"],"sourcesContent":["import { GAME_KEY, WATCHDOG_INTERVAL_MS } from \"./constants.js\";\nimport { games } from \"./games.js\";\n\nclass Watchdog {\n start() {\n console.log(`watchdog start at ${Date.now()} (${GAME_KEY})`);\n setInterval(() => this.wakeUp(), WATCHDOG_INTERVAL_MS);\n }\n\n wakeUp() {\n const now = Date.now();\n // console.log(`watchdog wakeUp at ${now} (${GAME_KEY})`);\n for (const game of games.values()) {\n if (game.expiresAt <= now) {\n games.delete(game.id);\n console.log(`watchdog purged ${game.id} (${GAME_KEY})`);\n }\n }\n }\n}\n\nexport const watchdog = new Watchdog();\n","import { watchdog } from \"./watchdog.js\";\n\nexport { createGame } from \"./actions/createGame.js\";\nexport { drawCard } from \"./actions/drawCard.js\";\nexport { getClientStateAndClearEvents } from \"./actions/getClientStateAndClearEvents.js\";\nexport { getEventsAndClearAcknowledged } from \"./actions/getEventsAndClearAcknowledged.js\";\nexport { getJoinableGames } from \"./actions/getJoinableGames.js\";\nexport { joinGame } from \"./actions/joinGame.js\";\nexport { leaveGame } from \"./actions/leaveGame.js\";\nexport { playCard } from \"./actions/playCard.js\";\nexport { reportNoPlayableCards } from \"./actions/reportNoPlayableCards.js\";\nexport { sendChat } from \"./actions/sendChat.js\";\nexport { startGame } from \"./actions/startGame.js\";\n\nwatchdog.start();\n"],"mappings":";;;AAGA,IAAM,WAAN,MAAe;CACb,QAAQ;EACN,QAAQ,IAAI,qBAAqB,KAAK,IAAI,EAAE,IAAIA,kBAAAA,SAAS,EAAE;EAC3D,kBAAkB,KAAK,OAAO,GAAGC,kBAAAA,oBAAoB;CACvD;CAEA,SAAS;EACP,MAAM,MAAM,KAAK,IAAI;EAErB,KAAK,MAAM,QAAQC,kBAAAA,MAAM,OAAO,GAC9B,IAAI,KAAK,aAAa,KAAK;GACzB,kBAAA,MAAM,OAAO,KAAK,EAAE;GACpB,QAAQ,IAAI,mBAAmB,KAAK,GAAG,IAAIF,kBAAAA,SAAS,EAAE;EACxD;CAEJ;AACF;;;ACLA,IDO4B,SCP5B,CAAA,CAAS,MAAM"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/manager/actions/createGame.ts","../../src/manager/actions/drawCard.ts","../../src/manager/actions/getClientStateAndClearEvents.ts","../../src/manager/actions/getEventsAndClearAcknowledged.ts","../../src/manager/actions/getJoinableGames.ts","../../src/manager/actions/joinGame.ts","../../src/manager/actions/leaveGame.ts","../../src/manager/actions/playCard.ts","../../src/manager/actions/reportNoPlayableCards.ts","../../src/manager/actions/sendChat.ts","../../src/manager/actions/startGame.ts"],"mappings":";;;KAKK,gBAAA;EAAA,SAEU,OAAA;EAAA,SACA,MAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAGC,UAAA,CAAW,MAAA,UAAgB,QAAA,WAAmB,gBAAgB;;;KCXzE,cAAA;EAAA,SAEU,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBASC,QAAA,CAAS,MAAA,UAAgB,QAAA,WAAmB,cAAc;;;KCjBrE,kCAAA;EAAA,SAEU,OAAA;EAAA,SACA,KAAA,EAAO,WAAW;AAAA;EAAA,SAGlB,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAGC,4BAAA,CACd,MAAA,UACA,QAAA,WACC,kCAAkC;;;KCbhC,mCAAA;EAAA,SAEU,OAAA;EAAA,SACA,MAAA,WAAiB,SAAS;AAAA;EAAA,SAG1B,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAGC,6BAAA,CACd,MAAA,UACA,QAAA,UACA,UAAA,kBACC,mCAAmC;;;KCdjC,sBAAA;EAAA,SACM,OAAA;EAAA,SACA,KAAA;IAAA,SACE,EAAA;IAAA,SACA,UAAA;EAAA;AAAA;AAAA,iBAIG,gBAAA,IAAoB,sBAAsB;;;KCNrD,cAAA;EAAA,SAEU,OAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAOC,QAAA,CACd,MAAA,UACA,MAAA,UACA,QAAA,WACC,cAAc;;;KClBZ,eAAA;EAAA,SAEU,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAGC,SAAA,CAAU,MAAA,UAAgB,QAAA,WAAmB,eAAe;;;KCPvE,cAAA;EAAA,SAEU,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBASC,QAAA,CACd,MAAA,UACA,QAAA,UACA,MAAA,UACA,oBAAA,YACC,cAAc;;;KCjBZ,2BAAA;EAAA,SAEU,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAUC,qBAAA,CACd,MAAA,UACA,QAAA,WACC,2BAA2B;;;KCzBzB,cAAA;EAAA,SAEU,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAGC,QAAA,CACd,MAAA,UACA,QAAA,UACA,IAAA,WACC,cAAc;;;KCLZ,eAAA;EAAA,SAEU,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAQC,SAAA,CAAU,MAAA,UAAgB,QAAA,WAAmB,eAAe"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/manager/actions/createGame.ts","../../src/manager/actions/drawCard.ts","../../src/manager/actions/getClientStateAndClearEvents.ts","../../src/manager/actions/getEventsAndClearAcknowledged.ts","../../src/manager/actions/getJoinableGames.ts","../../src/manager/actions/joinGame.ts","../../src/manager/actions/leaveGame.ts","../../src/manager/actions/playCard.ts","../../src/manager/actions/reportNoPlayableCards.ts","../../src/manager/actions/sendChat.ts","../../src/manager/actions/startGame.ts"],"mappings":";;;KAKK,gBAAA;EAAA,SAEU,OAAA;EAAA,SACA,MAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAGC,UAAA,CAAW,MAAA,UAAgB,QAAA,WAAmB,gBAAgB;;;KCXzE,cAAA;EAAA,SAEU,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBASC,QAAA,CAAS,MAAA,UAAgB,QAAA,WAAmB,cAAc;;;KCjBrE,kCAAA;EAAA,SAEU,OAAA;EAAA,SACA,KAAA,EAAO,WAAW;AAAA;EAAA,SAGlB,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAGC,4BAAA,CACd,MAAA,UACA,QAAA,WACC,kCAAkC;;;KCbhC,mCAAA;EAAA,SAEU,OAAA;EAAA,SACA,MAAA,WAAiB,SAAS;AAAA;EAAA,SAG1B,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAGC,6BAAA,CACd,MAAA,UACA,QAAA,UACA,UAAA,kBACC,mCAAmC;;;KCdjC,sBAAA;EAAA,SACM,OAAA;EAAA,SACA,KAAA;IAAA,SACE,EAAA;IAAA,SACA,UAAA;EAAA;AAAA;AAAA,iBAIG,gBAAA,IAAoB,sBAAsB;;;KCNrD,cAAA;EAAA,SAEU,OAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAOC,QAAA,CACd,MAAA,UACA,MAAA,UACA,QAAA,WACC,cAAc;;;KClBZ,eAAA;EAAA,SAEU,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAGC,SAAA,CAAU,MAAA,UAAgB,QAAA,WAAmB,eAAe;;;KCPvE,cAAA;EAAA,SAEU,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBASC,QAAA,CACd,MAAA,UACA,QAAA,UACA,MAAA,UACA,oBAAA,YACC,cAAc;;;KCjBZ,2BAAA;EAAA,SAEU,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAUC,qBAAA,CACd,MAAA,UACA,QAAA,WACC,2BAA2B;;;KCzBzB,cAAA;EAAA,SAEU,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAGC,QAAA,CACd,MAAA,UACA,QAAA,UACA,IAAA,WACC,cAAc;;;KCLZ,eAAA;EAAA,SAEU,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAQC,SAAA,CAAU,MAAA,UAAgB,QAAA,WAAmB,eAAe"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/manager/watchdog.ts","../../src/manager/index.ts"],"sourcesContent":["import { GAME_KEY, WATCHDOG_INTERVAL_MS } from \"./constants.js\";\nimport { games } from \"./games.js\";\n\nclass Watchdog {\n start() {\n console.log(`watchdog start at ${Date.now()} (${GAME_KEY})`);\n setInterval(() => this.wakeUp(), WATCHDOG_INTERVAL_MS);\n }\n\n wakeUp() {\n const now = Date.now();\n // console.log(`watchdog wakeUp at ${now} (${GAME_KEY})`);\n for (const game of games.values()) {\n if (game.expiresAt <= now) {\n games.delete(game.id);\n console.log(`watchdog purged ${game.id} (${GAME_KEY})`);\n }\n }\n }\n}\n\nexport const watchdog = new Watchdog();\n","import { watchdog } from \"./watchdog.js\";\n\nexport { createGame } from \"./actions/createGame.js\";\nexport { drawCard } from \"./actions/drawCard.js\";\nexport { getClientStateAndClearEvents } from \"./actions/getClientStateAndClearEvents.js\";\nexport { getEventsAndClearAcknowledged } from \"./actions/getEventsAndClearAcknowledged.js\";\nexport { getJoinableGames } from \"./actions/getJoinableGames.js\";\nexport { joinGame } from \"./actions/joinGame.js\";\nexport { leaveGame } from \"./actions/leaveGame.js\";\nexport { playCard } from \"./actions/playCard.js\";\nexport { reportNoPlayableCards } from \"./actions/reportNoPlayableCards.js\";\nexport { sendChat } from \"./actions/sendChat.js\";\nexport { startGame } from \"./actions/startGame.js\";\n\nwatchdog.start();\n"],"mappings":";;AAGA,IAAM,WAAN,MAAe;CACb,QAAQ;EACN,QAAQ,IAAI,qBAAqB,KAAK,IAAI,EAAE,IAAI,SAAS,EAAE;EAC3D,kBAAkB,KAAK,OAAO,GAAG,oBAAoB;CACvD;CAEA,SAAS;EACP,MAAM,MAAM,KAAK,IAAI;EAErB,KAAK,MAAM,QAAQ,MAAM,OAAO,GAC9B,IAAI,KAAK,aAAa,KAAK;GACzB,MAAM,OAAO,KAAK,EAAE;GACpB,QAAQ,IAAI,mBAAmB,KAAK,GAAG,IAAI,SAAS,EAAE;EACxD;CAEJ;AACF;;;ACLA,IDO4B,SCP5B,CAAA,CAAS,MAAM"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/server/index.ts"],"mappings":";;;cAYa,OAAA;EAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/server/index.ts"],"mappings":";;;cAYa,OAAA;EAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"startGame-5InkAgEp.d.cts","names":[],"sources":["../src/server/actions/createGame.ts","../src/server/actions/drawCard.ts","../src/server/actions/getClientStateAndClearEvents.ts","../src/server/actions/getEventsAndClearAcknowledged.ts","../src/server/actions/getJoinableGames.ts","../src/server/actions/joinGame.ts","../src/server/actions/leaveGame.ts","../src/server/actions/playCard.ts","../src/server/actions/reportNoPlayableCards.ts","../src/server/actions/sendChat.ts","../src/server/actions/startGame.ts"],"mappings":";;;KAEY,gBAAA;EAAA,SAEG,OAAA;EAAA,SACA,MAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAGC,UAAA,CAAW,MAAA,UAAgB,QAAA,WAAmB,gBAAgB;;;KCVlE,cAAA;EAAA,SAEG,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAiBC,QAAA,CAAS,KAAA,YAAiB,cAAc;;;KCtB5C,kCAAA;EAAA,SAEG,OAAA;EAAA,SACA,KAAA,EAAO,WAAW;AAAA;EAAA,SAGlB,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAUC,4BAAA,CACd,KAAA,YACC,kCAAkC;;;KCnBzB,mCAAA;EAAA,SAEG,OAAA;EAAA,SACA,MAAA,WAAiB,SAAS;AAAA;EAAA,SAG1B,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAcC,6BAAA,CACd,KAAA,YACC,mCAAmC;;;KCzB1B,sBAAA;EAAA,SACD,KAAA;IAAA,SACE,EAAA;IAAA,SACA,UAAA;EAAA;AAAA;AAAA,iBAIG,gBAAA,IAAoB,sBAAsB;;;KCN9C,cAAA;EAAA,SAEG,OAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAcC,QAAA,CACd,KAAA,WACA,MAAA,UACA,QAAA,WACC,cAAc;;;KCzBL,eAAA;EAAA,SAEG,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAUC,SAAA,CAAU,KAAA,YAAiB,eAAe;;;KChB9C,cAAA;EAAA,SAEG,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAsBC,QAAA,CAAS,KAAA,YAAiB,cAAc;;;KC5B5C,2BAAA;EAAA,SAEG,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAkBC,qBAAA,CACd,KAAA,YACC,2BAA2B;;;KC1BlB,cAAA;EAAA,SAEG,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAWC,QAAA,CAAS,KAAA,YAAiB,cAAc;;;KCjB5C,eAAA;EAAA,SAEG,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAgBC,SAAA,CAAU,KAAA,YAAiB,eAAe"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"startGame-BC9XfFzG.mjs","names":[],"sources":["../src/manager/constants.ts","../src/manager/games.ts","../src/manager/actions/createGame.ts","../src/lib/emitEvent.ts","../src/lib/emitEventToPlayer.ts","../src/manager/actions/drawCard.ts","../src/manager/actions/getClientStateAndClearEvents.ts","../src/manager/actions/getEventsAndClearAcknowledged.ts","../src/manager/actions/getJoinableGames.ts","../src/manager/actions/joinGame.ts","../src/manager/actions/leaveGame.ts","../src/manager/lib/isCardPlayable.ts","../src/manager/lib/hasPlayableCard.ts","../src/manager/actions/playCard.ts","../src/lib/shuffleCards.ts","../src/manager/actions/reportNoPlayableCards.ts","../src/manager/actions/sendChat.ts","../src/manager/actions/startGame.ts"],"sourcesContent":["import type { Card } from \"./types/Card.js\";\n\nexport const GAME_KEY = \"speed\";\nexport const MAX_GAMES = 50;\nexport const WATCHDOG_INTERVAL_MS = 10000;\n\nexport const EXPIRY_EXTENSION_MS = 300000; // 5 minutes\nexport const MIN_PLAYERS = 2;\nexport const MAX_PLAYERS = 2;\nexport const MAX_HAND_SIZE = 5;\nexport const CAN_PLAY_AT_DELAY_MS = 3000;\n\nexport const CARDS: readonly Card[] = [\n { id: crypto.randomUUID(), rank: 2, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"spades\" },\n];\n","import type { Game } from \"./types/Game.js\";\n\nexport const games = new Map<string, Game>();\n","import { EXPIRY_EXTENSION_MS, MAX_GAMES } from \"../constants.js\";\nimport { games } from \"../games.js\";\nimport type { Player } from \"../types/Player.js\";\nimport type { Game } from \"../types/Game.js\";\n\ntype CreateGameResult =\n | {\n readonly success: true;\n readonly gameId: string;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error: \"maxGamesReached\";\n };\n\nexport function createGame(userId: string, username: string): CreateGameResult {\n if (games.size === MAX_GAMES) {\n return { success: false, error: \"maxGamesReached\" };\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n const createdAt = Date.now();\n const game: Game = {\n status: \"open\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n };\n games.set(game.id, game);\n return { success: true, gameId: game.id, playerId: player.id };\n}\n","type Game = {\n readonly players: {\n readonly events: { readonly id: string }[];\n }[];\n};\n\ntype OmitId<T> = T extends unknown ? Omit<T, \"id\"> : never;\n\nexport function emitEvent<T extends Game>(\n game: T,\n data: OmitId<T[\"players\"][number][\"events\"][number]>,\n): void {\n const event = { ...data, id: crypto.randomUUID() };\n for (const p of game.players) {\n p.events.push(event);\n }\n}\n","type Player = {\n readonly events: { readonly id: string }[];\n};\n\ntype OmitId<T> = T extends unknown ? Omit<T, \"id\"> : never;\n\nexport function emitEventToPlayer<T extends Player>(\n player: T,\n data: OmitId<T[\"events\"][number]>,\n): void {\n player.events.push({ ...data, id: crypto.randomUUID() });\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { emitEventToPlayer } from \"../../lib/emitEventToPlayer.js\";\nimport { EXPIRY_EXTENSION_MS, MAX_HAND_SIZE } from \"../constants.js\";\nimport { games } from \"../games.js\";\n\ntype DrawCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"handFull\"\n | \"drawPileEmpty\";\n };\n\nexport function drawCard(gameId: string, playerId: string): DrawCardResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" };\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" };\n }\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n const card = player.drawPile.pop()!;\n player.hand.push(card);\n emitEventToPlayer(player, { type: \"drewCard\", card });\n emitEvent(game, { type: \"playerDrewCard\", username: player.username });\n return { success: true };\n}\n","import { games } from \"../games.js\";\nimport type { ClientState } from \"../types/ClientState.js\";\n\ntype GetClientStateAndClearEventsResult =\n | {\n readonly success: true;\n readonly state: ClientState;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport function getClientStateAndClearEvents(\n gameId: string,\n playerId: string,\n): GetClientStateAndClearEventsResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const state: ClientState = {\n status: game.status,\n gameId,\n playerId,\n username: player.username,\n players: game.players.map((p) => ({\n username: p.username,\n handSize: p.hand.length,\n drawPileSize: p.drawPile.length,\n sidePileSize: p.sidePile.length,\n centerPileTopCard: p.centerPile.length\n ? p.centerPile[p.centerPile.length - 1]!\n : null,\n })),\n expiresAt: game.expiresAt,\n chatMessages: game.chatMessages,\n hand: player.hand,\n canPlayAt: game.status === \"started\" ? game.canPlayAt : null,\n };\n player.events.length = 0;\n return { success: true, state };\n}\n","import { games } from \"../games.js\";\nimport type { GameEvent } from \"../types/GameEvent.js\";\n\ntype GetEventsAndClearAcknowledgedResult =\n | {\n readonly success: true;\n readonly events: readonly GameEvent[];\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport function getEventsAndClearAcknowledged(\n gameId: string,\n playerId: string,\n lastReadId: string | null,\n): GetEventsAndClearAcknowledgedResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const lastReadEventIndex = player.events.findIndex(\n (e) => e.id === lastReadId,\n );\n player.events.splice(0, lastReadEventIndex + 1);\n return { success: true, events: player.events };\n}\n","import { MAX_PLAYERS } from \"../constants.js\";\nimport { games } from \"../games.js\";\n\ntype GetJoinableGamesResult = {\n readonly success: true;\n readonly games: readonly {\n readonly id: string;\n readonly numPlayers: number;\n }[];\n};\n\nexport function getJoinableGames(): GetJoinableGamesResult {\n return {\n success: true,\n games: Array.from(games.values())\n .filter((g) => g.status === \"open\" && g.players.length < MAX_PLAYERS)\n .map((g) => ({\n id: g.id,\n numPlayers: g.players.length,\n })),\n };\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { MAX_PLAYERS } from \"../constants.js\";\nimport { games } from \"../games.js\";\nimport type { Player } from \"../types/Player.js\";\n\ntype JoinGameResult =\n | {\n readonly success: true;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"maxPlayersReached\"\n | \"alreadyInGame\";\n };\n\nexport function joinGame(\n gameId: string,\n userId: string,\n username: string,\n): JoinGameResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n if (game.status !== \"open\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" };\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" };\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n game.players.push(player);\n emitEvent(game, { type: \"playerJoined\", username });\n return { success: true, playerId: player.id };\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { EXPIRY_EXTENSION_MS, MIN_PLAYERS } from \"../constants.js\";\nimport { games } from \"../games.js\";\nimport type { Game } from \"../types/Game.js\";\n\ntype LeaveGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport function leaveGame(gameId: string, playerId: string): LeaveGameResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const playerIndex = game.players.findIndex((p) => p.id === playerId);\n if (playerIndex === -1) {\n return { success: false, error: \"playerNotFound\" };\n }\n\n const player = game.players[playerIndex]!;\n emitEvent(game, { type: \"playerLeft\", username: player.username });\n\n game.players.splice(playerIndex, 1);\n\n if (game.status === \"started\" && game.players.length < MIN_PLAYERS) {\n const forfeitedGame: Game = {\n ...game,\n status: \"forfeited\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n };\n games.set(game.id, forfeitedGame);\n emitEvent(forfeitedGame, { type: \"gameForfeited\" });\n emitEvent(forfeitedGame, {\n type: \"expirationUpdated\",\n expiresAt: forfeitedGame.expiresAt,\n });\n }\n if (game.players.length === 0) {\n games.delete(game.id);\n }\n return { success: true };\n}\n","import type { Card } from \"../types/Card.js\";\n\nexport function isCardPlayable(card: Card, targetPile: Card[]) {\n const targetCard = targetPile[targetPile.length - 1]!;\n const diff = Math.abs(card.rank - targetCard.rank) % 11;\n return diff === 1;\n}\n","import { isCardPlayable } from \"./isCardPlayable.js\";\nimport type { Game } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function hasPlayableCard(player: Player, game: Game) {\n const otherPlayer = game.players.find((p) => p !== player)!;\n const targetPile1 = player.centerPile;\n const targetPile2 = otherPlayer.centerPile;\n for (const card of player.hand) {\n if (\n isCardPlayable(card, targetPile1) ||\n isCardPlayable(card, targetPile2)\n ) {\n return true;\n }\n }\n return false;\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { EXPIRY_EXTENSION_MS } from \"../constants.js\";\nimport { games } from \"../games.js\";\nimport { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport { isCardPlayable } from \"../lib/isCardPlayable.js\";\nimport type { Game } from \"../types/Game.js\";\n\ntype PlayCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"cardNotFound\"\n | \"cardNotPlayable\";\n };\n\nexport function playCard(\n gameId: string,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n): PlayCardResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n const cardIndex = player.hand.findIndex((c) => c.id === cardId);\n if (cardIndex === -1) {\n return { success: false, error: \"cardNotFound\" };\n }\n const otherPlayer = game.players.find((p) => p !== player)!;\n const targetPile = isForOtherPlayerPile\n ? otherPlayer.centerPile\n : player.centerPile;\n const card = player.hand[cardIndex]!;\n if (!isCardPlayable(card, targetPile)) {\n return { success: false, error: \"cardNotPlayable\" };\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hand.splice(cardIndex, 1);\n targetPile.push(card);\n emitEvent(game, {\n type: \"cardPlayed\",\n username: player.username,\n card,\n isForOtherPlayerPile,\n });\n\n if (otherPlayer.hasNoPlayableCards && hasPlayableCard(otherPlayer, game)) {\n otherPlayer.hasNoPlayableCards = false;\n }\n\n if (player.hand.length === 0 && player.drawPile.length === 0) {\n emitEvent(game, { type: \"gameCompleted\" });\n const completedGame: Game = {\n ...game,\n status: \"completed\",\n };\n games.set(game.id, completedGame);\n }\n\n return { success: true };\n}\n","type Card = { readonly id: string };\n\nexport function shuffleCards<T extends Card>(cards: T[]): void {\n for (let i = cards.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [cards[i], cards[j]] = [cards[j]!, cards[i]!];\n }\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { shuffleCards } from \"../../lib/shuffleCards.js\";\nimport {\n CAN_PLAY_AT_DELAY_MS,\n EXPIRY_EXTENSION_MS,\n MAX_HAND_SIZE,\n} from \"../constants.js\";\nimport { games } from \"../games.js\";\nimport { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\n\ntype ReportNoPlayableCardsResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"alreadyReported\"\n | \"hasPlayableCard\"\n | \"canDraw\";\n };\n\nexport function reportNoPlayableCards(\n gameId: string,\n playerId: string,\n): ReportNoPlayableCardsResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" };\n }\n if (hasPlayableCard(player, game)) {\n return { success: false, error: \"hasPlayableCard\" };\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" };\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hasNoPlayableCards = true;\n\n const otherPlayer = game.players.find((p) => p !== player)!;\n if (otherPlayer.hasNoPlayableCards) {\n if (player.sidePile.length === 0 && otherPlayer.sidePile.length === 0) {\n const cards = [...player.centerPile, ...otherPlayer.centerPile];\n shuffleCards(cards);\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n } else {\n const playerSidePileCard = player.sidePile.pop()!;\n player.centerPile.push(playerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: player.username,\n card: playerSidePileCard,\n });\n const otherPlayerSidePileCard = otherPlayer.sidePile.pop()!;\n otherPlayer.centerPile.push(otherPlayerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: otherPlayer.username,\n card: otherPlayerSidePileCard,\n });\n }\n player.hasNoPlayableCards = false;\n otherPlayer.hasNoPlayableCards = false;\n game.canPlayAt = Date.now() + CAN_PLAY_AT_DELAY_MS;\n emitEvent(game, {\n type: \"canPlayAtUpdated\",\n canPlayAt: game.canPlayAt,\n });\n }\n\n return { success: true };\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { games } from \"../games.js\";\nimport type { ChatMessage } from \"../types/ChatMessage.js\";\n\ntype SendChatResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport function sendChat(\n gameId: string,\n playerId: string,\n text: string,\n): SendChatResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const message: ChatMessage = {\n id: crypto.randomUUID(),\n username: player.username,\n text,\n };\n game.chatMessages.push(message);\n emitEvent(game, { type: \"chat\", message });\n return { success: true };\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { emitEventToPlayer } from \"../../lib/emitEventToPlayer.js\";\nimport { shuffleCards } from \"../../lib/shuffleCards.js\";\nimport {\n CAN_PLAY_AT_DELAY_MS,\n CARDS,\n EXPIRY_EXTENSION_MS,\n MIN_PLAYERS,\n} from \"../constants.js\";\nimport { games } from \"../games.js\";\nimport type { Game } from \"../types/Game.js\";\n\ntype StartGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"playerNotAdmin\"\n | \"minPlayersNotReached\";\n };\n\nexport function startGame(gameId: string, playerId: string): StartGameResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"open\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" };\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" };\n }\n const otherPlayer = game.players[1]!;\n const cards = [...CARDS];\n shuffleCards(cards);\n\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n\n player.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: player.username,\n numCards: player.drawPile.length,\n });\n\n player.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(player, { type: \"handInitialized\", cards: player.hand });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: player.username,\n numCards: player.hand.length,\n });\n\n otherPlayer.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.drawPile.length,\n });\n\n otherPlayer.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(otherPlayer, {\n type: \"handInitialized\",\n cards: otherPlayer.hand,\n });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.hand.length,\n });\n\n const startedGame: Game = {\n ...game,\n status: \"started\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS,\n };\n games.set(game.id, startedGame);\n emitEvent(startedGame, { type: \"gameStarted\" });\n emitEvent(startedGame, {\n type: \"expirationUpdated\",\n expiresAt: startedGame.expiresAt,\n });\n emitEvent(startedGame, {\n type: \"canPlayAtUpdated\",\n canPlayAt: startedGame.canPlayAt,\n });\n return { success: true };\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"startGame-Bhk__XWk.cjs","names":[],"sources":["../src/manager/constants.ts","../src/manager/games.ts","../src/manager/actions/createGame.ts","../src/lib/emitEvent.ts","../src/lib/emitEventToPlayer.ts","../src/manager/actions/drawCard.ts","../src/manager/actions/getClientStateAndClearEvents.ts","../src/manager/actions/getEventsAndClearAcknowledged.ts","../src/manager/actions/getJoinableGames.ts","../src/manager/actions/joinGame.ts","../src/manager/actions/leaveGame.ts","../src/manager/lib/isCardPlayable.ts","../src/manager/lib/hasPlayableCard.ts","../src/manager/actions/playCard.ts","../src/lib/shuffleCards.ts","../src/manager/actions/reportNoPlayableCards.ts","../src/manager/actions/sendChat.ts","../src/manager/actions/startGame.ts"],"sourcesContent":["import type { Card } from \"./types/Card.js\";\n\nexport const GAME_KEY = \"speed\";\nexport const MAX_GAMES = 50;\nexport const WATCHDOG_INTERVAL_MS = 10000;\n\nexport const EXPIRY_EXTENSION_MS = 300000; // 5 minutes\nexport const MIN_PLAYERS = 2;\nexport const MAX_PLAYERS = 2;\nexport const MAX_HAND_SIZE = 5;\nexport const CAN_PLAY_AT_DELAY_MS = 3000;\n\nexport const CARDS: readonly Card[] = [\n { id: crypto.randomUUID(), rank: 2, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"spades\" },\n];\n","import type { Game } from \"./types/Game.js\";\n\nexport const games = new Map<string, Game>();\n","import { EXPIRY_EXTENSION_MS, MAX_GAMES } from \"../constants.js\";\nimport { games } from \"../games.js\";\nimport type { Player } from \"../types/Player.js\";\nimport type { Game } from \"../types/Game.js\";\n\ntype CreateGameResult =\n | {\n readonly success: true;\n readonly gameId: string;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error: \"maxGamesReached\";\n };\n\nexport function createGame(userId: string, username: string): CreateGameResult {\n if (games.size === MAX_GAMES) {\n return { success: false, error: \"maxGamesReached\" };\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n const createdAt = Date.now();\n const game: Game = {\n status: \"open\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n };\n games.set(game.id, game);\n return { success: true, gameId: game.id, playerId: player.id };\n}\n","type Game = {\n readonly players: {\n readonly events: { readonly id: string }[];\n }[];\n};\n\ntype OmitId<T> = T extends unknown ? Omit<T, \"id\"> : never;\n\nexport function emitEvent<T extends Game>(\n game: T,\n data: OmitId<T[\"players\"][number][\"events\"][number]>,\n): void {\n const event = { ...data, id: crypto.randomUUID() };\n for (const p of game.players) {\n p.events.push(event);\n }\n}\n","type Player = {\n readonly events: { readonly id: string }[];\n};\n\ntype OmitId<T> = T extends unknown ? Omit<T, \"id\"> : never;\n\nexport function emitEventToPlayer<T extends Player>(\n player: T,\n data: OmitId<T[\"events\"][number]>,\n): void {\n player.events.push({ ...data, id: crypto.randomUUID() });\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { emitEventToPlayer } from \"../../lib/emitEventToPlayer.js\";\nimport { EXPIRY_EXTENSION_MS, MAX_HAND_SIZE } from \"../constants.js\";\nimport { games } from \"../games.js\";\n\ntype DrawCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"handFull\"\n | \"drawPileEmpty\";\n };\n\nexport function drawCard(gameId: string, playerId: string): DrawCardResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" };\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" };\n }\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n const card = player.drawPile.pop()!;\n player.hand.push(card);\n emitEventToPlayer(player, { type: \"drewCard\", card });\n emitEvent(game, { type: \"playerDrewCard\", username: player.username });\n return { success: true };\n}\n","import { games } from \"../games.js\";\nimport type { ClientState } from \"../types/ClientState.js\";\n\ntype GetClientStateAndClearEventsResult =\n | {\n readonly success: true;\n readonly state: ClientState;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport function getClientStateAndClearEvents(\n gameId: string,\n playerId: string,\n): GetClientStateAndClearEventsResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const state: ClientState = {\n status: game.status,\n gameId,\n playerId,\n username: player.username,\n players: game.players.map((p) => ({\n username: p.username,\n handSize: p.hand.length,\n drawPileSize: p.drawPile.length,\n sidePileSize: p.sidePile.length,\n centerPileTopCard: p.centerPile.length\n ? p.centerPile[p.centerPile.length - 1]!\n : null,\n })),\n expiresAt: game.expiresAt,\n chatMessages: game.chatMessages,\n hand: player.hand,\n canPlayAt: game.status === \"started\" ? game.canPlayAt : null,\n };\n player.events.length = 0;\n return { success: true, state };\n}\n","import { games } from \"../games.js\";\nimport type { GameEvent } from \"../types/GameEvent.js\";\n\ntype GetEventsAndClearAcknowledgedResult =\n | {\n readonly success: true;\n readonly events: readonly GameEvent[];\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport function getEventsAndClearAcknowledged(\n gameId: string,\n playerId: string,\n lastReadId: string | null,\n): GetEventsAndClearAcknowledgedResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const lastReadEventIndex = player.events.findIndex(\n (e) => e.id === lastReadId,\n );\n player.events.splice(0, lastReadEventIndex + 1);\n return { success: true, events: player.events };\n}\n","import { MAX_PLAYERS } from \"../constants.js\";\nimport { games } from \"../games.js\";\n\ntype GetJoinableGamesResult = {\n readonly success: true;\n readonly games: readonly {\n readonly id: string;\n readonly numPlayers: number;\n }[];\n};\n\nexport function getJoinableGames(): GetJoinableGamesResult {\n return {\n success: true,\n games: Array.from(games.values())\n .filter((g) => g.status === \"open\" && g.players.length < MAX_PLAYERS)\n .map((g) => ({\n id: g.id,\n numPlayers: g.players.length,\n })),\n };\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { MAX_PLAYERS } from \"../constants.js\";\nimport { games } from \"../games.js\";\nimport type { Player } from \"../types/Player.js\";\n\ntype JoinGameResult =\n | {\n readonly success: true;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"maxPlayersReached\"\n | \"alreadyInGame\";\n };\n\nexport function joinGame(\n gameId: string,\n userId: string,\n username: string,\n): JoinGameResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n if (game.status !== \"open\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" };\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" };\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n game.players.push(player);\n emitEvent(game, { type: \"playerJoined\", username });\n return { success: true, playerId: player.id };\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { EXPIRY_EXTENSION_MS, MIN_PLAYERS } from \"../constants.js\";\nimport { games } from \"../games.js\";\nimport type { Game } from \"../types/Game.js\";\n\ntype LeaveGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport function leaveGame(gameId: string, playerId: string): LeaveGameResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const playerIndex = game.players.findIndex((p) => p.id === playerId);\n if (playerIndex === -1) {\n return { success: false, error: \"playerNotFound\" };\n }\n\n const player = game.players[playerIndex]!;\n emitEvent(game, { type: \"playerLeft\", username: player.username });\n\n game.players.splice(playerIndex, 1);\n\n if (game.status === \"started\" && game.players.length < MIN_PLAYERS) {\n const forfeitedGame: Game = {\n ...game,\n status: \"forfeited\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n };\n games.set(game.id, forfeitedGame);\n emitEvent(forfeitedGame, { type: \"gameForfeited\" });\n emitEvent(forfeitedGame, {\n type: \"expirationUpdated\",\n expiresAt: forfeitedGame.expiresAt,\n });\n }\n if (game.players.length === 0) {\n games.delete(game.id);\n }\n return { success: true };\n}\n","import type { Card } from \"../types/Card.js\";\n\nexport function isCardPlayable(card: Card, targetPile: Card[]) {\n const targetCard = targetPile[targetPile.length - 1]!;\n const diff = Math.abs(card.rank - targetCard.rank) % 11;\n return diff === 1;\n}\n","import { isCardPlayable } from \"./isCardPlayable.js\";\nimport type { Game } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function hasPlayableCard(player: Player, game: Game) {\n const otherPlayer = game.players.find((p) => p !== player)!;\n const targetPile1 = player.centerPile;\n const targetPile2 = otherPlayer.centerPile;\n for (const card of player.hand) {\n if (\n isCardPlayable(card, targetPile1) ||\n isCardPlayable(card, targetPile2)\n ) {\n return true;\n }\n }\n return false;\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { EXPIRY_EXTENSION_MS } from \"../constants.js\";\nimport { games } from \"../games.js\";\nimport { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport { isCardPlayable } from \"../lib/isCardPlayable.js\";\nimport type { Game } from \"../types/Game.js\";\n\ntype PlayCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"cardNotFound\"\n | \"cardNotPlayable\";\n };\n\nexport function playCard(\n gameId: string,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n): PlayCardResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n const cardIndex = player.hand.findIndex((c) => c.id === cardId);\n if (cardIndex === -1) {\n return { success: false, error: \"cardNotFound\" };\n }\n const otherPlayer = game.players.find((p) => p !== player)!;\n const targetPile = isForOtherPlayerPile\n ? otherPlayer.centerPile\n : player.centerPile;\n const card = player.hand[cardIndex]!;\n if (!isCardPlayable(card, targetPile)) {\n return { success: false, error: \"cardNotPlayable\" };\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hand.splice(cardIndex, 1);\n targetPile.push(card);\n emitEvent(game, {\n type: \"cardPlayed\",\n username: player.username,\n card,\n isForOtherPlayerPile,\n });\n\n if (otherPlayer.hasNoPlayableCards && hasPlayableCard(otherPlayer, game)) {\n otherPlayer.hasNoPlayableCards = false;\n }\n\n if (player.hand.length === 0 && player.drawPile.length === 0) {\n emitEvent(game, { type: \"gameCompleted\" });\n const completedGame: Game = {\n ...game,\n status: \"completed\",\n };\n games.set(game.id, completedGame);\n }\n\n return { success: true };\n}\n","type Card = { readonly id: string };\n\nexport function shuffleCards<T extends Card>(cards: T[]): void {\n for (let i = cards.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [cards[i], cards[j]] = [cards[j]!, cards[i]!];\n }\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { shuffleCards } from \"../../lib/shuffleCards.js\";\nimport {\n CAN_PLAY_AT_DELAY_MS,\n EXPIRY_EXTENSION_MS,\n MAX_HAND_SIZE,\n} from \"../constants.js\";\nimport { games } from \"../games.js\";\nimport { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\n\ntype ReportNoPlayableCardsResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"alreadyReported\"\n | \"hasPlayableCard\"\n | \"canDraw\";\n };\n\nexport function reportNoPlayableCards(\n gameId: string,\n playerId: string,\n): ReportNoPlayableCardsResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" };\n }\n if (hasPlayableCard(player, game)) {\n return { success: false, error: \"hasPlayableCard\" };\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" };\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hasNoPlayableCards = true;\n\n const otherPlayer = game.players.find((p) => p !== player)!;\n if (otherPlayer.hasNoPlayableCards) {\n if (player.sidePile.length === 0 && otherPlayer.sidePile.length === 0) {\n const cards = [...player.centerPile, ...otherPlayer.centerPile];\n shuffleCards(cards);\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n } else {\n const playerSidePileCard = player.sidePile.pop()!;\n player.centerPile.push(playerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: player.username,\n card: playerSidePileCard,\n });\n const otherPlayerSidePileCard = otherPlayer.sidePile.pop()!;\n otherPlayer.centerPile.push(otherPlayerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: otherPlayer.username,\n card: otherPlayerSidePileCard,\n });\n }\n player.hasNoPlayableCards = false;\n otherPlayer.hasNoPlayableCards = false;\n game.canPlayAt = Date.now() + CAN_PLAY_AT_DELAY_MS;\n emitEvent(game, {\n type: \"canPlayAtUpdated\",\n canPlayAt: game.canPlayAt,\n });\n }\n\n return { success: true };\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { games } from \"../games.js\";\nimport type { ChatMessage } from \"../types/ChatMessage.js\";\n\ntype SendChatResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport function sendChat(\n gameId: string,\n playerId: string,\n text: string,\n): SendChatResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const message: ChatMessage = {\n id: crypto.randomUUID(),\n username: player.username,\n text,\n };\n game.chatMessages.push(message);\n emitEvent(game, { type: \"chat\", message });\n return { success: true };\n}\n","import { emitEvent } from \"../../lib/emitEvent.js\";\nimport { emitEventToPlayer } from \"../../lib/emitEventToPlayer.js\";\nimport { shuffleCards } from \"../../lib/shuffleCards.js\";\nimport {\n CAN_PLAY_AT_DELAY_MS,\n CARDS,\n EXPIRY_EXTENSION_MS,\n MIN_PLAYERS,\n} from \"../constants.js\";\nimport { games } from \"../games.js\";\nimport type { Game } from \"../types/Game.js\";\n\ntype StartGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"playerNotAdmin\"\n | \"minPlayersNotReached\";\n };\n\nexport function startGame(gameId: string, playerId: string): StartGameResult {\n const game = games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"open\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" };\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" };\n }\n const otherPlayer = game.players[1]!;\n const cards = [...CARDS];\n shuffleCards(cards);\n\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n\n player.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: player.username,\n numCards: player.drawPile.length,\n });\n\n player.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(player, { type: \"handInitialized\", cards: player.hand });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: player.username,\n numCards: player.hand.length,\n });\n\n otherPlayer.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.drawPile.length,\n });\n\n otherPlayer.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(otherPlayer, {\n type: \"handInitialized\",\n cards: otherPlayer.hand,\n });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.hand.length,\n });\n\n const startedGame: Game = {\n ...game,\n status: \"started\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS,\n };\n games.set(game.id, startedGame);\n emitEvent(startedGame, { type: \"gameStarted\" });\n emitEvent(startedGame, {\n type: \"expirationUpdated\",\n expiresAt: startedGame.expiresAt,\n });\n emitEvent(startedGame, {\n type: \"canPlayAtUpdated\",\n canPlayAt: startedGame.canPlayAt,\n });\n return { success: true };\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"startGame-ayp8a-Cl.d.mts","names":[],"sources":["../src/server/actions/createGame.ts","../src/server/actions/drawCard.ts","../src/server/actions/getClientStateAndClearEvents.ts","../src/server/actions/getEventsAndClearAcknowledged.ts","../src/server/actions/getJoinableGames.ts","../src/server/actions/joinGame.ts","../src/server/actions/leaveGame.ts","../src/server/actions/playCard.ts","../src/server/actions/reportNoPlayableCards.ts","../src/server/actions/sendChat.ts","../src/server/actions/startGame.ts"],"mappings":";;;KAEY,gBAAA;EAAA,SAEG,OAAA;EAAA,SACA,MAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAGC,UAAA,CAAW,MAAA,UAAgB,QAAA,WAAmB,gBAAgB;;;KCVlE,cAAA;EAAA,SAEG,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAiBC,QAAA,CAAS,KAAA,YAAiB,cAAc;;;KCtB5C,kCAAA;EAAA,SAEG,OAAA;EAAA,SACA,KAAA,EAAO,WAAW;AAAA;EAAA,SAGlB,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAUC,4BAAA,CACd,KAAA,YACC,kCAAkC;;;KCnBzB,mCAAA;EAAA,SAEG,OAAA;EAAA,SACA,MAAA,WAAiB,SAAS;AAAA;EAAA,SAG1B,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAcC,6BAAA,CACd,KAAA,YACC,mCAAmC;;;KCzB1B,sBAAA;EAAA,SACD,KAAA;IAAA,SACE,EAAA;IAAA,SACA,UAAA;EAAA;AAAA;AAAA,iBAIG,gBAAA,IAAoB,sBAAsB;;;KCN9C,cAAA;EAAA,SAEG,OAAA;EAAA,SACA,QAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAcC,QAAA,CACd,KAAA,WACA,MAAA,UACA,QAAA,WACC,cAAc;;;KCzBL,eAAA;EAAA,SAEG,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAUC,SAAA,CAAU,KAAA,YAAiB,eAAe;;;KChB9C,cAAA;EAAA,SAEG,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAsBC,QAAA,CAAS,KAAA,YAAiB,cAAc;;;KC5B5C,2BAAA;EAAA,SAEG,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAkBC,qBAAA,CACd,KAAA,YACC,2BAA2B;;;KC1BlB,cAAA;EAAA,SAEG,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAWC,QAAA,CAAS,KAAA,YAAiB,cAAc;;;KCjB5C,eAAA;EAAA,SAEG,OAAA;AAAA;EAAA,SAGA,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,iBAgBC,SAAA,CAAU,KAAA,YAAiB,eAAe"}