@hellacardgames/speed 0.11.2 → 0.12.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../src/client/Client.ts"],"sourcesContent":["import type { createServer } from \"../server/index.js\";\n\ntype Server = ReturnType<typeof createServer>;\n\ntype ServerResult<\n TServer extends {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n actions: readonly { path: string; action: (...args: any[]) => any }[];\n },\n TPath extends TServer[\"actions\"][number][\"path\"],\n> = ReturnType<Extract<TServer[\"actions\"][number], { path: TPath }>[\"action\"]>;\n\nexport class Client {\n private readonly baseUrl: string;\n\n constructor(baseUrl: string) {\n this.baseUrl = baseUrl;\n }\n\n async createGame(accessToken: string) {\n const response = await fetch(`${this.baseUrl}/createGame`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n });\n const result: ServerResult<Server, \"/createGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async drawCard(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/drawCard`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/drawCard\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async getClientStateAndClearEvents(gameId: string, playerId: string) {\n const response = await fetch(\n `${this.baseUrl}/getClientStateAndClearEvents`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n },\n );\n const result: ServerResult<Server, \"/getClientStateAndClearEvents\"> =\n await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async getEventsAndClearAcknowledged(\n gameId: string,\n playerId: string,\n lastReadId: string | null,\n ) {\n const response = await fetch(\n `${this.baseUrl}/getEventsAndClearAcknowledged`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId, lastReadId }),\n },\n );\n const result: ServerResult<Server, \"/getEventsAndClearAcknowledged\"> =\n await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async getJoinableGames() {\n const response = await fetch(`${this.baseUrl}/getJoinableGames`, {\n method: \"POST\",\n });\n const result: ServerResult<Server, \"/getJoinableGames\"> =\n await response.json();\n return result;\n }\n\n async joinGame(gameId: string, accessToken: string) {\n const response = await fetch(`${this.baseUrl}/joinGame`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId }),\n });\n const result: ServerResult<Server, \"/joinGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async leaveGame(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/leaveGame`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/leaveGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async playCard(\n gameId: string,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n ) {\n const response = await fetch(`${this.baseUrl}/playCard`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId, cardId, isForOtherPlayerPile }),\n });\n const result: ServerResult<Server, \"/playCard\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async reportNoPlayableCards(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/reportNoPlayableCards`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/reportNoPlayableCards\"> =\n await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async sendChat(gameId: string, playerId: string, text: string) {\n const response = await fetch(`${this.baseUrl}/sendChat`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId, text }),\n });\n const result: ServerResult<Server, \"/sendChat\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async startGame(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/startGame`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/startGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../src/client/Client.ts"],"sourcesContent":["import type { createServer } from \"../server/index.js\";\n\ntype Server = ReturnType<typeof createServer>;\n\ntype ServerResult<\n TServer extends {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n routes: readonly { path: string; action: (...args: any[]) => any }[];\n },\n TPath extends TServer[\"routes\"][number][\"path\"],\n> = ReturnType<Extract<TServer[\"routes\"][number], { path: TPath }>[\"action\"]>;\n\nexport class Client {\n private readonly baseUrl: string;\n\n constructor(baseUrl: string) {\n this.baseUrl = baseUrl;\n }\n\n async createGame(accessToken: string) {\n const response = await fetch(`${this.baseUrl}/createGame`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n });\n const result: ServerResult<Server, \"/createGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async drawCard(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/drawCard`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/drawCard\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async getClientStateAndClearEvents(gameId: string, playerId: string) {\n const response = await fetch(\n `${this.baseUrl}/getClientStateAndClearEvents`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n },\n );\n const result: ServerResult<Server, \"/getClientStateAndClearEvents\"> =\n await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async getEventsAndClearAcknowledged(\n gameId: string,\n playerId: string,\n lastReadId: string | null,\n ) {\n const response = await fetch(\n `${this.baseUrl}/getEventsAndClearAcknowledged`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId, lastReadId }),\n },\n );\n const result: ServerResult<Server, \"/getEventsAndClearAcknowledged\"> =\n await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async getJoinableGames() {\n const response = await fetch(`${this.baseUrl}/getJoinableGames`, {\n method: \"POST\",\n });\n const result: ServerResult<Server, \"/getJoinableGames\"> =\n await response.json();\n return result;\n }\n\n async joinGame(gameId: string, accessToken: string) {\n const response = await fetch(`${this.baseUrl}/joinGame`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId }),\n });\n const result: ServerResult<Server, \"/joinGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async leaveGame(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/leaveGame`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/leaveGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async playCard(\n gameId: string,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n ) {\n const response = await fetch(`${this.baseUrl}/playCard`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId, cardId, isForOtherPlayerPile }),\n });\n const result: ServerResult<Server, \"/playCard\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async reportNoPlayableCards(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/reportNoPlayableCards`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/reportNoPlayableCards\"> =\n await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async sendChat(gameId: string, playerId: string, text: string) {\n const response = await fetch(`${this.baseUrl}/sendChat`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId, text }),\n });\n const result: ServerResult<Server, \"/sendChat\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async startGame(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/startGame`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/startGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n}\n"],"mappings":"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"}
@@ -13,7 +13,6 @@ declare class Client {
13
13
  }>;
14
14
  drawCard(gameId: string, playerId: string): Promise<{
15
15
  readonly success: true;
16
- readonly error?: never;
17
16
  } | {
18
17
  readonly success: false;
19
18
  readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "handFull" | "drawPileEmpty" | "gameNotFound" | "invalidInput";
@@ -53,14 +52,12 @@ declare class Client {
53
52
  }>;
54
53
  playCard(gameId: string, playerId: string, cardId: string, isForOtherPlayerPile: boolean): Promise<{
55
54
  readonly success: true;
56
- readonly error?: never;
57
55
  } | {
58
56
  readonly success: false;
59
57
  readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "cardNotFound" | "cardNotPlayable" | "gameNotFound" | "invalidInput";
60
58
  }>;
61
59
  reportNoPlayableCards(gameId: string, playerId: string): Promise<{
62
60
  readonly success: true;
63
- readonly error?: never;
64
61
  } | {
65
62
  readonly success: false;
66
63
  readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "alreadyReported" | "hasPlayableCard" | "canDraw" | "gameNotFound" | "invalidInput";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/client/Client.ts","../../src/client/index.ts"],"mappings":";;cAYa;mBACM;EAEL,YAAA;EAIN,WAAW,sBAAmB;;;;;;;;EAc9B,SAAS,gBAAgB,mBAAgB;;;;;;;EAezC,6BAA6B,gBAAgB,mBAAgB;;oBAfpB;;;;;EAkCzC,8BACJ,gBACA,kBACA,4BAAyB;;8BAtBwC;;;;;EA0C7D,oBAAgB;;;;;;EAShB,SAAS,gBAAgB,sBAAmB;;;;;;;EAgB5C,UAAU,gBAAgB,mBAAgB;;;;;;EAe1C,SACJ,gBACA,kBACA,gBACA,gCAA6B;;;;;;;EAgBzB,sBAAsB,gBAAgB,mBAAgB;;;;;;;EAgBtD,SAAS,gBAAgB,kBAAkB,eAAY;;;;;;EAevD,UAAU,gBAAgB,mBAAgB;;;;;;;;;KClLtC,mBAAmB,QAAQ,WAAW;KACtC,iBAAiB,QAAQ,WAAW;KACpC,qCAAqC,QAC/C,WAAW;KAED,sCAAsC,QAChD,WAAW;KAED,yBAAyB,QACnC,WAAW;KAED,iBAAiB,QAAQ,WAAW;KACpC,kBAAkB,QAAQ,WAAW;KACrC,iBAAiB,QAAQ,WAAW;KACpC,wBAAwB,QAClC,WAAW;KAED,iBAAiB,QAAQ,WAAW;KACpC,kBAAkB,QAAQ,WAAW"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/client/Client.ts","../../src/client/index.ts"],"mappings":";;cAYa;mBACM;EAEL,YAAA;EAIN,WAAW,sBAAmB;;;;;;;;EAc9B,SAAS,gBAAgB,mBAAgB;;;;;;EAezC,6BAA6B,gBAAgB,mBAAgB;;oBAfpB;;;;;EAkCzC,8BACJ,gBACA,kBACA,4BAAyB;;8BAtBwC;;;;;EA0C7D,oBAAgB;;;;;;EAShB,SAAS,gBAAgB,sBAAmB;;;;;;;EAgB5C,UAAU,gBAAgB,mBAAgB;;;;;;EAe1C,SACJ,gBACA,kBACA,gBACA,gCAA6B;;;;;;EAgBzB,sBAAsB,gBAAgB,mBAAgB;;;;;;EAgBtD,SAAS,gBAAgB,kBAAkB,eAAY;;;;;;EAevD,UAAU,gBAAgB,mBAAgB;;;;;;;;;KClLtC,mBAAmB,QAAQ,WAAW;KACtC,iBAAiB,QAAQ,WAAW;KACpC,qCAAqC,QAC/C,WAAW;KAED,sCAAsC,QAChD,WAAW;KAED,yBAAyB,QACnC,WAAW;KAED,iBAAiB,QAAQ,WAAW;KACpC,kBAAkB,QAAQ,WAAW;KACrC,iBAAiB,QAAQ,WAAW;KACpC,wBAAwB,QAClC,WAAW;KAED,iBAAiB,QAAQ,WAAW;KACpC,kBAAkB,QAAQ,WAAW"}
@@ -13,7 +13,6 @@ declare class Client {
13
13
  }>;
14
14
  drawCard(gameId: string, playerId: string): Promise<{
15
15
  readonly success: true;
16
- readonly error?: never;
17
16
  } | {
18
17
  readonly success: false;
19
18
  readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "handFull" | "drawPileEmpty" | "gameNotFound" | "invalidInput";
@@ -53,14 +52,12 @@ declare class Client {
53
52
  }>;
54
53
  playCard(gameId: string, playerId: string, cardId: string, isForOtherPlayerPile: boolean): Promise<{
55
54
  readonly success: true;
56
- readonly error?: never;
57
55
  } | {
58
56
  readonly success: false;
59
57
  readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "cardNotFound" | "cardNotPlayable" | "gameNotFound" | "invalidInput";
60
58
  }>;
61
59
  reportNoPlayableCards(gameId: string, playerId: string): Promise<{
62
60
  readonly success: true;
63
- readonly error?: never;
64
61
  } | {
65
62
  readonly success: false;
66
63
  readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "alreadyReported" | "hasPlayableCard" | "canDraw" | "gameNotFound" | "invalidInput";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/client/Client.ts","../../src/client/index.ts"],"mappings":";;cAYa;mBACM;EAEL,YAAA;EAIN,WAAW,sBAAmB;;;;;;;;EAc9B,SAAS,gBAAgB,mBAAgB;;;;;;;EAezC,6BAA6B,gBAAgB,mBAAgB;;oBAfpB;;;;;EAkCzC,8BACJ,gBACA,kBACA,4BAAyB;;8BAtBwC;;;;;EA0C7D,oBAAgB;;;;;;EAShB,SAAS,gBAAgB,sBAAmB;;;;;;;EAgB5C,UAAU,gBAAgB,mBAAgB;;;;;;EAe1C,SACJ,gBACA,kBACA,gBACA,gCAA6B;;;;;;;EAgBzB,sBAAsB,gBAAgB,mBAAgB;;;;;;;EAgBtD,SAAS,gBAAgB,kBAAkB,eAAY;;;;;;EAevD,UAAU,gBAAgB,mBAAgB;;;;;;;;;KClLtC,mBAAmB,QAAQ,WAAW;KACtC,iBAAiB,QAAQ,WAAW;KACpC,qCAAqC,QAC/C,WAAW;KAED,sCAAsC,QAChD,WAAW;KAED,yBAAyB,QACnC,WAAW;KAED,iBAAiB,QAAQ,WAAW;KACpC,kBAAkB,QAAQ,WAAW;KACrC,iBAAiB,QAAQ,WAAW;KACpC,wBAAwB,QAClC,WAAW;KAED,iBAAiB,QAAQ,WAAW;KACpC,kBAAkB,QAAQ,WAAW"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/client/Client.ts","../../src/client/index.ts"],"mappings":";;cAYa;mBACM;EAEL,YAAA;EAIN,WAAW,sBAAmB;;;;;;;;EAc9B,SAAS,gBAAgB,mBAAgB;;;;;;EAezC,6BAA6B,gBAAgB,mBAAgB;;oBAfpB;;;;;EAkCzC,8BACJ,gBACA,kBACA,4BAAyB;;8BAtBwC;;;;;EA0C7D,oBAAgB;;;;;;EAShB,SAAS,gBAAgB,sBAAmB;;;;;;;EAgB5C,UAAU,gBAAgB,mBAAgB;;;;;;EAe1C,SACJ,gBACA,kBACA,gBACA,gCAA6B;;;;;;EAgBzB,sBAAsB,gBAAgB,mBAAgB;;;;;;EAgBtD,SAAS,gBAAgB,kBAAkB,eAAY;;;;;;EAevD,UAAU,gBAAgB,mBAAgB;;;;;;;;;KClLtC,mBAAmB,QAAQ,WAAW;KACtC,iBAAiB,QAAQ,WAAW;KACpC,qCAAqC,QAC/C,WAAW;KAED,sCAAsC,QAChD,WAAW;KAED,yBAAyB,QACnC,WAAW;KAED,iBAAiB,QAAQ,WAAW;KACpC,kBAAkB,QAAQ,WAAW;KACrC,iBAAiB,QAAQ,WAAW;KACpC,wBAAwB,QAClC,WAAW;KAED,iBAAiB,QAAQ,WAAW;KACpC,kBAAkB,QAAQ,WAAW"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/client/Client.ts"],"sourcesContent":["import type { createServer } from \"../server/index.js\";\n\ntype Server = ReturnType<typeof createServer>;\n\ntype ServerResult<\n TServer extends {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n actions: readonly { path: string; action: (...args: any[]) => any }[];\n },\n TPath extends TServer[\"actions\"][number][\"path\"],\n> = ReturnType<Extract<TServer[\"actions\"][number], { path: TPath }>[\"action\"]>;\n\nexport class Client {\n private readonly baseUrl: string;\n\n constructor(baseUrl: string) {\n this.baseUrl = baseUrl;\n }\n\n async createGame(accessToken: string) {\n const response = await fetch(`${this.baseUrl}/createGame`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n });\n const result: ServerResult<Server, \"/createGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async drawCard(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/drawCard`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/drawCard\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async getClientStateAndClearEvents(gameId: string, playerId: string) {\n const response = await fetch(\n `${this.baseUrl}/getClientStateAndClearEvents`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n },\n );\n const result: ServerResult<Server, \"/getClientStateAndClearEvents\"> =\n await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async getEventsAndClearAcknowledged(\n gameId: string,\n playerId: string,\n lastReadId: string | null,\n ) {\n const response = await fetch(\n `${this.baseUrl}/getEventsAndClearAcknowledged`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId, lastReadId }),\n },\n );\n const result: ServerResult<Server, \"/getEventsAndClearAcknowledged\"> =\n await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async getJoinableGames() {\n const response = await fetch(`${this.baseUrl}/getJoinableGames`, {\n method: \"POST\",\n });\n const result: ServerResult<Server, \"/getJoinableGames\"> =\n await response.json();\n return result;\n }\n\n async joinGame(gameId: string, accessToken: string) {\n const response = await fetch(`${this.baseUrl}/joinGame`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId }),\n });\n const result: ServerResult<Server, \"/joinGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async leaveGame(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/leaveGame`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/leaveGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async playCard(\n gameId: string,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n ) {\n const response = await fetch(`${this.baseUrl}/playCard`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId, cardId, isForOtherPlayerPile }),\n });\n const result: ServerResult<Server, \"/playCard\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async reportNoPlayableCards(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/reportNoPlayableCards`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/reportNoPlayableCards\"> =\n await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async sendChat(gameId: string, playerId: string, text: string) {\n const response = await fetch(`${this.baseUrl}/sendChat`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId, text }),\n });\n const result: ServerResult<Server, \"/sendChat\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async startGame(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/startGame`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/startGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n}\n"],"mappings":";AAYA,IAAa,SAAb,MAAoB;CAClB;CAEA,YAAY,SAAiB;EAC3B,KAAK,UAAU;CACjB;CAEA,MAAM,WAAW,aAAqB;EAOpC,MAAM,SAA8C,OAAM,MANnC,MAAM,GAAG,KAAK,QAAQ,cAAc;GACzD,QAAQ;GACR,SAAS,EACP,eAAe,UAAU,cAC3B;EACF,CAAC,EAAA,CACkE,KAAK;EACxE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,SAAS,QAAgB,UAAkB;EAQ/C,MAAM,SAA4C,OAAM,MAPjC,MAAM,GAAG,KAAK,QAAQ,YAAY;GACvD,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;GAAS,CAAC;EAC3C,CAAC,EAAA,CACgE,KAAK;EACtE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,6BAA6B,QAAgB,UAAkB;EAWnE,MAAM,SACJ,OAAM,MAXe,MACrB,GAAG,KAAK,QAAQ,gCAChB;GACE,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;GAAS,CAAC;EAC3C,CACF,EAAA,CAEiB,KAAK;EACtB,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,8BACJ,QACA,UACA,YACA;EAWA,MAAM,SACJ,OAAM,MAXe,MACrB,GAAG,KAAK,QAAQ,iCAChB;GACE,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;IAAU;GAAW,CAAC;EACvD,CACF,EAAA,CAEiB,KAAK;EACtB,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,mBAAmB;EAMvB,OAAO,OADC,MAJe,MAAM,GAAG,KAAK,QAAQ,oBAAoB,EAC/D,QAAQ,OACV,CAAC,EAAA,CAEgB,KAAK;CAExB;CAEA,MAAM,SAAS,QAAgB,aAAqB;EASlD,MAAM,SAA4C,OAAM,MARjC,MAAM,GAAG,KAAK,QAAQ,YAAY;GACvD,QAAQ;GACR,SAAS;IACP,eAAe,UAAU;IACzB,gBAAgB;GAClB;GACA,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;EACjC,CAAC,EAAA,CACgE,KAAK;EACtE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,UAAU,QAAgB,UAAkB;EAQhD,MAAM,SAA6C,OAAM,MAPlC,MAAM,GAAG,KAAK,QAAQ,aAAa;GACxD,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;GAAS,CAAC;EAC3C,CAAC,EAAA,CACiE,KAAK;EACvE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,SACJ,QACA,UACA,QACA,sBACA;EAQA,MAAM,SAA4C,OAAM,MAPjC,MAAM,GAAG,KAAK,QAAQ,YAAY;GACvD,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;IAAU;IAAQ;GAAqB,CAAC;EACzE,CAAC,EAAA,CACgE,KAAK;EACtE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,sBAAsB,QAAgB,UAAkB;EAQ5D,MAAM,SACJ,OAAM,MARe,MAAM,GAAG,KAAK,QAAQ,yBAAyB;GACpE,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;GAAS,CAAC;EAC3C,CAAC,EAAA,CAEgB,KAAK;EACtB,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,SAAS,QAAgB,UAAkB,MAAc;EAQ7D,MAAM,SAA4C,OAAM,MAPjC,MAAM,GAAG,KAAK,QAAQ,YAAY;GACvD,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;IAAU;GAAK,CAAC;EACjD,CAAC,EAAA,CACgE,KAAK;EACtE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,UAAU,QAAgB,UAAkB;EAQhD,MAAM,SAA6C,OAAM,MAPlC,MAAM,GAAG,KAAK,QAAQ,aAAa;GACxD,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;GAAS,CAAC;EAC3C,CAAC,EAAA,CACiE,KAAK;EACvE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/client/Client.ts"],"sourcesContent":["import type { createServer } from \"../server/index.js\";\n\ntype Server = ReturnType<typeof createServer>;\n\ntype ServerResult<\n TServer extends {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n routes: readonly { path: string; action: (...args: any[]) => any }[];\n },\n TPath extends TServer[\"routes\"][number][\"path\"],\n> = ReturnType<Extract<TServer[\"routes\"][number], { path: TPath }>[\"action\"]>;\n\nexport class Client {\n private readonly baseUrl: string;\n\n constructor(baseUrl: string) {\n this.baseUrl = baseUrl;\n }\n\n async createGame(accessToken: string) {\n const response = await fetch(`${this.baseUrl}/createGame`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n });\n const result: ServerResult<Server, \"/createGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async drawCard(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/drawCard`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/drawCard\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async getClientStateAndClearEvents(gameId: string, playerId: string) {\n const response = await fetch(\n `${this.baseUrl}/getClientStateAndClearEvents`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n },\n );\n const result: ServerResult<Server, \"/getClientStateAndClearEvents\"> =\n await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async getEventsAndClearAcknowledged(\n gameId: string,\n playerId: string,\n lastReadId: string | null,\n ) {\n const response = await fetch(\n `${this.baseUrl}/getEventsAndClearAcknowledged`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId, lastReadId }),\n },\n );\n const result: ServerResult<Server, \"/getEventsAndClearAcknowledged\"> =\n await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async getJoinableGames() {\n const response = await fetch(`${this.baseUrl}/getJoinableGames`, {\n method: \"POST\",\n });\n const result: ServerResult<Server, \"/getJoinableGames\"> =\n await response.json();\n return result;\n }\n\n async joinGame(gameId: string, accessToken: string) {\n const response = await fetch(`${this.baseUrl}/joinGame`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId }),\n });\n const result: ServerResult<Server, \"/joinGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async leaveGame(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/leaveGame`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/leaveGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async playCard(\n gameId: string,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n ) {\n const response = await fetch(`${this.baseUrl}/playCard`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId, cardId, isForOtherPlayerPile }),\n });\n const result: ServerResult<Server, \"/playCard\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async reportNoPlayableCards(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/reportNoPlayableCards`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/reportNoPlayableCards\"> =\n await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async sendChat(gameId: string, playerId: string, text: string) {\n const response = await fetch(`${this.baseUrl}/sendChat`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId, text }),\n });\n const result: ServerResult<Server, \"/sendChat\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n\n async startGame(gameId: string, playerId: string) {\n const response = await fetch(`${this.baseUrl}/startGame`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ gameId, playerId }),\n });\n const result: ServerResult<Server, \"/startGame\"> = await response.json();\n if (!result.success) {\n return { success: false, error: result.error } as const;\n }\n return result;\n }\n}\n"],"mappings":";AAYA,IAAa,SAAb,MAAoB;CAClB;CAEA,YAAY,SAAiB;EAC3B,KAAK,UAAU;CACjB;CAEA,MAAM,WAAW,aAAqB;EAOpC,MAAM,SAA8C,OAAM,MANnC,MAAM,GAAG,KAAK,QAAQ,cAAc;GACzD,QAAQ;GACR,SAAS,EACP,eAAe,UAAU,cAC3B;EACF,CAAC,EAAA,CACkE,KAAK;EACxE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,SAAS,QAAgB,UAAkB;EAQ/C,MAAM,SAA4C,OAAM,MAPjC,MAAM,GAAG,KAAK,QAAQ,YAAY;GACvD,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;GAAS,CAAC;EAC3C,CAAC,EAAA,CACgE,KAAK;EACtE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,6BAA6B,QAAgB,UAAkB;EAWnE,MAAM,SACJ,OAAM,MAXe,MACrB,GAAG,KAAK,QAAQ,gCAChB;GACE,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;GAAS,CAAC;EAC3C,CACF,EAAA,CAEiB,KAAK;EACtB,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,8BACJ,QACA,UACA,YACA;EAWA,MAAM,SACJ,OAAM,MAXe,MACrB,GAAG,KAAK,QAAQ,iCAChB;GACE,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;IAAU;GAAW,CAAC;EACvD,CACF,EAAA,CAEiB,KAAK;EACtB,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,mBAAmB;EAMvB,OAAO,OADC,MAJe,MAAM,GAAG,KAAK,QAAQ,oBAAoB,EAC/D,QAAQ,OACV,CAAC,EAAA,CAEgB,KAAK;CAExB;CAEA,MAAM,SAAS,QAAgB,aAAqB;EASlD,MAAM,SAA4C,OAAM,MARjC,MAAM,GAAG,KAAK,QAAQ,YAAY;GACvD,QAAQ;GACR,SAAS;IACP,eAAe,UAAU;IACzB,gBAAgB;GAClB;GACA,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;EACjC,CAAC,EAAA,CACgE,KAAK;EACtE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,UAAU,QAAgB,UAAkB;EAQhD,MAAM,SAA6C,OAAM,MAPlC,MAAM,GAAG,KAAK,QAAQ,aAAa;GACxD,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;GAAS,CAAC;EAC3C,CAAC,EAAA,CACiE,KAAK;EACvE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,SACJ,QACA,UACA,QACA,sBACA;EAQA,MAAM,SAA4C,OAAM,MAPjC,MAAM,GAAG,KAAK,QAAQ,YAAY;GACvD,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;IAAU;IAAQ;GAAqB,CAAC;EACzE,CAAC,EAAA,CACgE,KAAK;EACtE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,sBAAsB,QAAgB,UAAkB;EAQ5D,MAAM,SACJ,OAAM,MARe,MAAM,GAAG,KAAK,QAAQ,yBAAyB;GACpE,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;GAAS,CAAC;EAC3C,CAAC,EAAA,CAEgB,KAAK;EACtB,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,SAAS,QAAgB,UAAkB,MAAc;EAQ7D,MAAM,SAA4C,OAAM,MAPjC,MAAM,GAAG,KAAK,QAAQ,YAAY;GACvD,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;IAAU;GAAK,CAAC;EACjD,CAAC,EAAA,CACgE,KAAK;EACtE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;CAEA,MAAM,UAAU,QAAgB,UAAkB;EAQhD,MAAM,SAA6C,OAAM,MAPlC,MAAM,GAAG,KAAK,QAAQ,aAAa;GACxD,QAAQ;GACR,SAAS,EACP,gBAAgB,mBAClB;GACA,MAAM,KAAK,UAAU;IAAE;IAAQ;GAAS,CAAC;EAC3C,CAAC,EAAA,CACiE,KAAK;EACvE,IAAI,CAAC,OAAO,SACV,OAAO;GAAE,SAAS;GAAO,OAAO,OAAO;EAAM;EAE/C,OAAO;CACT;AACF"}
@@ -1,3 +1,3 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_manager = require("../manager-BI5b7WMo.cjs");
2
+ const require_manager = require("../manager-DdpdgNfz.cjs");
3
3
  exports.createManager = require_manager.createManager;
@@ -89,36 +89,45 @@ declare const createManager: (logKey: string, maxGames: number, watchdogInterval
89
89
  };
90
90
  } & Readonly<{
91
91
  drawCard: (gameId: string, playerId: string) => {
92
- readonly success: false;
93
- readonly error: "gameNotFound";
94
- } | {
95
92
  readonly success: true;
96
- readonly error?: never;
97
93
  } | {
98
94
  readonly success: false;
99
- readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "handFull" | "drawPileEmpty";
95
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "handFull" | "drawPileEmpty" | "gameNotFound";
100
96
  };
101
97
  playCard: (gameId: string, playerId: string, cardId: string, isForOtherPlayerPile: boolean) => {
102
- readonly success: false;
103
- readonly error: "gameNotFound";
104
- } | {
105
98
  readonly success: true;
106
- readonly error?: never;
107
99
  } | {
108
100
  readonly success: false;
109
- readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "cardNotFound" | "cardNotPlayable";
101
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "cardNotFound" | "cardNotPlayable" | "gameNotFound";
110
102
  };
111
103
  reportNoPlayableCards: (gameId: string, playerId: string) => {
112
- readonly success: false;
113
- readonly error: "gameNotFound";
114
- } | {
115
104
  readonly success: true;
116
- readonly error?: never;
117
105
  } | {
118
106
  readonly success: false;
119
- readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "alreadyReported" | "hasPlayableCard" | "canDraw";
107
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "alreadyReported" | "hasPlayableCard" | "canDraw" | "gameNotFound";
120
108
  };
121
- }>;
109
+ }> & {
110
+ readonly gameplayActions: Readonly<{
111
+ drawCard: (gameId: string, playerId: string) => {
112
+ readonly success: true;
113
+ } | {
114
+ readonly success: false;
115
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "handFull" | "drawPileEmpty" | "gameNotFound";
116
+ };
117
+ playCard: (gameId: string, playerId: string, cardId: string, isForOtherPlayerPile: boolean) => {
118
+ readonly success: true;
119
+ } | {
120
+ readonly success: false;
121
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "cardNotFound" | "cardNotPlayable" | "gameNotFound";
122
+ };
123
+ reportNoPlayableCards: (gameId: string, playerId: string) => {
124
+ readonly success: true;
125
+ } | {
126
+ readonly success: false;
127
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "alreadyReported" | "hasPlayableCard" | "canDraw" | "gameNotFound";
128
+ };
129
+ }>;
130
+ };
122
131
  //#endregion
123
132
  export { createManager };
124
133
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/manager/createManager.ts"],"mappings":";;cAea,gBAAa,gBAAA,kBAAA;;;;aAekiI;aAA+B;;;;;aAA4H;;;;;;;;;;;;oBAf1sI"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/manager/createManager.ts"],"mappings":";;cAea,gBAAa,gBAAA,kBAAA;;;;aAe4lI;aAA+B;;;;;aAA4H;;;;;;;;;;;;oBAfpwI"}
@@ -89,36 +89,45 @@ declare const createManager: (logKey: string, maxGames: number, watchdogInterval
89
89
  };
90
90
  } & Readonly<{
91
91
  drawCard: (gameId: string, playerId: string) => {
92
- readonly success: false;
93
- readonly error: "gameNotFound";
94
- } | {
95
92
  readonly success: true;
96
- readonly error?: never;
97
93
  } | {
98
94
  readonly success: false;
99
- readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "handFull" | "drawPileEmpty";
95
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "handFull" | "drawPileEmpty" | "gameNotFound";
100
96
  };
101
97
  playCard: (gameId: string, playerId: string, cardId: string, isForOtherPlayerPile: boolean) => {
102
- readonly success: false;
103
- readonly error: "gameNotFound";
104
- } | {
105
98
  readonly success: true;
106
- readonly error?: never;
107
99
  } | {
108
100
  readonly success: false;
109
- readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "cardNotFound" | "cardNotPlayable";
101
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "cardNotFound" | "cardNotPlayable" | "gameNotFound";
110
102
  };
111
103
  reportNoPlayableCards: (gameId: string, playerId: string) => {
112
- readonly success: false;
113
- readonly error: "gameNotFound";
114
- } | {
115
104
  readonly success: true;
116
- readonly error?: never;
117
105
  } | {
118
106
  readonly success: false;
119
- readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "alreadyReported" | "hasPlayableCard" | "canDraw";
107
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "alreadyReported" | "hasPlayableCard" | "canDraw" | "gameNotFound";
120
108
  };
121
- }>;
109
+ }> & {
110
+ readonly gameplayActions: Readonly<{
111
+ drawCard: (gameId: string, playerId: string) => {
112
+ readonly success: true;
113
+ } | {
114
+ readonly success: false;
115
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "handFull" | "drawPileEmpty" | "gameNotFound";
116
+ };
117
+ playCard: (gameId: string, playerId: string, cardId: string, isForOtherPlayerPile: boolean) => {
118
+ readonly success: true;
119
+ } | {
120
+ readonly success: false;
121
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "cardNotFound" | "cardNotPlayable" | "gameNotFound";
122
+ };
123
+ reportNoPlayableCards: (gameId: string, playerId: string) => {
124
+ readonly success: true;
125
+ } | {
126
+ readonly success: false;
127
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "alreadyReported" | "hasPlayableCard" | "canDraw" | "gameNotFound";
128
+ };
129
+ }>;
130
+ };
122
131
  //#endregion
123
132
  export { createManager };
124
133
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/manager/createManager.ts"],"mappings":";;cAea,gBAAa,gBAAA,kBAAA;;;;aAekiI;aAA+B;;;;;aAA4H;;;;;;;;;;;;oBAf1sI"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/manager/createManager.ts"],"mappings":";;cAea,gBAAa,gBAAA,kBAAA;;;;aAe4lI;aAA+B;;;;;aAA4H;;;;;;;;;;;;oBAfpwI"}
@@ -1,2 +1,2 @@
1
- import { t as createManager } from "../manager-D7K5YYcq.mjs";
1
+ import { t as createManager } from "../manager-C8wqbmrE.mjs";
2
2
  export { createManager };
@@ -725,13 +725,13 @@ const createManager = createManagerFactory({
725
725
  leaveGame,
726
726
  sendChat,
727
727
  startGame,
728
- addCustomActions: (wrapAction) => ({
729
- drawCard: wrapAction(drawCard),
730
- playCard: wrapAction(playCard),
731
- reportNoPlayableCards: wrapAction(reportNoPlayableCards)
732
- })
728
+ gameplayActions: {
729
+ drawCard,
730
+ playCard,
731
+ reportNoPlayableCards
732
+ }
733
733
  });
734
734
  //#endregion
735
735
  export { createManager as t };
736
736
 
737
- //# sourceMappingURL=manager-D7K5YYcq.mjs.map
737
+ //# sourceMappingURL=manager-C8wqbmrE.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"manager-D7K5YYcq.mjs","names":[],"sources":["../src/game/constants.ts","../src/game/actions/createGame.ts","../src/game/lib/emitEvent.ts","../src/game/lib/emitEventToPlayer.ts","../src/game/actions/drawCard.ts","../src/game/actions/getClientStateAndClearEvents.ts","../src/game/actions/joinGame.ts","../src/game/actions/leaveGame.ts","../src/game/lib/isCardPlayable.ts","../src/game/lib/hasPlayableCard.ts","../src/game/actions/playCard.ts","../src/game/lib/shuffleCards.ts","../src/game/actions/reportNoPlayableCards.ts","../src/game/actions/startGame.ts","../src/manager/createManager.ts"],"sourcesContent":["import type { Card } from \"./types/Card.js\";\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 { EXPIRY_EXTENSION_MS } from \"../constants.js\";\nimport type { CreatedGame } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function createGame(userId: string, username: string) {\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\n const createdAt = Date.now();\n\n const game: CreatedGame = {\n status: \"created\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n };\n\n return { game, playerId: player.id } as const;\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 type { Game } from \"../types/Game.js\";\n\nexport function drawCard(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" } as const;\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" } as const;\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, game } as const;\n}\n","import { getClientStateAndClearEventsFactory } from \"@hellacardgames/lib\";\nimport type { ClientState } from \"../types/ClientState.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport const getClientStateAndClearEvents = getClientStateAndClearEventsFactory<\n Game,\n ClientState\n>((game, player) => ({\n status: game.status,\n gameId: game.id,\n playerId: player.id,\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","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { MAX_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function joinGame(game: Game, userId: string, username: string) {\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" } as const;\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" } as const;\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, game, playerId: player.id } as const;\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { EXPIRY_EXTENSION_MS, MIN_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function leaveGame(game: Game, playerId: string) {\n const playerIndex = game.players.findIndex((p) => p.id === playerId);\n if (playerIndex === -1) {\n return { success: false, error: \"playerNotFound\" } as const;\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 // this.games.set(game.id, forfeitedGame);\n emitEvent(forfeitedGame, { type: \"gameForfeited\" });\n emitEvent(forfeitedGame, {\n type: \"expirationUpdated\",\n expiresAt: forfeitedGame.expiresAt,\n });\n return { success: true, game: forfeitedGame } as const;\n }\n return { success: true, game } as const;\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 { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport { isCardPlayable } from \"../lib/isCardPlayable.js\";\nimport type { CompletedGame, Game } from \"../types/Game.js\";\n\nexport function playCard(\n game: Game,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n const cardIndex = player.hand.findIndex((c) => c.id === cardId);\n if (cardIndex === -1) {\n return { success: false, error: \"cardNotFound\" } as const;\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\" } as const;\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: CompletedGame = {\n ...game,\n status: \"completed\",\n };\n return { success: true, game: completedGame } as const;\n }\n\n return { success: true, game } as const;\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 { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function reportNoPlayableCards(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" } as const;\n }\n if (hasPlayableCard(player, game)) {\n return { success: false, error: \"hasPlayableCard\" } as const;\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" } as const;\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, game } as const;\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 type { Game, StartedGame } from \"../types/Game.js\";\n\nexport function startGame(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" } as const;\n }\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" } as const;\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: StartedGame = {\n ...game,\n status: \"started\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS,\n };\n // this.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, game: startedGame } as const;\n}\n","import { createManagerFactory } from \"@hellacardgames/lib\";\nimport {\n createGame,\n drawCard,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n MAX_PLAYERS,\n playCard,\n reportNoPlayableCards,\n sendChat,\n startGame,\n} from \"../game/index.js\";\n\nexport const createManager = createManagerFactory({\n maxPlayers: MAX_PLAYERS,\n createGame,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n sendChat,\n startGame,\n addCustomActions: (wrapAction) => ({\n drawCard: wrapAction(drawCard),\n playCard: wrapAction(playCard),\n reportNoPlayableCards: wrapAction(reportNoPlayableCards),\n }),\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"manager-C8wqbmrE.mjs","names":[],"sources":["../src/game/constants.ts","../src/game/actions/createGame.ts","../src/game/lib/emitEvent.ts","../src/game/lib/emitEventToPlayer.ts","../src/game/actions/drawCard.ts","../src/game/actions/getClientStateAndClearEvents.ts","../src/game/actions/joinGame.ts","../src/game/actions/leaveGame.ts","../src/game/lib/isCardPlayable.ts","../src/game/lib/hasPlayableCard.ts","../src/game/actions/playCard.ts","../src/game/lib/shuffleCards.ts","../src/game/actions/reportNoPlayableCards.ts","../src/game/actions/startGame.ts","../src/manager/createManager.ts"],"sourcesContent":["import type { Card } from \"./types/Card.js\";\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 { EXPIRY_EXTENSION_MS } from \"../constants.js\";\nimport type { CreatedGame } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function createGame(userId: string, username: string) {\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\n const createdAt = Date.now();\n\n const game: CreatedGame = {\n status: \"created\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n };\n\n return { game, playerId: player.id } as const;\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 type { Game } from \"../types/Game.js\";\n\nexport function drawCard(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" } as const;\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" } as const;\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, game } as const;\n}\n","import { getClientStateAndClearEventsFactory } from \"@hellacardgames/lib\";\nimport type { ClientState } from \"../types/ClientState.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport const getClientStateAndClearEvents = getClientStateAndClearEventsFactory<\n Game,\n ClientState\n>((game, player) => ({\n status: game.status,\n gameId: game.id,\n playerId: player.id,\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","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { MAX_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function joinGame(game: Game, userId: string, username: string) {\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" } as const;\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" } as const;\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, game, playerId: player.id } as const;\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { EXPIRY_EXTENSION_MS, MIN_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function leaveGame(game: Game, playerId: string) {\n const playerIndex = game.players.findIndex((p) => p.id === playerId);\n if (playerIndex === -1) {\n return { success: false, error: \"playerNotFound\" } as const;\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 // this.games.set(game.id, forfeitedGame);\n emitEvent(forfeitedGame, { type: \"gameForfeited\" });\n emitEvent(forfeitedGame, {\n type: \"expirationUpdated\",\n expiresAt: forfeitedGame.expiresAt,\n });\n return { success: true, game: forfeitedGame } as const;\n }\n return { success: true, game } as const;\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 { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport { isCardPlayable } from \"../lib/isCardPlayable.js\";\nimport type { CompletedGame, Game } from \"../types/Game.js\";\n\nexport function playCard(\n game: Game,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n const cardIndex = player.hand.findIndex((c) => c.id === cardId);\n if (cardIndex === -1) {\n return { success: false, error: \"cardNotFound\" } as const;\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\" } as const;\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: CompletedGame = {\n ...game,\n status: \"completed\",\n };\n return { success: true, game: completedGame } as const;\n }\n\n return { success: true, game } as const;\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 { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function reportNoPlayableCards(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" } as const;\n }\n if (hasPlayableCard(player, game)) {\n return { success: false, error: \"hasPlayableCard\" } as const;\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" } as const;\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, game } as const;\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 type { Game, StartedGame } from \"../types/Game.js\";\n\nexport function startGame(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" } as const;\n }\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" } as const;\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: StartedGame = {\n ...game,\n status: \"started\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS,\n };\n // this.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, game: startedGame } as const;\n}\n","import { createManagerFactory } from \"@hellacardgames/lib\";\nimport {\n createGame,\n drawCard,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n MAX_PLAYERS,\n playCard,\n reportNoPlayableCards,\n sendChat,\n startGame,\n} from \"../game/index.js\";\n\nexport const createManager = createManagerFactory({\n maxPlayers: MAX_PLAYERS,\n createGame,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n sendChat,\n startGame,\n gameplayActions: {\n drawCard,\n playCard,\n reportNoPlayableCards,\n },\n});\n"],"mappings":"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"}
@@ -725,11 +725,11 @@ const createManager = (0, _hellacardgames_lib.createManagerFactory)({
725
725
  leaveGame,
726
726
  sendChat: _hellacardgames_lib.sendChat,
727
727
  startGame,
728
- addCustomActions: (wrapAction) => ({
729
- drawCard: wrapAction(drawCard),
730
- playCard: wrapAction(playCard),
731
- reportNoPlayableCards: wrapAction(reportNoPlayableCards)
732
- })
728
+ gameplayActions: {
729
+ drawCard,
730
+ playCard,
731
+ reportNoPlayableCards
732
+ }
733
733
  });
734
734
  //#endregion
735
735
  Object.defineProperty(exports, "createManager", {
@@ -739,4 +739,4 @@ Object.defineProperty(exports, "createManager", {
739
739
  }
740
740
  });
741
741
 
742
- //# sourceMappingURL=manager-BI5b7WMo.cjs.map
742
+ //# sourceMappingURL=manager-DdpdgNfz.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"manager-BI5b7WMo.cjs","names":["getClientStateAndClearEventsFactory","createManagerFactory"],"sources":["../src/game/constants.ts","../src/game/actions/createGame.ts","../src/game/lib/emitEvent.ts","../src/game/lib/emitEventToPlayer.ts","../src/game/actions/drawCard.ts","../src/game/actions/getClientStateAndClearEvents.ts","../src/game/actions/joinGame.ts","../src/game/actions/leaveGame.ts","../src/game/lib/isCardPlayable.ts","../src/game/lib/hasPlayableCard.ts","../src/game/actions/playCard.ts","../src/game/lib/shuffleCards.ts","../src/game/actions/reportNoPlayableCards.ts","../src/game/actions/startGame.ts","../src/manager/createManager.ts"],"sourcesContent":["import type { Card } from \"./types/Card.js\";\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 { EXPIRY_EXTENSION_MS } from \"../constants.js\";\nimport type { CreatedGame } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function createGame(userId: string, username: string) {\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\n const createdAt = Date.now();\n\n const game: CreatedGame = {\n status: \"created\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n };\n\n return { game, playerId: player.id } as const;\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 type { Game } from \"../types/Game.js\";\n\nexport function drawCard(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" } as const;\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" } as const;\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, game } as const;\n}\n","import { getClientStateAndClearEventsFactory } from \"@hellacardgames/lib\";\nimport type { ClientState } from \"../types/ClientState.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport const getClientStateAndClearEvents = getClientStateAndClearEventsFactory<\n Game,\n ClientState\n>((game, player) => ({\n status: game.status,\n gameId: game.id,\n playerId: player.id,\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","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { MAX_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function joinGame(game: Game, userId: string, username: string) {\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" } as const;\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" } as const;\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, game, playerId: player.id } as const;\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { EXPIRY_EXTENSION_MS, MIN_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function leaveGame(game: Game, playerId: string) {\n const playerIndex = game.players.findIndex((p) => p.id === playerId);\n if (playerIndex === -1) {\n return { success: false, error: \"playerNotFound\" } as const;\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 // this.games.set(game.id, forfeitedGame);\n emitEvent(forfeitedGame, { type: \"gameForfeited\" });\n emitEvent(forfeitedGame, {\n type: \"expirationUpdated\",\n expiresAt: forfeitedGame.expiresAt,\n });\n return { success: true, game: forfeitedGame } as const;\n }\n return { success: true, game } as const;\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 { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport { isCardPlayable } from \"../lib/isCardPlayable.js\";\nimport type { CompletedGame, Game } from \"../types/Game.js\";\n\nexport function playCard(\n game: Game,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n const cardIndex = player.hand.findIndex((c) => c.id === cardId);\n if (cardIndex === -1) {\n return { success: false, error: \"cardNotFound\" } as const;\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\" } as const;\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: CompletedGame = {\n ...game,\n status: \"completed\",\n };\n return { success: true, game: completedGame } as const;\n }\n\n return { success: true, game } as const;\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 { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function reportNoPlayableCards(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" } as const;\n }\n if (hasPlayableCard(player, game)) {\n return { success: false, error: \"hasPlayableCard\" } as const;\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" } as const;\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, game } as const;\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 type { Game, StartedGame } from \"../types/Game.js\";\n\nexport function startGame(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" } as const;\n }\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" } as const;\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: StartedGame = {\n ...game,\n status: \"started\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS,\n };\n // this.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, game: startedGame } as const;\n}\n","import { createManagerFactory } from \"@hellacardgames/lib\";\nimport {\n createGame,\n drawCard,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n MAX_PLAYERS,\n playCard,\n reportNoPlayableCards,\n sendChat,\n startGame,\n} from \"../game/index.js\";\n\nexport const createManager = createManagerFactory({\n maxPlayers: MAX_PLAYERS,\n createGame,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n sendChat,\n startGame,\n addCustomActions: (wrapAction) => ({\n drawCard: wrapAction(drawCard),\n playCard: wrapAction(playCard),\n reportNoPlayableCards: wrapAction(reportNoPlayableCards),\n }),\n});\n"],"mappings":";;AAEA,MAAa,sBAAsB;AAInC,MAAa,uBAAuB;AAEpC,MAAa,QAAyB;CACpC;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAQ;CACnD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAQ;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAW;CACtD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAW;CACvD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAG,OAAO;CAAS;CACpD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;CACrD;EAAE,IAAI,OAAO,WAAW;EAAG,MAAM;EAAI,OAAO;CAAS;AACvD;;;ACzDA,SAAgB,WAAW,QAAgB,UAAkB;CAC3D,MAAM,SAAiB;EACrB,IAAI,OAAO,WAAW;EACtB;EACA;EACA,QAAQ,CAAC;EACT,MAAM,CAAC;EACP,UAAU,CAAC;EACX,UAAU,CAAC;EACX,YAAY,CAAC;EACb,oBAAoB;CACtB;CAEA,MAAM,YAAY,KAAK,IAAI;CAW3B,OAAO;EAAE,MAAA;GARP,QAAQ;GACR,IAAI,OAAO,WAAW;GACtB;GACA,WAAW,YAAY;GACvB,cAAc,CAAC;GACf,SAAS,CAAC,MAAM;EAGN;EAAG,UAAU,OAAO;CAAG;AACrC;;;ACrBA,SAAgB,UACd,MACA,MACM;CACN,MAAM,QAAQ;EAAE,GAAG;EAAM,IAAI,OAAO,WAAW;CAAE;CACjD,KAAK,MAAM,KAAK,KAAK,SACnB,EAAE,OAAO,KAAK,KAAK;AAEvB;;;ACVA,SAAgB,kBACd,QACA,MACM;CACN,OAAO,OAAO,KAAK;EAAE,GAAG;EAAM,IAAI,OAAO,WAAW;CAAE,CAAC;AACzD;;;ACNA,SAAgB,SAAS,MAAY,UAAkB;CACrD,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;CACzD,IAAI,CAAC,QACH,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,IAAI,IAAI,KAAK,WACpB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAsB;CAExD,IAAI,OAAO,KAAK,UAAA,GACd,OAAO;EAAE,SAAS;EAAO,OAAO;CAAW;CAE7C,IAAI,OAAO,SAAS,WAAW,GAC7B,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,KAAK,YAAY,KAAK,IAAI,IAAI;CAC9B,UAAU,MAAM;EAAE,MAAM;EAAqB,WAAW,KAAK;CAAU,CAAC;CACxE,MAAM,OAAO,OAAO,SAAS,IAAI;CACjC,OAAO,KAAK,KAAK,IAAI;CACrB,kBAAkB,QAAQ;EAAE,MAAM;EAAY;CAAK,CAAC;CACpD,UAAU,MAAM;EAAE,MAAM;EAAkB,UAAU,OAAO;CAAS,CAAC;CACrE,OAAO;EAAE,SAAS;EAAM;CAAK;AAC/B;;;ACzBA,MAAa,gCAAA,GAA+BA,oBAAAA,oCAAAA,EAGzC,MAAM,YAAY;CACnB,QAAQ,KAAK;CACb,QAAQ,KAAK;CACb,UAAU,OAAO;CACjB,UAAU,OAAO;CACjB,SAAS,KAAK,QAAQ,KAAK,OAAO;EAChC,UAAU,EAAE;EACZ,UAAU,EAAE,KAAK;EACjB,cAAc,EAAE,SAAS;EACzB,cAAc,EAAE,SAAS;EACzB,mBAAmB,EAAE,WAAW,SAC5B,EAAE,WAAW,EAAE,WAAW,SAAS,KACnC;CACN,EAAE;CACF,WAAW,KAAK;CAChB,cAAc,KAAK;CACnB,MAAM,OAAO;CACb,WAAW,KAAK,WAAW,YAAY,KAAK,YAAY;AAC1D,EAAE;;;ACpBF,SAAgB,SAAS,MAAY,QAAgB,UAAkB;CACrE,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,QAAQ,WAAA,GACf,OAAO;EAAE,SAAS;EAAO,OAAO;CAAoB;CAEtD,IAAI,KAAK,QAAQ,MAAM,MAAM,EAAE,WAAW,MAAM,GAC9C,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,MAAM,SAAiB;EACrB,IAAI,OAAO,WAAW;EACtB;EACA;EACA,QAAQ,CAAC;EACT,MAAM,CAAC;EACP,UAAU,CAAC;EACX,UAAU,CAAC;EACX,YAAY,CAAC;EACb,oBAAoB;CACtB;CACA,KAAK,QAAQ,KAAK,MAAM;CACxB,UAAU,MAAM;EAAE,MAAM;EAAgB;CAAS,CAAC;CAClD,OAAO;EAAE,SAAS;EAAM;EAAM,UAAU,OAAO;CAAG;AACpD;;;ACzBA,SAAgB,UAAU,MAAY,UAAkB;CACtD,MAAM,cAAc,KAAK,QAAQ,WAAW,MAAM,EAAE,OAAO,QAAQ;CACnE,IAAI,gBAAgB,IAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAGnD,MAAM,SAAS,KAAK,QAAQ;CAC5B,UAAU,MAAM;EAAE,MAAM;EAAc,UAAU,OAAO;CAAS,CAAC;CAEjE,KAAK,QAAQ,OAAO,aAAa,CAAC;CAElC,IAAI,KAAK,WAAW,aAAa,KAAK,QAAQ,SAAA,GAAsB;EAClE,MAAM,gBAAsB;GAC1B,GAAG;GACH,QAAQ;GACR,WAAW,KAAK,IAAI,IAAI;EAC1B;EAEA,UAAU,eAAe,EAAE,MAAM,gBAAgB,CAAC;EAClD,UAAU,eAAe;GACvB,MAAM;GACN,WAAW,cAAc;EAC3B,CAAC;EACD,OAAO;GAAE,SAAS;GAAM,MAAM;EAAc;CAC9C;CACA,OAAO;EAAE,SAAS;EAAM;CAAK;AAC/B;;;AC5BA,SAAgB,eAAe,MAAY,YAAoB;CAC7D,MAAM,aAAa,WAAW,WAAW,SAAS;CAElD,OADa,KAAK,IAAI,KAAK,OAAO,WAAW,IAAI,IAAI,OACrC;AAClB;;;ACFA,SAAgB,gBAAgB,QAAgB,MAAY;CAC1D,MAAM,cAAc,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM;CACzD,MAAM,cAAc,OAAO;CAC3B,MAAM,cAAc,YAAY;CAChC,KAAK,MAAM,QAAQ,OAAO,MACxB,IACE,eAAe,MAAM,WAAW,KAChC,eAAe,MAAM,WAAW,GAEhC,OAAO;CAGX,OAAO;AACT;;;ACXA,SAAgB,SACd,MACA,UACA,QACA,sBACA;CACA,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;CACzD,IAAI,CAAC,QACH,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,IAAI,IAAI,KAAK,WACpB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAsB;CAExD,MAAM,YAAY,OAAO,KAAK,WAAW,MAAM,EAAE,OAAO,MAAM;CAC9D,IAAI,cAAc,IAChB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAe;CAEjD,MAAM,cAAc,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM;CACzD,MAAM,aAAa,uBACf,YAAY,aACZ,OAAO;CACX,MAAM,OAAO,OAAO,KAAK;CACzB,IAAI,CAAC,eAAe,MAAM,UAAU,GAClC,OAAO;EAAE,SAAS;EAAO,OAAO;CAAkB;CAGpD,KAAK,YAAY,KAAK,IAAI,IAAI;CAC9B,UAAU,MAAM;EAAE,MAAM;EAAqB,WAAW,KAAK;CAAU,CAAC;CAExE,OAAO,KAAK,OAAO,WAAW,CAAC;CAC/B,WAAW,KAAK,IAAI;CACpB,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB;EACA;CACF,CAAC;CAED,IAAI,YAAY,sBAAsB,gBAAgB,aAAa,IAAI,GACrE,YAAY,qBAAqB;CAGnC,IAAI,OAAO,KAAK,WAAW,KAAK,OAAO,SAAS,WAAW,GAAG;EAC5D,UAAU,MAAM,EAAE,MAAM,gBAAgB,CAAC;EAKzC,OAAO;GAAE,SAAS;GAAM,MAAM;IAH5B,GAAG;IACH,QAAQ;GAEgC;EAAE;CAC9C;CAEA,OAAO;EAAE,SAAS;EAAM;CAAK;AAC/B;;;AC3DA,SAAgB,aAA6B,OAAkB;CAC7D,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,IAAI,GAAG,KAAK;EACzC,MAAM,IAAI,KAAK,MAAM,KAAK,OAAO,KAAK,IAAI,EAAE;EAC5C,CAAC,MAAM,IAAI,MAAM,MAAM,CAAC,MAAM,IAAK,MAAM,EAAG;CAC9C;AACF;;;ACGA,SAAgB,sBAAsB,MAAY,UAAkB;CAClE,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;CACzD,IAAI,CAAC,QACH,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,IAAI,IAAI,KAAK,WACpB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAsB;CAExD,IAAI,OAAO,oBACT,OAAO;EAAE,SAAS;EAAO,OAAO;CAAkB;CAEpD,IAAI,gBAAgB,QAAQ,IAAI,GAC9B,OAAO;EAAE,SAAS;EAAO,OAAO;CAAkB;CAEpD,IAAI,OAAO,SAAS,SAAS,KAAK,OAAO,KAAK,SAAA,GAC5C,OAAO;EAAE,SAAS;EAAO,OAAO;CAAU;CAG5C,KAAK,YAAY,KAAK,IAAI,IAAI;CAC9B,UAAU,MAAM;EAAE,MAAM;EAAqB,WAAW,KAAK;CAAU,CAAC;CAExE,OAAO,qBAAqB;CAE5B,MAAM,cAAc,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM;CACzD,IAAI,YAAY,oBAAoB;EAClC,IAAI,OAAO,SAAS,WAAW,KAAK,YAAY,SAAS,WAAW,GAAG;GACrE,MAAM,QAAQ,CAAC,GAAG,OAAO,YAAY,GAAG,YAAY,UAAU;GAC9D,aAAa,KAAK;GAClB,OAAO,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;GAC1C,UAAU,MAAM;IACd,MAAM;IACN,UAAU,OAAO;IACjB,UAAU,OAAO,SAAS;GAC5B,CAAC;GACD,OAAO,WAAW,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;GAC5C,UAAU,MAAM;IACd,MAAM;IACN,UAAU,OAAO;IACjB,MAAM,OAAO,WAAW,OAAO,WAAW,SAAS;GACrD,CAAC;GACD,YAAY,WAAW,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;GACjD,UAAU,MAAM;IACd,MAAM;IACN,UAAU,YAAY;IACtB,MAAM,YAAY,WAAW,YAAY,WAAW,SAAS;GAC/D,CAAC;GACD,YAAY,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;GAC/C,UAAU,MAAM;IACd,MAAM;IACN,UAAU,YAAY;IACtB,UAAU,YAAY,SAAS;GACjC,CAAC;EACH,OAAO;GACL,MAAM,qBAAqB,OAAO,SAAS,IAAI;GAC/C,OAAO,WAAW,KAAK,kBAAkB;GACzC,UAAU,MAAM;IACd,MAAM;IACN,UAAU,OAAO;IACjB,MAAM;GACR,CAAC;GACD,MAAM,0BAA0B,YAAY,SAAS,IAAI;GACzD,YAAY,WAAW,KAAK,uBAAuB;GACnD,UAAU,MAAM;IACd,MAAM;IACN,UAAU,YAAY;IACtB,MAAM;GACR,CAAC;EACH;EACA,OAAO,qBAAqB;EAC5B,YAAY,qBAAqB;EACjC,KAAK,YAAY,KAAK,IAAI,IAAI;EAC9B,UAAU,MAAM;GACd,MAAM;GACN,WAAW,KAAK;EAClB,CAAC;CACH;CAEA,OAAO;EAAE,SAAS;EAAM;CAAK;AAC/B;;;AChFA,SAAgB,UAAU,MAAY,UAAkB;CACtD,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;CACzD,IAAI,CAAC,QACH,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,QAAQ,QAAQ,MAAM,MAAM,GACnC,OAAO;EAAE,SAAS;EAAO,OAAO;CAAiB;CAEnD,IAAI,KAAK,WAAW,WAClB,OAAO;EAAE,SAAS;EAAO,OAAO;CAAgB;CAElD,IAAI,KAAK,QAAQ,SAAA,GACf,OAAO;EAAE,SAAS;EAAO,OAAO;CAAuB;CAEzD,MAAM,cAAc,KAAK,QAAQ;CACjC,MAAM,QAAQ,CAAC,GAAG,KAAK;CACvB,aAAa,KAAK;CAElB,OAAO,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CAC1C,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB,UAAU,OAAO,SAAS;CAC5B,CAAC;CAED,OAAO,WAAW,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CAC5C,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB,MAAM,OAAO,WAAW,OAAO,WAAW,SAAS;CACrD,CAAC;CAED,YAAY,WAAW,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CACjD,UAAU,MAAM;EACd,MAAM;EACN,UAAU,YAAY;EACtB,MAAM,YAAY,WAAW,YAAY,WAAW,SAAS;CAC/D,CAAC;CAED,YAAY,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CAC/C,UAAU,MAAM;EACd,MAAM;EACN,UAAU,YAAY;EACtB,UAAU,YAAY,SAAS;CACjC,CAAC;CAED,OAAO,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,EAAE,CAAC;CAC3C,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB,UAAU,OAAO,SAAS;CAC5B,CAAC;CAED,OAAO,KAAK,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CACtC,kBAAkB,QAAQ;EAAE,MAAM;EAAmB,OAAO,OAAO;CAAK,CAAC;CACzE,UAAU,MAAM;EACd,MAAM;EACN,UAAU,OAAO;EACjB,UAAU,OAAO,KAAK;CACxB,CAAC;CAED,YAAY,SAAS,KAAK,GAAG,MAAM,OAAO,GAAG,EAAE,CAAC;CAChD,UAAU,MAAM;EACd,MAAM;EACN,UAAU,YAAY;EACtB,UAAU,YAAY,SAAS;CACjC,CAAC;CAED,YAAY,KAAK,KAAK,GAAG,MAAM,OAAO,GAAG,CAAC,CAAC;CAC3C,kBAAkB,aAAa;EAC7B,MAAM;EACN,OAAO,YAAY;CACrB,CAAC;CACD,UAAU,MAAM;EACd,MAAM;EACN,UAAU,YAAY;EACtB,UAAU,YAAY,KAAK;CAC7B,CAAC;CAED,MAAM,cAA2B;EAC/B,GAAG;EACH,QAAQ;EACR,WAAW,KAAK,IAAI,IAAI;EACxB,WAAW,KAAK,IAAI,IAAI;CAC1B;CAEA,UAAU,aAAa,EAAE,MAAM,cAAc,CAAC;CAC9C,UAAU,aAAa;EACrB,MAAM;EACN,WAAW,YAAY;CACzB,CAAC;CACD,UAAU,aAAa;EACrB,MAAM;EACN,WAAW,YAAY;CACzB,CAAC;CACD,OAAO;EAAE,SAAS;EAAM,MAAM;CAAY;AAC5C;;;AC5FA,MAAa,iBAAA,GAAgBC,oBAAAA,qBAAAA,CAAqB;CAChD,YAAA;CACA;CACA;CACA,+BAAA,oBAAA;CACA;CACA;CACA,UAAA,oBAAA;CACA;CACA,mBAAmB,gBAAgB;EACjC,UAAU,WAAW,QAAQ;EAC7B,UAAU,WAAW,QAAQ;EAC7B,uBAAuB,WAAW,qBAAqB;CACzD;AACF,CAAC"}
1
+ {"version":3,"file":"manager-DdpdgNfz.cjs","names":["getClientStateAndClearEventsFactory","createManagerFactory"],"sources":["../src/game/constants.ts","../src/game/actions/createGame.ts","../src/game/lib/emitEvent.ts","../src/game/lib/emitEventToPlayer.ts","../src/game/actions/drawCard.ts","../src/game/actions/getClientStateAndClearEvents.ts","../src/game/actions/joinGame.ts","../src/game/actions/leaveGame.ts","../src/game/lib/isCardPlayable.ts","../src/game/lib/hasPlayableCard.ts","../src/game/actions/playCard.ts","../src/game/lib/shuffleCards.ts","../src/game/actions/reportNoPlayableCards.ts","../src/game/actions/startGame.ts","../src/manager/createManager.ts"],"sourcesContent":["import type { Card } from \"./types/Card.js\";\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 { EXPIRY_EXTENSION_MS } from \"../constants.js\";\nimport type { CreatedGame } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function createGame(userId: string, username: string) {\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\n const createdAt = Date.now();\n\n const game: CreatedGame = {\n status: \"created\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n };\n\n return { game, playerId: player.id } as const;\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 type { Game } from \"../types/Game.js\";\n\nexport function drawCard(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" } as const;\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" } as const;\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, game } as const;\n}\n","import { getClientStateAndClearEventsFactory } from \"@hellacardgames/lib\";\nimport type { ClientState } from \"../types/ClientState.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport const getClientStateAndClearEvents = getClientStateAndClearEventsFactory<\n Game,\n ClientState\n>((game, player) => ({\n status: game.status,\n gameId: game.id,\n playerId: player.id,\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","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { MAX_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\nimport type { Player } from \"../types/Player.js\";\n\nexport function joinGame(game: Game, userId: string, username: string) {\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" } as const;\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" } as const;\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, game, playerId: player.id } as const;\n}\n","import { emitEvent } from \"../lib/emitEvent.js\";\nimport { EXPIRY_EXTENSION_MS, MIN_PLAYERS } from \"../constants.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function leaveGame(game: Game, playerId: string) {\n const playerIndex = game.players.findIndex((p) => p.id === playerId);\n if (playerIndex === -1) {\n return { success: false, error: \"playerNotFound\" } as const;\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 // this.games.set(game.id, forfeitedGame);\n emitEvent(forfeitedGame, { type: \"gameForfeited\" });\n emitEvent(forfeitedGame, {\n type: \"expirationUpdated\",\n expiresAt: forfeitedGame.expiresAt,\n });\n return { success: true, game: forfeitedGame } as const;\n }\n return { success: true, game } as const;\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 { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport { isCardPlayable } from \"../lib/isCardPlayable.js\";\nimport type { CompletedGame, Game } from \"../types/Game.js\";\n\nexport function playCard(\n game: Game,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n const cardIndex = player.hand.findIndex((c) => c.id === cardId);\n if (cardIndex === -1) {\n return { success: false, error: \"cardNotFound\" } as const;\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\" } as const;\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: CompletedGame = {\n ...game,\n status: \"completed\",\n };\n return { success: true, game: completedGame } as const;\n }\n\n return { success: true, game } as const;\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 { hasPlayableCard } from \"../lib/hasPlayableCard.js\";\nimport type { Game } from \"../types/Game.js\";\n\nexport function reportNoPlayableCards(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" } as const;\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" } as const;\n }\n if (hasPlayableCard(player, game)) {\n return { success: false, error: \"hasPlayableCard\" } as const;\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" } as const;\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, game } as const;\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 type { Game, StartedGame } from \"../types/Game.js\";\n\nexport function startGame(game: Game, playerId: string) {\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" } as const;\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" } as const;\n }\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" } as const;\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" } as const;\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: StartedGame = {\n ...game,\n status: \"started\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS,\n };\n // this.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, game: startedGame } as const;\n}\n","import { createManagerFactory } from \"@hellacardgames/lib\";\nimport {\n createGame,\n drawCard,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n MAX_PLAYERS,\n playCard,\n reportNoPlayableCards,\n sendChat,\n startGame,\n} from \"../game/index.js\";\n\nexport const createManager = createManagerFactory({\n maxPlayers: MAX_PLAYERS,\n createGame,\n getClientStateAndClearEvents,\n getEventsAndClearAcknowledged,\n joinGame,\n leaveGame,\n sendChat,\n startGame,\n gameplayActions: {\n drawCard,\n playCard,\n reportNoPlayableCards,\n },\n});\n"],"mappings":"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"}
@@ -1,22 +1,14 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_manager = require("../manager-BI5b7WMo.cjs");
2
+ const require_manager = require("../manager-DdpdgNfz.cjs");
3
3
  let _hellacardgames_lib = require("@hellacardgames/lib");
4
4
  let zod = require("zod");
5
5
  //#region src/server/createServer.ts
6
- const createServer = (0, _hellacardgames_lib.createServerFactory)(require_manager.createManager, (manager) => {
7
- const drawCardInputSchema = zod.z.object({
6
+ const createServer = (0, _hellacardgames_lib.createServerFactory)(require_manager.createManager, {
7
+ drawCard: zod.z.object({
8
8
  gameId: zod.z.string(),
9
9
  playerId: zod.z.string()
10
- }).transform(({ gameId, playerId }) => [gameId, playerId]);
11
- function drawCard(input) {
12
- const parseResult = drawCardInputSchema.safeParse(input);
13
- if (!parseResult.success) return {
14
- success: false,
15
- error: "invalidInput"
16
- };
17
- return manager.drawCard(...parseResult.data);
18
- }
19
- const playCardInputSchema = zod.z.object({
10
+ }).transform(({ gameId, playerId }) => [gameId, playerId]),
11
+ playCard: zod.z.object({
20
12
  gameId: zod.z.string(),
21
13
  playerId: zod.z.string(),
22
14
  cardId: zod.z.string(),
@@ -26,41 +18,11 @@ const createServer = (0, _hellacardgames_lib.createServerFactory)(require_manage
26
18
  playerId,
27
19
  cardId,
28
20
  isForOtherPlayerPile
29
- ]);
30
- function playCard(input) {
31
- const parseResult = playCardInputSchema.safeParse(input);
32
- if (!parseResult.success) return {
33
- success: false,
34
- error: "invalidInput"
35
- };
36
- return manager.playCard(...parseResult.data);
37
- }
38
- const reportNoPlayableCardsInputSchema = zod.z.object({
21
+ ]),
22
+ reportNoPlayableCards: zod.z.object({
39
23
  gameId: zod.z.string(),
40
24
  playerId: zod.z.string()
41
- }).transform(({ gameId, playerId }) => [gameId, playerId]);
42
- function reportNoPlayableCards(input) {
43
- const parseResult = reportNoPlayableCardsInputSchema.safeParse(input);
44
- if (!parseResult.success) return {
45
- success: false,
46
- error: "invalidInput"
47
- };
48
- return manager.reportNoPlayableCards(...parseResult.data);
49
- }
50
- return [
51
- {
52
- path: "/drawCard",
53
- action: drawCard
54
- },
55
- {
56
- path: "/playCard",
57
- action: playCard
58
- },
59
- {
60
- path: "/reportNoPlayableCards",
61
- action: reportNoPlayableCards
62
- }
63
- ];
25
+ }).transform(({ gameId, playerId }) => [gameId, playerId])
64
26
  });
65
27
  //#endregion
66
28
  exports.createServer = createServer;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["createServerFactory","createManager","z"],"sources":["../../src/server/createServer.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { createServerFactory } from \"@hellacardgames/lib\";\nimport { createManager } from \"../manager/index.js\";\n\nexport const createServer = createServerFactory(createManager, (manager) => {\n const drawCardInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\n function drawCard(input: unknown) {\n const parseResult = drawCardInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" } as const;\n }\n return manager.drawCard(...parseResult.data);\n }\n\n const playCardInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n cardId: z.string(),\n isForOtherPlayerPile: z.boolean(),\n })\n .transform(\n ({ gameId, playerId, cardId, isForOtherPlayerPile }) =>\n [gameId, playerId, cardId, isForOtherPlayerPile] as const,\n );\n\n function playCard(input: unknown) {\n const parseResult = playCardInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" } as const;\n }\n return manager.playCard(...parseResult.data);\n }\n\n const reportNoPlayableCardsInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\n function reportNoPlayableCards(input: unknown) {\n const parseResult = reportNoPlayableCardsInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" } as const;\n }\n return manager.reportNoPlayableCards(...parseResult.data);\n }\n\n return [\n { path: \"/drawCard\", action: drawCard },\n { path: \"/playCard\", action: playCard },\n { path: \"/reportNoPlayableCards\", action: reportNoPlayableCards },\n ];\n});\n"],"mappings":";;;;;AAIA,MAAa,gBAAA,GAAeA,oBAAAA,oBAAAA,CAAoBC,gBAAAA,gBAAgB,YAAY;CAC1E,MAAM,sBAAsBC,IAAAA,EACzB,OAAO;EACN,QAAQA,IAAAA,EAAE,OAAO;EACjB,UAAUA,IAAAA,EAAE,OAAO;CACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;CAElE,SAAS,SAAS,OAAgB;EAChC,MAAM,cAAc,oBAAoB,UAAU,KAAK;EACvD,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,QAAQ,SAAS,GAAG,YAAY,IAAI;CAC7C;CAEA,MAAM,sBAAsBA,IAAAA,EACzB,OAAO;EACN,QAAQA,IAAAA,EAAE,OAAO;EACjB,UAAUA,IAAAA,EAAE,OAAO;EACnB,QAAQA,IAAAA,EAAE,OAAO;EACjB,sBAAsBA,IAAAA,EAAE,QAAQ;CAClC,CAAC,CAAC,CACD,WACE,EAAE,QAAQ,UAAU,QAAQ,2BAC3B;EAAC;EAAQ;EAAU;EAAQ;CAAoB,CACnD;CAEF,SAAS,SAAS,OAAgB;EAChC,MAAM,cAAc,oBAAoB,UAAU,KAAK;EACvD,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,QAAQ,SAAS,GAAG,YAAY,IAAI;CAC7C;CAEA,MAAM,mCAAmCA,IAAAA,EACtC,OAAO;EACN,QAAQA,IAAAA,EAAE,OAAO;EACjB,UAAUA,IAAAA,EAAE,OAAO;CACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;CAElE,SAAS,sBAAsB,OAAgB;EAC7C,MAAM,cAAc,iCAAiC,UAAU,KAAK;EACpE,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,QAAQ,sBAAsB,GAAG,YAAY,IAAI;CAC1D;CAEA,OAAO;EACL;GAAE,MAAM;GAAa,QAAQ;EAAS;EACtC;GAAE,MAAM;GAAa,QAAQ;EAAS;EACtC;GAAE,MAAM;GAA0B,QAAQ;EAAsB;CAClE;AACF,CAAC"}
1
+ {"version":3,"file":"index.cjs","names":["createServerFactory","createManager","z"],"sources":["../../src/server/createServer.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { createServerFactory } from \"@hellacardgames/lib\";\nimport { createManager } from \"../manager/index.js\";\n\nexport const createServer = createServerFactory(createManager, {\n drawCard: z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const),\n\n playCard: z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n cardId: z.string(),\n isForOtherPlayerPile: z.boolean(),\n })\n .transform(\n ({ gameId, playerId, cardId, isForOtherPlayerPile }) =>\n [gameId, playerId, cardId, isForOtherPlayerPile] as const,\n ),\n\n reportNoPlayableCards: z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const),\n});\n"],"mappings":";;;;;AAIA,MAAa,gBAAA,GAAeA,oBAAAA,oBAAAA,CAAoBC,gBAAAA,eAAe;CAC7D,UAAUC,IAAAA,EACP,OAAO;EACN,QAAQA,IAAAA,EAAE,OAAO;EACjB,UAAUA,IAAAA,EAAE,OAAO;CACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;CAElE,UAAUA,IAAAA,EACP,OAAO;EACN,QAAQA,IAAAA,EAAE,OAAO;EACjB,UAAUA,IAAAA,EAAE,OAAO;EACnB,QAAQA,IAAAA,EAAE,OAAO;EACjB,sBAAsBA,IAAAA,EAAE,QAAQ;CAClC,CAAC,CAAC,CACD,WACE,EAAE,QAAQ,UAAU,QAAQ,2BAC3B;EAAC;EAAQ;EAAU;EAAQ;CAAoB,CACnD;CAEF,uBAAuBA,IAAAA,EACpB,OAAO;EACN,QAAQA,IAAAA,EAAE,OAAO;EACjB,UAAUA,IAAAA,EAAE,OAAO;CACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;AACpE,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { n as GameEvent, t as ClientState } from "../index-89KVb2dD.cjs";
2
2
  //#region src/server/createServer.d.ts
3
3
  declare const createServer: (logKey: string, maxGames: number, watchdogIntervalMs: number) => {
4
- readonly actions: readonly [{
4
+ readonly routes: readonly [{
5
5
  readonly path: "/createGame";
6
6
  readonly action: (userId: string, username: string) => {
7
7
  readonly success: true;
@@ -88,52 +88,31 @@ declare const createServer: (logKey: string, maxGames: number, watchdogIntervalM
88
88
  readonly success: false;
89
89
  readonly error: "playerNotFound" | "invalidStatus" | "playerNotAdmin" | "minPlayersNotReached" | "gameNotFound";
90
90
  };
91
- }, {
91
+ }, ...({
92
92
  readonly path: "/drawCard";
93
93
  readonly action: (input: unknown) => {
94
- readonly success: false;
95
- readonly error: "gameNotFound";
96
- } | {
97
94
  readonly success: true;
98
- readonly error?: never;
99
- } | {
100
- readonly success: false;
101
- readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "handFull" | "drawPileEmpty";
102
95
  } | {
103
96
  readonly success: false;
104
- readonly error: "invalidInput";
97
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "handFull" | "drawPileEmpty" | "gameNotFound" | "invalidInput";
105
98
  };
106
- }, {
99
+ } | {
107
100
  readonly path: "/playCard";
108
101
  readonly action: (input: unknown) => {
109
- readonly success: false;
110
- readonly error: "gameNotFound";
111
- } | {
112
102
  readonly success: true;
113
- readonly error?: never;
114
103
  } | {
115
104
  readonly success: false;
116
- readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "cardNotFound" | "cardNotPlayable";
117
- } | {
118
- readonly success: false;
119
- readonly error: "invalidInput";
105
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "cardNotFound" | "cardNotPlayable" | "gameNotFound" | "invalidInput";
120
106
  };
121
- }, {
107
+ } | {
122
108
  readonly path: "/reportNoPlayableCards";
123
109
  readonly action: (input: unknown) => {
124
- readonly success: false;
125
- readonly error: "gameNotFound";
126
- } | {
127
110
  readonly success: true;
128
- readonly error?: never;
129
- } | {
130
- readonly success: false;
131
- readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "alreadyReported" | "hasPlayableCard" | "canDraw";
132
111
  } | {
133
112
  readonly success: false;
134
- readonly error: "invalidInput";
113
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "alreadyReported" | "hasPlayableCard" | "canDraw" | "gameNotFound" | "invalidInput";
135
114
  };
136
- }];
115
+ })[]];
137
116
  };
138
117
  //#endregion
139
118
  export { createServer };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/server/createServer.ts"],"mappings":";;cAIa,eAAY,gBAAA,kBAAA;;;;;;;;;;;;;;;;;;sBAAZ;;;;;;;;;;;;gCAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAQc,SAAA;;;;;;;;;;;;;;;aAoBA,SAAA;;;;;;;;;;;;;;;aAea,SAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/server/createServer.ts"],"mappings":";;cAIa,eAAY,gBAAA,kBAAA;;;;;;;;;;;;;;;;;;sBAAZ;;;;;;;;;;;;gCAAA"}
@@ -1,7 +1,7 @@
1
1
  import { n as GameEvent, t as ClientState } from "../index-89KVb2dD.mjs";
2
2
  //#region src/server/createServer.d.ts
3
3
  declare const createServer: (logKey: string, maxGames: number, watchdogIntervalMs: number) => {
4
- readonly actions: readonly [{
4
+ readonly routes: readonly [{
5
5
  readonly path: "/createGame";
6
6
  readonly action: (userId: string, username: string) => {
7
7
  readonly success: true;
@@ -88,52 +88,31 @@ declare const createServer: (logKey: string, maxGames: number, watchdogIntervalM
88
88
  readonly success: false;
89
89
  readonly error: "playerNotFound" | "invalidStatus" | "playerNotAdmin" | "minPlayersNotReached" | "gameNotFound";
90
90
  };
91
- }, {
91
+ }, ...({
92
92
  readonly path: "/drawCard";
93
93
  readonly action: (input: unknown) => {
94
- readonly success: false;
95
- readonly error: "gameNotFound";
96
- } | {
97
94
  readonly success: true;
98
- readonly error?: never;
99
- } | {
100
- readonly success: false;
101
- readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "handFull" | "drawPileEmpty";
102
95
  } | {
103
96
  readonly success: false;
104
- readonly error: "invalidInput";
97
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "handFull" | "drawPileEmpty" | "gameNotFound" | "invalidInput";
105
98
  };
106
- }, {
99
+ } | {
107
100
  readonly path: "/playCard";
108
101
  readonly action: (input: unknown) => {
109
- readonly success: false;
110
- readonly error: "gameNotFound";
111
- } | {
112
102
  readonly success: true;
113
- readonly error?: never;
114
103
  } | {
115
104
  readonly success: false;
116
- readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "cardNotFound" | "cardNotPlayable";
117
- } | {
118
- readonly success: false;
119
- readonly error: "invalidInput";
105
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "cardNotFound" | "cardNotPlayable" | "gameNotFound" | "invalidInput";
120
106
  };
121
- }, {
107
+ } | {
122
108
  readonly path: "/reportNoPlayableCards";
123
109
  readonly action: (input: unknown) => {
124
- readonly success: false;
125
- readonly error: "gameNotFound";
126
- } | {
127
110
  readonly success: true;
128
- readonly error?: never;
129
- } | {
130
- readonly success: false;
131
- readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "alreadyReported" | "hasPlayableCard" | "canDraw";
132
111
  } | {
133
112
  readonly success: false;
134
- readonly error: "invalidInput";
113
+ readonly error: "playerNotFound" | "invalidStatus" | "canPlayAtNotReached" | "alreadyReported" | "hasPlayableCard" | "canDraw" | "gameNotFound" | "invalidInput";
135
114
  };
136
- }];
115
+ })[]];
137
116
  };
138
117
  //#endregion
139
118
  export { createServer };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/server/createServer.ts"],"mappings":";;cAIa,eAAY,gBAAA,kBAAA;;;;;;;;;;;;;;;;;;sBAAZ;;;;;;;;;;;;gCAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAQc,SAAA;;;;;;;;;;;;;;;aAoBA,SAAA;;;;;;;;;;;;;;;aAea,SAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/server/createServer.ts"],"mappings":";;cAIa,eAAY,gBAAA,kBAAA;;;;;;;;;;;;;;;;;;sBAAZ;;;;;;;;;;;;gCAAA"}
@@ -1,21 +1,13 @@
1
- import { t as createManager } from "../manager-D7K5YYcq.mjs";
1
+ import { t as createManager } from "../manager-C8wqbmrE.mjs";
2
2
  import { createServerFactory } from "@hellacardgames/lib";
3
3
  import { z } from "zod";
4
4
  //#region src/server/createServer.ts
5
- const createServer = createServerFactory(createManager, (manager) => {
6
- const drawCardInputSchema = z.object({
5
+ const createServer = createServerFactory(createManager, {
6
+ drawCard: z.object({
7
7
  gameId: z.string(),
8
8
  playerId: z.string()
9
- }).transform(({ gameId, playerId }) => [gameId, playerId]);
10
- function drawCard(input) {
11
- const parseResult = drawCardInputSchema.safeParse(input);
12
- if (!parseResult.success) return {
13
- success: false,
14
- error: "invalidInput"
15
- };
16
- return manager.drawCard(...parseResult.data);
17
- }
18
- const playCardInputSchema = z.object({
9
+ }).transform(({ gameId, playerId }) => [gameId, playerId]),
10
+ playCard: z.object({
19
11
  gameId: z.string(),
20
12
  playerId: z.string(),
21
13
  cardId: z.string(),
@@ -25,41 +17,11 @@ const createServer = createServerFactory(createManager, (manager) => {
25
17
  playerId,
26
18
  cardId,
27
19
  isForOtherPlayerPile
28
- ]);
29
- function playCard(input) {
30
- const parseResult = playCardInputSchema.safeParse(input);
31
- if (!parseResult.success) return {
32
- success: false,
33
- error: "invalidInput"
34
- };
35
- return manager.playCard(...parseResult.data);
36
- }
37
- const reportNoPlayableCardsInputSchema = z.object({
20
+ ]),
21
+ reportNoPlayableCards: z.object({
38
22
  gameId: z.string(),
39
23
  playerId: z.string()
40
- }).transform(({ gameId, playerId }) => [gameId, playerId]);
41
- function reportNoPlayableCards(input) {
42
- const parseResult = reportNoPlayableCardsInputSchema.safeParse(input);
43
- if (!parseResult.success) return {
44
- success: false,
45
- error: "invalidInput"
46
- };
47
- return manager.reportNoPlayableCards(...parseResult.data);
48
- }
49
- return [
50
- {
51
- path: "/drawCard",
52
- action: drawCard
53
- },
54
- {
55
- path: "/playCard",
56
- action: playCard
57
- },
58
- {
59
- path: "/reportNoPlayableCards",
60
- action: reportNoPlayableCards
61
- }
62
- ];
24
+ }).transform(({ gameId, playerId }) => [gameId, playerId])
63
25
  });
64
26
  //#endregion
65
27
  export { createServer };
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/server/createServer.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { createServerFactory } from \"@hellacardgames/lib\";\nimport { createManager } from \"../manager/index.js\";\n\nexport const createServer = createServerFactory(createManager, (manager) => {\n const drawCardInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\n function drawCard(input: unknown) {\n const parseResult = drawCardInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" } as const;\n }\n return manager.drawCard(...parseResult.data);\n }\n\n const playCardInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n cardId: z.string(),\n isForOtherPlayerPile: z.boolean(),\n })\n .transform(\n ({ gameId, playerId, cardId, isForOtherPlayerPile }) =>\n [gameId, playerId, cardId, isForOtherPlayerPile] as const,\n );\n\n function playCard(input: unknown) {\n const parseResult = playCardInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" } as const;\n }\n return manager.playCard(...parseResult.data);\n }\n\n const reportNoPlayableCardsInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\n function reportNoPlayableCards(input: unknown) {\n const parseResult = reportNoPlayableCardsInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" } as const;\n }\n return manager.reportNoPlayableCards(...parseResult.data);\n }\n\n return [\n { path: \"/drawCard\", action: drawCard },\n { path: \"/playCard\", action: playCard },\n { path: \"/reportNoPlayableCards\", action: reportNoPlayableCards },\n ];\n});\n"],"mappings":";;;;AAIA,MAAa,eAAe,oBAAoB,gBAAgB,YAAY;CAC1E,MAAM,sBAAsB,EACzB,OAAO;EACN,QAAQ,EAAE,OAAO;EACjB,UAAU,EAAE,OAAO;CACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;CAElE,SAAS,SAAS,OAAgB;EAChC,MAAM,cAAc,oBAAoB,UAAU,KAAK;EACvD,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,QAAQ,SAAS,GAAG,YAAY,IAAI;CAC7C;CAEA,MAAM,sBAAsB,EACzB,OAAO;EACN,QAAQ,EAAE,OAAO;EACjB,UAAU,EAAE,OAAO;EACnB,QAAQ,EAAE,OAAO;EACjB,sBAAsB,EAAE,QAAQ;CAClC,CAAC,CAAC,CACD,WACE,EAAE,QAAQ,UAAU,QAAQ,2BAC3B;EAAC;EAAQ;EAAU;EAAQ;CAAoB,CACnD;CAEF,SAAS,SAAS,OAAgB;EAChC,MAAM,cAAc,oBAAoB,UAAU,KAAK;EACvD,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,QAAQ,SAAS,GAAG,YAAY,IAAI;CAC7C;CAEA,MAAM,mCAAmC,EACtC,OAAO;EACN,QAAQ,EAAE,OAAO;EACjB,UAAU,EAAE,OAAO;CACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;CAElE,SAAS,sBAAsB,OAAgB;EAC7C,MAAM,cAAc,iCAAiC,UAAU,KAAK;EACpE,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,QAAQ,sBAAsB,GAAG,YAAY,IAAI;CAC1D;CAEA,OAAO;EACL;GAAE,MAAM;GAAa,QAAQ;EAAS;EACtC;GAAE,MAAM;GAAa,QAAQ;EAAS;EACtC;GAAE,MAAM;GAA0B,QAAQ;EAAsB;CAClE;AACF,CAAC"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/server/createServer.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { createServerFactory } from \"@hellacardgames/lib\";\nimport { createManager } from \"../manager/index.js\";\n\nexport const createServer = createServerFactory(createManager, {\n drawCard: z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const),\n\n playCard: z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n cardId: z.string(),\n isForOtherPlayerPile: z.boolean(),\n })\n .transform(\n ({ gameId, playerId, cardId, isForOtherPlayerPile }) =>\n [gameId, playerId, cardId, isForOtherPlayerPile] as const,\n ),\n\n reportNoPlayableCards: z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const),\n});\n"],"mappings":";;;;AAIA,MAAa,eAAe,oBAAoB,eAAe;CAC7D,UAAU,EACP,OAAO;EACN,QAAQ,EAAE,OAAO;EACjB,UAAU,EAAE,OAAO;CACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;CAElE,UAAU,EACP,OAAO;EACN,QAAQ,EAAE,OAAO;EACjB,UAAU,EAAE,OAAO;EACnB,QAAQ,EAAE,OAAO;EACjB,sBAAsB,EAAE,QAAQ;CAClC,CAAC,CAAC,CACD,WACE,EAAE,QAAQ,UAAU,QAAQ,2BAC3B;EAAC;EAAQ;EAAU;EAAQ;CAAoB,CACnD;CAEF,uBAAuB,EACpB,OAAO;EACN,QAAQ,EAAE,OAAO;EACjB,UAAU,EAAE,OAAO;CACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;AACpE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hellacardgames/speed",
3
- "version": "0.11.2",
3
+ "version": "0.12.0",
4
4
  "description": "A TypeScript library implementing the Speed card game.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -86,7 +86,7 @@
86
86
  "vitest": "^4.1.9"
87
87
  },
88
88
  "dependencies": {
89
- "@hellacardgames/lib": "^0.14.0",
89
+ "@hellacardgames/lib": "^0.16.0",
90
90
  "zod": "^4.4.3"
91
91
  }
92
92
  }