@hellacardgames/speed 0.6.0 → 0.8.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.
- package/dist/client/index.d.cts +2 -2
- package/dist/client/index.d.mts +2 -2
- package/dist/{index-FveApXzq.d.cts → index-C5bT1Zzd.d.mts} +3 -2
- package/dist/{index-FveApXzq.d.cts.map → index-C5bT1Zzd.d.mts.map} +1 -1
- package/dist/{index-J8s2QklC.d.mts → index-NySusLtY.d.cts} +3 -2
- package/dist/{index-J8s2QklC.d.mts.map → index-NySusLtY.d.cts.map} +1 -1
- package/dist/{index-YAYbNr-s.d.cts → index-uaOvIhKT.d.cts} +55 -8
- package/dist/index-uaOvIhKT.d.cts.map +1 -0
- package/dist/{index-YAYbNr-s.d.mts → index-uaOvIhKT.d.mts} +55 -8
- package/dist/index-uaOvIhKT.d.mts.map +1 -0
- package/dist/manager/index.cjs +1 -1
- package/dist/manager/index.d.cts +1 -1
- package/dist/manager/index.d.mts +1 -1
- package/dist/manager/index.mjs +1 -1
- package/dist/{manager-BOymBQ4E.mjs → manager-BAxBCUOk.mjs} +8 -35
- package/dist/manager-BAxBCUOk.mjs.map +1 -0
- package/dist/{manager-BpKvQbcp.cjs → manager-C9oZYA47.cjs} +8 -35
- package/dist/manager-C9oZYA47.cjs.map +1 -0
- package/dist/server/index.cjs +5 -2
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +2 -2
- package/dist/server/index.d.mts +2 -2
- package/dist/server/index.mjs +5 -2
- package/dist/server/index.mjs.map +1 -1
- package/package.json +2 -2
- package/dist/index-YAYbNr-s.d.cts.map +0 -1
- package/dist/index-YAYbNr-s.d.mts.map +0 -1
- package/dist/manager-BOymBQ4E.mjs.map +0 -1
- package/dist/manager-BpKvQbcp.cjs.map +0 -1
package/dist/client/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { g as Card, h as ChatMessage, m as ClientState, p as GameEvent } from "../index-
|
|
2
|
-
import { a as GetJoinableGamesResult, c as PlayCardResult, f as StartGameResult, i as GetEventsAndClearAcknowledgedResult, l as ReportNoPlayableCardsResult, n as DrawCardResult, o as JoinGameResult, r as GetClientStateAndClearEventsResult, s as LeaveGameResult, t as CreateGameResult, u as SendChatResult } from "../index-
|
|
1
|
+
import { g as Card, h as ChatMessage, m as ClientState, p as GameEvent } from "../index-uaOvIhKT.cjs";
|
|
2
|
+
import { a as GetJoinableGamesResult, c as PlayCardResult, f as StartGameResult, i as GetEventsAndClearAcknowledgedResult, l as ReportNoPlayableCardsResult, n as DrawCardResult, o as JoinGameResult, r as GetClientStateAndClearEventsResult, s as LeaveGameResult, t as CreateGameResult, u as SendChatResult } from "../index-NySusLtY.cjs";
|
|
3
3
|
//#region src/client/Client.d.ts
|
|
4
4
|
declare class Client {
|
|
5
5
|
private readonly baseUrl;
|
package/dist/client/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { g as Card, h as ChatMessage, m as ClientState, p as GameEvent } from "../index-
|
|
2
|
-
import { a as GetJoinableGamesResult, c as PlayCardResult, f as StartGameResult, i as GetEventsAndClearAcknowledgedResult, l as ReportNoPlayableCardsResult, n as DrawCardResult, o as JoinGameResult, r as GetClientStateAndClearEventsResult, s as LeaveGameResult, t as CreateGameResult, u as SendChatResult } from "../index-
|
|
1
|
+
import { g as Card, h as ChatMessage, m as ClientState, p as GameEvent } from "../index-uaOvIhKT.mjs";
|
|
2
|
+
import { a as GetJoinableGamesResult, c as PlayCardResult, f as StartGameResult, i as GetEventsAndClearAcknowledgedResult, l as ReportNoPlayableCardsResult, n as DrawCardResult, o as JoinGameResult, r as GetClientStateAndClearEventsResult, s as LeaveGameResult, t as CreateGameResult, u as SendChatResult } from "../index-C5bT1Zzd.mjs";
|
|
3
3
|
//#region src/client/Client.d.ts
|
|
4
4
|
declare class Client {
|
|
5
5
|
private readonly baseUrl;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { m as ClientState, p as GameEvent } from "./index-
|
|
1
|
+
import { c as Manager, m as ClientState, p as GameEvent } from "./index-uaOvIhKT.mjs";
|
|
2
2
|
//#region src/server/Server.d.ts
|
|
3
3
|
type CreateGameResult = {
|
|
4
4
|
readonly success: true;
|
|
@@ -107,6 +107,7 @@ declare class Server {
|
|
|
107
107
|
readonly path: "/startGame";
|
|
108
108
|
readonly action: (input: unknown) => StartGameResult;
|
|
109
109
|
}];
|
|
110
|
+
constructor(...args: ConstructorParameters<typeof Manager>);
|
|
110
111
|
private createGame;
|
|
111
112
|
private drawCard;
|
|
112
113
|
private getClientStateAndClearEvents;
|
|
@@ -121,4 +122,4 @@ declare class Server {
|
|
|
121
122
|
}
|
|
122
123
|
//#endregion
|
|
123
124
|
export { GetJoinableGamesResult as a, PlayCardResult as c, Server as d, StartGameResult as f, GetEventsAndClearAcknowledgedResult as i, ReportNoPlayableCardsResult as l, DrawCardResult as n, JoinGameResult as o, GetClientStateAndClearEventsResult as r, LeaveGameResult as s, CreateGameResult as t, SendChatResult as u };
|
|
124
|
-
//# sourceMappingURL=index-
|
|
125
|
+
//# sourceMappingURL=index-C5bT1Zzd.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-C5bT1Zzd.d.mts","names":[],"sources":["../src/server/Server.ts"],"mappings":";;KAIY;WAEG;WACA;WACA;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;KAUH;WAEG;WACA,OAAO;;WAGP;WACA;;KAGH;WAEG;WACA,iBAAiB;;WAGjB;WACA;;KAGH;WACD;aACE;aACA;;;KAID;WAEG;WACA;;WAGA;WACA;;KAQH;WAEG;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;KAUH;WAEG;;WAGA;WACA;;KAWH;WAEG;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;cAiFF;mBACM;WAER;;aA2BkB,SAAA,gBAAM,qBAAqB;;;aAI9B,SAAA,mBAAU;;;aASzB,SAAA,mBACN;;;aAUM,SAAA,mBACN;;;aASyB,cAAA;;;aAKnB,SAAA,gBAAO,gBACA,qBAEb;;;aAQsB,SAAA,mBAAU;;;aAQX,SAAA,mBAAU;;;aAQG,SAAA,mBAAU;;;aAQvB,SAAA,mBAAU;;;aAQT,SAAA,mBAAU;;EAtFvB,eAAG,MAAM,6BAA6B;UAI1C;UAIA;UAQA;UAWA;UAWA;UAIA;UAYA;UAQA;UAQA;UAQA;UAQA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { m as ClientState, p as GameEvent } from "./index-
|
|
1
|
+
import { c as Manager, m as ClientState, p as GameEvent } from "./index-uaOvIhKT.cjs";
|
|
2
2
|
//#region src/server/Server.d.ts
|
|
3
3
|
type CreateGameResult = {
|
|
4
4
|
readonly success: true;
|
|
@@ -107,6 +107,7 @@ declare class Server {
|
|
|
107
107
|
readonly path: "/startGame";
|
|
108
108
|
readonly action: (input: unknown) => StartGameResult;
|
|
109
109
|
}];
|
|
110
|
+
constructor(...args: ConstructorParameters<typeof Manager>);
|
|
110
111
|
private createGame;
|
|
111
112
|
private drawCard;
|
|
112
113
|
private getClientStateAndClearEvents;
|
|
@@ -121,4 +122,4 @@ declare class Server {
|
|
|
121
122
|
}
|
|
122
123
|
//#endregion
|
|
123
124
|
export { GetJoinableGamesResult as a, PlayCardResult as c, Server as d, StartGameResult as f, GetEventsAndClearAcknowledgedResult as i, ReportNoPlayableCardsResult as l, DrawCardResult as n, JoinGameResult as o, GetClientStateAndClearEventsResult as r, LeaveGameResult as s, CreateGameResult as t, SendChatResult as u };
|
|
124
|
-
//# sourceMappingURL=index-
|
|
125
|
+
//# sourceMappingURL=index-NySusLtY.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-NySusLtY.d.cts","names":[],"sources":["../src/server/Server.ts"],"mappings":";;KAIY;WAEG;WACA;WACA;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;KAUH;WAEG;WACA,OAAO;;WAGP;WACA;;KAGH;WAEG;WACA,iBAAiB;;WAGjB;WACA;;KAGH;WACD;aACE;aACA;;;KAID;WAEG;WACA;;WAGA;WACA;;KAQH;WAEG;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;KAUH;WAEG;;WAGA;WACA;;KAWH;WAEG;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;cAiFF;mBACM;WAER;;aA2BkB,SAAA,gBAAM,qBAAqB;;;aAI9B,SAAA,mBAAU;;;aASzB,SAAA,mBACN;;;aAUM,SAAA,mBACN;;;aASyB,cAAA;;;aAKnB,SAAA,gBAAO,gBACA,qBAEb;;;aAQsB,SAAA,mBAAU;;;aAQX,SAAA,mBAAU;;;aAQG,SAAA,mBAAU;;;aAQvB,SAAA,mBAAU;;;aAQT,SAAA,mBAAU;;EAtFvB,eAAG,MAAM,6BAA6B;UAI1C;UAIA;UAQA;UAWA;UAWA;UAIA;UAYA;UAQA;UAQA;UAQA;UAQA"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ManagerBase } from "@hellacardgames/lib";
|
|
1
2
|
//#region src/manager/types/Card.d.ts
|
|
2
3
|
type Card = {
|
|
3
4
|
readonly id: string;
|
|
@@ -14,17 +15,17 @@ type ChatMessage = {
|
|
|
14
15
|
//#endregion
|
|
15
16
|
//#region src/manager/types/ClientState.d.ts
|
|
16
17
|
type ClientState = {
|
|
17
|
-
readonly status: "
|
|
18
|
+
readonly status: "created" | "started" | "completed" | "forfeited";
|
|
18
19
|
readonly gameId: string;
|
|
19
20
|
readonly playerId: string;
|
|
20
21
|
readonly username: string;
|
|
21
|
-
readonly players: readonly Player[];
|
|
22
|
+
readonly players: readonly Player$1[];
|
|
22
23
|
readonly expiresAt: number;
|
|
23
24
|
readonly chatMessages: readonly ChatMessage[];
|
|
24
25
|
readonly hand: readonly Card[];
|
|
25
26
|
readonly canPlayAt: number | null;
|
|
26
27
|
};
|
|
27
|
-
type Player = {
|
|
28
|
+
type Player$1 = {
|
|
28
29
|
readonly username: string;
|
|
29
30
|
readonly handSize: number;
|
|
30
31
|
readonly drawPileSize: number;
|
|
@@ -107,6 +108,55 @@ type GameEvent = {
|
|
|
107
108
|
readonly numCards: number;
|
|
108
109
|
};
|
|
109
110
|
//#endregion
|
|
111
|
+
//#region src/manager/types/Player.d.ts
|
|
112
|
+
type Player = {
|
|
113
|
+
readonly id: string;
|
|
114
|
+
readonly userId: string;
|
|
115
|
+
readonly username: string;
|
|
116
|
+
readonly events: GameEvent[];
|
|
117
|
+
readonly hand: Card[];
|
|
118
|
+
readonly drawPile: Card[];
|
|
119
|
+
readonly sidePile: Card[];
|
|
120
|
+
readonly centerPile: Card[];
|
|
121
|
+
hasNoPlayableCards: boolean;
|
|
122
|
+
};
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/manager/types/Game.d.ts
|
|
125
|
+
type Game = CreatedGame | StartedGame | CompletedGame | ForfeitedGame;
|
|
126
|
+
type CreatedGame = {
|
|
127
|
+
readonly status: "created";
|
|
128
|
+
readonly id: string;
|
|
129
|
+
readonly createdAt: number;
|
|
130
|
+
readonly expiresAt: number;
|
|
131
|
+
readonly chatMessages: ChatMessage[];
|
|
132
|
+
readonly players: Player[];
|
|
133
|
+
};
|
|
134
|
+
type StartedGame = {
|
|
135
|
+
readonly status: "started";
|
|
136
|
+
readonly id: string;
|
|
137
|
+
readonly createdAt: number;
|
|
138
|
+
expiresAt: number;
|
|
139
|
+
readonly chatMessages: ChatMessage[];
|
|
140
|
+
readonly players: Player[];
|
|
141
|
+
canPlayAt: number;
|
|
142
|
+
};
|
|
143
|
+
type CompletedGame = {
|
|
144
|
+
readonly status: "completed";
|
|
145
|
+
readonly id: string;
|
|
146
|
+
readonly createdAt: number;
|
|
147
|
+
readonly expiresAt: number;
|
|
148
|
+
readonly chatMessages: ChatMessage[];
|
|
149
|
+
readonly players: Player[];
|
|
150
|
+
};
|
|
151
|
+
type ForfeitedGame = {
|
|
152
|
+
readonly status: "forfeited";
|
|
153
|
+
readonly id: string;
|
|
154
|
+
readonly createdAt: number;
|
|
155
|
+
readonly expiresAt: number;
|
|
156
|
+
readonly chatMessages: ChatMessage[];
|
|
157
|
+
readonly players: Player[];
|
|
158
|
+
};
|
|
159
|
+
//#endregion
|
|
110
160
|
//#region src/manager/Manager.d.ts
|
|
111
161
|
type CreateGameResult = {
|
|
112
162
|
readonly success: true;
|
|
@@ -179,10 +229,7 @@ type StartGameResult = {
|
|
|
179
229
|
readonly success: false;
|
|
180
230
|
readonly error: "gameNotFound" | "invalidStatus" | "playerNotFound" | "playerNotAdmin" | "minPlayersNotReached";
|
|
181
231
|
};
|
|
182
|
-
declare class Manager {
|
|
183
|
-
private readonly games;
|
|
184
|
-
private readonly watchdog;
|
|
185
|
-
constructor();
|
|
232
|
+
declare class Manager extends ManagerBase<Game> {
|
|
186
233
|
createGame(userId: string, username: string): CreateGameResult;
|
|
187
234
|
drawCard(gameId: string, playerId: string): DrawCardResult;
|
|
188
235
|
getClientStateAndClearEvents(gameId: string, playerId: string): GetClientStateAndClearEventsResult;
|
|
@@ -197,4 +244,4 @@ declare class Manager {
|
|
|
197
244
|
}
|
|
198
245
|
//#endregion
|
|
199
246
|
export { GetJoinableGamesResult as a, Manager as c, SendChatResult as d, StartGameResult as f, Card as g, ChatMessage as h, GetEventsAndClearAcknowledgedResult as i, PlayCardResult as l, ClientState as m, DrawCardResult as n, JoinGameResult as o, GameEvent as p, GetClientStateAndClearEventsResult as r, LeaveGameResult as s, CreateGameResult as t, ReportNoPlayableCardsResult as u };
|
|
200
|
-
//# sourceMappingURL=index-
|
|
247
|
+
//# sourceMappingURL=index-uaOvIhKT.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-uaOvIhKT.d.cts","names":[],"sources":["../src/manager/types/Card.ts","../src/manager/types/ChatMessage.ts","../src/manager/types/ClientState.ts","../src/manager/types/GameEvent.ts","../src/manager/types/Player.ts","../src/manager/types/Game.ts","../src/manager/Manager.ts"],"mappings":";;KAAY;WACD;WACA;WACA;;;;KCHC;WACD;WACA;WACA;;;;KCAC;WACD;WACA;WACA;WACA;WACA,kBAAkB;WAClB;WACA,uBAAuB;WACvB,eAAe;WACf;;KAGN;WACM;WACA;WACA;WACA;WACA,mBAAmB;;;;KCjBlB;WAEG;WACA;WACA;;WAGA;WACA;WACA;WACA,MAAM;;WAGN;WACA;WACA;WACA,MAAM;WACN;;WAGA;WACA;WACA,SAAS;;WAGT;WACA;WACA,MAAM;;WAGN;WACA;WACA;;WAGA;WACA;;WAGA;WACA;;WAGA;WACA;;WAGA;WACA;WACA,gBAAgB;;WAGhB;WACA;WACA;WACA,MAAM;;WAGN;WACA;WACA;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;;;;KCxFH;WACD;WACA;WACA;WACA,QAAQ;WACR,MAAM;WACN,UAAU;WACV,UAAU;WACV,YAAY;EACrB;;;;KCTU,OAAO,cAAc,cAAc,gBAAgB;KAE1D;WACM;WACA;WACA;WACA;WACA,cAAc;WACd,SAAS;;KAGf;WACM;WACA;WACA;EACT;WACS,cAAc;WACd,SAAS;EAClB;;KAGG;WACM;WACA;WACA;WACA;WACA,cAAc;WACd,SAAS;;KAGf;WACM;WACA;WACA;WACA;WACA,cAAc;WACd,SAAS;;;;KCnBR;WAEG;WACA;WACA;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;KASH;WAEG;WACA,OAAO;;WAGP;WACA;;KAGH;WAEG;WACA,iBAAiB;;WAGjB;WACA;;KAGH;WACD;aACE;aACA;;;KAID;WAEG;WACA;;WAGA;WACA;;KAOH;WAEG;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;KASH;WAEG;;WAGA;WACA;;KAUH;WAEG;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;cAQF,gBAAgB,YAAY;EACvC,WAAW,gBAAgB,mBAAmB;EA4B9C,SAAS,gBAAgB,mBAAmB;EA8B5C,6BACE,gBACA,mBACC;EAgCH,8BACE,gBACA,kBACA,4BACC;EAgBH,oBAAoB;EAWpB,SAAS,gBAAgB,gBAAgB,mBAAmB;EA8B5D,UAAU,gBAAgB,mBAAmB;EAkC7C,SACE,gBACA,kBACA,gBACA,gCACC;EAwDH,sBACE,gBACA,mBACC;EAuFH,SAAS,gBAAgB,kBAAkB,eAAe;EAmB1D,UAAU,gBAAgB,mBAAmB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ManagerBase } from "@hellacardgames/lib";
|
|
1
2
|
//#region src/manager/types/Card.d.ts
|
|
2
3
|
type Card = {
|
|
3
4
|
readonly id: string;
|
|
@@ -14,17 +15,17 @@ type ChatMessage = {
|
|
|
14
15
|
//#endregion
|
|
15
16
|
//#region src/manager/types/ClientState.d.ts
|
|
16
17
|
type ClientState = {
|
|
17
|
-
readonly status: "
|
|
18
|
+
readonly status: "created" | "started" | "completed" | "forfeited";
|
|
18
19
|
readonly gameId: string;
|
|
19
20
|
readonly playerId: string;
|
|
20
21
|
readonly username: string;
|
|
21
|
-
readonly players: readonly Player[];
|
|
22
|
+
readonly players: readonly Player$1[];
|
|
22
23
|
readonly expiresAt: number;
|
|
23
24
|
readonly chatMessages: readonly ChatMessage[];
|
|
24
25
|
readonly hand: readonly Card[];
|
|
25
26
|
readonly canPlayAt: number | null;
|
|
26
27
|
};
|
|
27
|
-
type Player = {
|
|
28
|
+
type Player$1 = {
|
|
28
29
|
readonly username: string;
|
|
29
30
|
readonly handSize: number;
|
|
30
31
|
readonly drawPileSize: number;
|
|
@@ -107,6 +108,55 @@ type GameEvent = {
|
|
|
107
108
|
readonly numCards: number;
|
|
108
109
|
};
|
|
109
110
|
//#endregion
|
|
111
|
+
//#region src/manager/types/Player.d.ts
|
|
112
|
+
type Player = {
|
|
113
|
+
readonly id: string;
|
|
114
|
+
readonly userId: string;
|
|
115
|
+
readonly username: string;
|
|
116
|
+
readonly events: GameEvent[];
|
|
117
|
+
readonly hand: Card[];
|
|
118
|
+
readonly drawPile: Card[];
|
|
119
|
+
readonly sidePile: Card[];
|
|
120
|
+
readonly centerPile: Card[];
|
|
121
|
+
hasNoPlayableCards: boolean;
|
|
122
|
+
};
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/manager/types/Game.d.ts
|
|
125
|
+
type Game = CreatedGame | StartedGame | CompletedGame | ForfeitedGame;
|
|
126
|
+
type CreatedGame = {
|
|
127
|
+
readonly status: "created";
|
|
128
|
+
readonly id: string;
|
|
129
|
+
readonly createdAt: number;
|
|
130
|
+
readonly expiresAt: number;
|
|
131
|
+
readonly chatMessages: ChatMessage[];
|
|
132
|
+
readonly players: Player[];
|
|
133
|
+
};
|
|
134
|
+
type StartedGame = {
|
|
135
|
+
readonly status: "started";
|
|
136
|
+
readonly id: string;
|
|
137
|
+
readonly createdAt: number;
|
|
138
|
+
expiresAt: number;
|
|
139
|
+
readonly chatMessages: ChatMessage[];
|
|
140
|
+
readonly players: Player[];
|
|
141
|
+
canPlayAt: number;
|
|
142
|
+
};
|
|
143
|
+
type CompletedGame = {
|
|
144
|
+
readonly status: "completed";
|
|
145
|
+
readonly id: string;
|
|
146
|
+
readonly createdAt: number;
|
|
147
|
+
readonly expiresAt: number;
|
|
148
|
+
readonly chatMessages: ChatMessage[];
|
|
149
|
+
readonly players: Player[];
|
|
150
|
+
};
|
|
151
|
+
type ForfeitedGame = {
|
|
152
|
+
readonly status: "forfeited";
|
|
153
|
+
readonly id: string;
|
|
154
|
+
readonly createdAt: number;
|
|
155
|
+
readonly expiresAt: number;
|
|
156
|
+
readonly chatMessages: ChatMessage[];
|
|
157
|
+
readonly players: Player[];
|
|
158
|
+
};
|
|
159
|
+
//#endregion
|
|
110
160
|
//#region src/manager/Manager.d.ts
|
|
111
161
|
type CreateGameResult = {
|
|
112
162
|
readonly success: true;
|
|
@@ -179,10 +229,7 @@ type StartGameResult = {
|
|
|
179
229
|
readonly success: false;
|
|
180
230
|
readonly error: "gameNotFound" | "invalidStatus" | "playerNotFound" | "playerNotAdmin" | "minPlayersNotReached";
|
|
181
231
|
};
|
|
182
|
-
declare class Manager {
|
|
183
|
-
private readonly games;
|
|
184
|
-
private readonly watchdog;
|
|
185
|
-
constructor();
|
|
232
|
+
declare class Manager extends ManagerBase<Game> {
|
|
186
233
|
createGame(userId: string, username: string): CreateGameResult;
|
|
187
234
|
drawCard(gameId: string, playerId: string): DrawCardResult;
|
|
188
235
|
getClientStateAndClearEvents(gameId: string, playerId: string): GetClientStateAndClearEventsResult;
|
|
@@ -197,4 +244,4 @@ declare class Manager {
|
|
|
197
244
|
}
|
|
198
245
|
//#endregion
|
|
199
246
|
export { GetJoinableGamesResult as a, Manager as c, SendChatResult as d, StartGameResult as f, Card as g, ChatMessage as h, GetEventsAndClearAcknowledgedResult as i, PlayCardResult as l, ClientState as m, DrawCardResult as n, JoinGameResult as o, GameEvent as p, GetClientStateAndClearEventsResult as r, LeaveGameResult as s, CreateGameResult as t, ReportNoPlayableCardsResult as u };
|
|
200
|
-
//# sourceMappingURL=index-
|
|
247
|
+
//# sourceMappingURL=index-uaOvIhKT.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-uaOvIhKT.d.mts","names":[],"sources":["../src/manager/types/Card.ts","../src/manager/types/ChatMessage.ts","../src/manager/types/ClientState.ts","../src/manager/types/GameEvent.ts","../src/manager/types/Player.ts","../src/manager/types/Game.ts","../src/manager/Manager.ts"],"mappings":";;KAAY;WACD;WACA;WACA;;;;KCHC;WACD;WACA;WACA;;;;KCAC;WACD;WACA;WACA;WACA;WACA,kBAAkB;WAClB;WACA,uBAAuB;WACvB,eAAe;WACf;;KAGN;WACM;WACA;WACA;WACA;WACA,mBAAmB;;;;KCjBlB;WAEG;WACA;WACA;;WAGA;WACA;WACA;WACA,MAAM;;WAGN;WACA;WACA;WACA,MAAM;WACN;;WAGA;WACA;WACA,SAAS;;WAGT;WACA;WACA,MAAM;;WAGN;WACA;WACA;;WAGA;WACA;;WAGA;WACA;;WAGA;WACA;;WAGA;WACA;WACA,gBAAgB;;WAGhB;WACA;WACA;WACA,MAAM;;WAGN;WACA;WACA;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;;;;KCxFH;WACD;WACA;WACA;WACA,QAAQ;WACR,MAAM;WACN,UAAU;WACV,UAAU;WACV,YAAY;EACrB;;;;KCTU,OAAO,cAAc,cAAc,gBAAgB;KAE1D;WACM;WACA;WACA;WACA;WACA,cAAc;WACd,SAAS;;KAGf;WACM;WACA;WACA;EACT;WACS,cAAc;WACd,SAAS;EAClB;;KAGG;WACM;WACA;WACA;WACA;WACA,cAAc;WACd,SAAS;;KAGf;WACM;WACA;WACA;WACA;WACA,cAAc;WACd,SAAS;;;;KCnBR;WAEG;WACA;WACA;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;KASH;WAEG;WACA,OAAO;;WAGP;WACA;;KAGH;WAEG;WACA,iBAAiB;;WAGjB;WACA;;KAGH;WACD;aACE;aACA;;;KAID;WAEG;WACA;;WAGA;WACA;;KAOH;WAEG;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;KASH;WAEG;;WAGA;WACA;;KAUH;WAEG;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;cAQF,gBAAgB,YAAY;EACvC,WAAW,gBAAgB,mBAAmB;EA4B9C,SAAS,gBAAgB,mBAAmB;EA8B5C,6BACE,gBACA,mBACC;EAgCH,8BACE,gBACA,kBACA,4BACC;EAgBH,oBAAoB;EAWpB,SAAS,gBAAgB,gBAAgB,mBAAmB;EA8B5D,UAAU,gBAAgB,mBAAmB;EAkC7C,SACE,gBACA,kBACA,gBACA,gCACC;EAwDH,sBACE,gBACA,mBACC;EAuFH,SAAS,gBAAgB,kBAAkB,eAAe;EAmB1D,UAAU,gBAAgB,mBAAmB"}
|
package/dist/manager/index.cjs
CHANGED
package/dist/manager/index.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as GetJoinableGamesResult, c as Manager, d as SendChatResult, f as StartGameResult, g as Card, h as ChatMessage, i as GetEventsAndClearAcknowledgedResult, l as PlayCardResult, m as ClientState, n as DrawCardResult, o as JoinGameResult, p as GameEvent, r as GetClientStateAndClearEventsResult, s as LeaveGameResult, t as CreateGameResult, u as ReportNoPlayableCardsResult } from "../index-
|
|
1
|
+
import { a as GetJoinableGamesResult, c as Manager, d as SendChatResult, f as StartGameResult, g as Card, h as ChatMessage, i as GetEventsAndClearAcknowledgedResult, l as PlayCardResult, m as ClientState, n as DrawCardResult, o as JoinGameResult, p as GameEvent, r as GetClientStateAndClearEventsResult, s as LeaveGameResult, t as CreateGameResult, u as ReportNoPlayableCardsResult } from "../index-uaOvIhKT.cjs";
|
|
2
2
|
export { type Card, type ChatMessage, type ClientState, type CreateGameResult, type DrawCardResult, type GameEvent, type GetClientStateAndClearEventsResult, type GetEventsAndClearAcknowledgedResult, type GetJoinableGamesResult, type JoinGameResult, type LeaveGameResult, Manager, type PlayCardResult, type ReportNoPlayableCardsResult, type SendChatResult, type StartGameResult };
|
package/dist/manager/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as GetJoinableGamesResult, c as Manager, d as SendChatResult, f as StartGameResult, g as Card, h as ChatMessage, i as GetEventsAndClearAcknowledgedResult, l as PlayCardResult, m as ClientState, n as DrawCardResult, o as JoinGameResult, p as GameEvent, r as GetClientStateAndClearEventsResult, s as LeaveGameResult, t as CreateGameResult, u as ReportNoPlayableCardsResult } from "../index-
|
|
1
|
+
import { a as GetJoinableGamesResult, c as Manager, d as SendChatResult, f as StartGameResult, g as Card, h as ChatMessage, i as GetEventsAndClearAcknowledgedResult, l as PlayCardResult, m as ClientState, n as DrawCardResult, o as JoinGameResult, p as GameEvent, r as GetClientStateAndClearEventsResult, s as LeaveGameResult, t as CreateGameResult, u as ReportNoPlayableCardsResult } from "../index-uaOvIhKT.mjs";
|
|
2
2
|
export { type Card, type ChatMessage, type ClientState, type CreateGameResult, type DrawCardResult, type GameEvent, type GetClientStateAndClearEventsResult, type GetEventsAndClearAcknowledgedResult, type GetJoinableGamesResult, type JoinGameResult, type LeaveGameResult, Manager, type PlayCardResult, type ReportNoPlayableCardsResult, type SendChatResult, type StartGameResult };
|
package/dist/manager/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as Manager } from "../manager-
|
|
1
|
+
import { t as Manager } from "../manager-BAxBCUOk.mjs";
|
|
2
2
|
export { Manager };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
+
import { ManagerBase } from "@hellacardgames/lib";
|
|
1
2
|
//#region src/manager/constants.ts
|
|
2
|
-
const GAME_KEY = "speed";
|
|
3
|
-
const WATCHDOG_INTERVAL_MS = 1e4;
|
|
4
3
|
const EXPIRY_EXTENSION_MS = 3e5;
|
|
5
4
|
const CAN_PLAY_AT_DELAY_MS = 3e3;
|
|
6
5
|
const CARDS = [
|
|
@@ -266,25 +265,6 @@ const CARDS = [
|
|
|
266
265
|
}
|
|
267
266
|
];
|
|
268
267
|
//#endregion
|
|
269
|
-
//#region src/manager/Watchdog.ts
|
|
270
|
-
var Watchdog = class {
|
|
271
|
-
games;
|
|
272
|
-
constructor(games) {
|
|
273
|
-
this.games = games;
|
|
274
|
-
}
|
|
275
|
-
start() {
|
|
276
|
-
console.log(`watchdog start at ${Date.now()} (${GAME_KEY})`);
|
|
277
|
-
setInterval(() => this.wakeUp(), WATCHDOG_INTERVAL_MS);
|
|
278
|
-
}
|
|
279
|
-
wakeUp() {
|
|
280
|
-
const now = Date.now();
|
|
281
|
-
for (const game of this.games.values()) if (game.expiresAt <= now) {
|
|
282
|
-
this.games.delete(game.id);
|
|
283
|
-
console.log(`watchdog purged ${game.id} (${GAME_KEY})`);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
//#endregion
|
|
288
268
|
//#region src/lib/emitEvent.ts
|
|
289
269
|
function emitEvent(game, data) {
|
|
290
270
|
const event = {
|
|
@@ -326,16 +306,9 @@ function shuffleCards(cards) {
|
|
|
326
306
|
}
|
|
327
307
|
//#endregion
|
|
328
308
|
//#region src/manager/Manager.ts
|
|
329
|
-
var Manager = class {
|
|
330
|
-
games;
|
|
331
|
-
watchdog;
|
|
332
|
-
constructor() {
|
|
333
|
-
this.games = /* @__PURE__ */ new Map();
|
|
334
|
-
this.watchdog = new Watchdog(this.games);
|
|
335
|
-
this.watchdog.start();
|
|
336
|
-
}
|
|
309
|
+
var Manager = class extends ManagerBase {
|
|
337
310
|
createGame(userId, username) {
|
|
338
|
-
if (this.games.size ===
|
|
311
|
+
if (this.games.size === this.maxGames) return {
|
|
339
312
|
success: false,
|
|
340
313
|
error: "maxGamesReached"
|
|
341
314
|
};
|
|
@@ -352,7 +325,7 @@ var Manager = class {
|
|
|
352
325
|
};
|
|
353
326
|
const createdAt = Date.now();
|
|
354
327
|
const game = {
|
|
355
|
-
status: "
|
|
328
|
+
status: "created",
|
|
356
329
|
id: crypto.randomUUID(),
|
|
357
330
|
createdAt,
|
|
358
331
|
expiresAt: createdAt + EXPIRY_EXTENSION_MS,
|
|
@@ -463,7 +436,7 @@ var Manager = class {
|
|
|
463
436
|
};
|
|
464
437
|
}
|
|
465
438
|
getJoinableGames() {
|
|
466
|
-
return { games: Array.from(this.games.values()).filter((g) => g.status === "
|
|
439
|
+
return { games: Array.from(this.games.values()).filter((g) => g.status === "created" && g.players.length < 2).map((g) => ({
|
|
467
440
|
id: g.id,
|
|
468
441
|
numPlayers: g.players.length
|
|
469
442
|
})) };
|
|
@@ -474,7 +447,7 @@ var Manager = class {
|
|
|
474
447
|
success: false,
|
|
475
448
|
error: "gameNotFound"
|
|
476
449
|
};
|
|
477
|
-
if (game.status !== "
|
|
450
|
+
if (game.status !== "created") return {
|
|
478
451
|
success: false,
|
|
479
452
|
error: "invalidStatus"
|
|
480
453
|
};
|
|
@@ -721,7 +694,7 @@ var Manager = class {
|
|
|
721
694
|
success: false,
|
|
722
695
|
error: "playerNotFound"
|
|
723
696
|
};
|
|
724
|
-
if (game.status !== "
|
|
697
|
+
if (game.status !== "created") return {
|
|
725
698
|
success: false,
|
|
726
699
|
error: "invalidStatus"
|
|
727
700
|
};
|
|
@@ -814,4 +787,4 @@ var Manager = class {
|
|
|
814
787
|
//#endregion
|
|
815
788
|
export { Manager as t };
|
|
816
789
|
|
|
817
|
-
//# sourceMappingURL=manager-
|
|
790
|
+
//# sourceMappingURL=manager-BAxBCUOk.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager-BAxBCUOk.mjs","names":[],"sources":["../src/manager/constants.ts","../src/lib/emitEvent.ts","../src/lib/emitEventToPlayer.ts","../src/manager/lib/isCardPlayable.ts","../src/manager/lib/hasPlayableCard.ts","../src/lib/shuffleCards.ts","../src/manager/Manager.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","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 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","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 { ManagerBase } from \"@hellacardgames/lib\";\nimport {\n CAN_PLAY_AT_DELAY_MS,\n CARDS,\n EXPIRY_EXTENSION_MS,\n MAX_HAND_SIZE,\n MAX_PLAYERS,\n MIN_PLAYERS,\n} from \"./constants.js\";\nimport { emitEvent } from \"../lib/emitEvent.js\";\nimport { emitEventToPlayer } from \"../lib/emitEventToPlayer.js\";\nimport { isCardPlayable } from \"./lib/isCardPlayable.js\";\nimport { hasPlayableCard } from \"./lib/hasPlayableCard.js\";\nimport { shuffleCards } from \"../lib/shuffleCards.js\";\nimport type { ChatMessage } from \"./types/ChatMessage.js\";\nimport type { ClientState } from \"./types/ClientState.js\";\nimport type { Game } from \"./types/Game.js\";\nimport type { GameEvent } from \"./types/GameEvent.js\";\nimport type { Player } from \"./types/Player.js\";\n\nexport type CreateGameResult =\n | {\n readonly success: true;\n readonly gameId: string;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error: \"maxGamesReached\";\n };\n\nexport type DrawCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"handFull\"\n | \"drawPileEmpty\";\n };\n\nexport type GetClientStateAndClearEventsResult =\n | {\n readonly success: true;\n readonly state: ClientState;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetEventsAndClearAcknowledgedResult =\n | {\n readonly success: true;\n readonly events: readonly GameEvent[];\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetJoinableGamesResult = {\n readonly games: readonly {\n readonly id: string;\n readonly numPlayers: number;\n }[];\n};\n\nexport type JoinGameResult =\n | {\n readonly success: true;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"maxPlayersReached\"\n | \"alreadyInGame\";\n };\n\nexport type LeaveGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type PlayCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"cardNotFound\"\n | \"cardNotPlayable\";\n };\n\nexport type ReportNoPlayableCardsResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"alreadyReported\"\n | \"hasPlayableCard\"\n | \"canDraw\";\n };\n\nexport type SendChatResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type StartGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"playerNotFound\"\n | \"playerNotAdmin\"\n | \"minPlayersNotReached\";\n };\n\nexport class Manager extends ManagerBase<Game> {\n createGame(userId: string, username: string): CreateGameResult {\n if (this.games.size === this.maxGames) {\n return { success: false, error: \"maxGamesReached\" };\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n const createdAt = Date.now();\n const game: Game = {\n status: \"created\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n };\n this.games.set(game.id, game);\n return { success: true, gameId: game.id, playerId: player.id };\n }\n\n drawCard(gameId: string, playerId: string): DrawCardResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" };\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" };\n }\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n const card = player.drawPile.pop()!;\n player.hand.push(card);\n emitEventToPlayer(player, { type: \"drewCard\", card });\n emitEvent(game, { type: \"playerDrewCard\", username: player.username });\n return { success: true };\n }\n\n getClientStateAndClearEvents(\n gameId: string,\n playerId: string,\n ): GetClientStateAndClearEventsResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const state: ClientState = {\n status: game.status,\n gameId,\n playerId,\n username: player.username,\n players: game.players.map((p) => ({\n username: p.username,\n handSize: p.hand.length,\n drawPileSize: p.drawPile.length,\n sidePileSize: p.sidePile.length,\n centerPileTopCard: p.centerPile.length\n ? p.centerPile[p.centerPile.length - 1]!\n : null,\n })),\n expiresAt: game.expiresAt,\n chatMessages: game.chatMessages,\n hand: player.hand,\n canPlayAt: game.status === \"started\" ? game.canPlayAt : null,\n };\n player.events.length = 0;\n return { success: true, state };\n }\n\n getEventsAndClearAcknowledged(\n gameId: string,\n playerId: string,\n lastReadId: string | null,\n ): GetEventsAndClearAcknowledgedResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const lastReadEventIndex = player.events.findIndex(\n (e) => e.id === lastReadId,\n );\n player.events.splice(0, lastReadEventIndex + 1);\n return { success: true, events: player.events };\n }\n\n getJoinableGames(): GetJoinableGamesResult {\n return {\n games: Array.from(this.games.values())\n .filter((g) => g.status === \"created\" && g.players.length < MAX_PLAYERS)\n .map((g) => ({\n id: g.id,\n numPlayers: g.players.length,\n })),\n };\n }\n\n joinGame(gameId: string, userId: string, username: string): JoinGameResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" };\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" };\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n game.players.push(player);\n emitEvent(game, { type: \"playerJoined\", username });\n return { success: true, playerId: player.id };\n }\n\n leaveGame(gameId: string, playerId: string): LeaveGameResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const playerIndex = game.players.findIndex((p) => p.id === playerId);\n if (playerIndex === -1) {\n return { success: false, error: \"playerNotFound\" };\n }\n\n const player = game.players[playerIndex]!;\n emitEvent(game, { type: \"playerLeft\", username: player.username });\n\n game.players.splice(playerIndex, 1);\n\n if (game.status === \"started\" && game.players.length < MIN_PLAYERS) {\n const forfeitedGame: Game = {\n ...game,\n status: \"forfeited\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n };\n this.games.set(game.id, forfeitedGame);\n emitEvent(forfeitedGame, { type: \"gameForfeited\" });\n emitEvent(forfeitedGame, {\n type: \"expirationUpdated\",\n expiresAt: forfeitedGame.expiresAt,\n });\n }\n if (game.players.length === 0) {\n this.games.delete(game.id);\n }\n return { success: true };\n }\n\n playCard(\n gameId: string,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n ): PlayCardResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n const cardIndex = player.hand.findIndex((c) => c.id === cardId);\n if (cardIndex === -1) {\n return { success: false, error: \"cardNotFound\" };\n }\n const otherPlayer = game.players.find((p) => p !== player)!;\n const targetPile = isForOtherPlayerPile\n ? otherPlayer.centerPile\n : player.centerPile;\n const card = player.hand[cardIndex]!;\n if (!isCardPlayable(card, targetPile)) {\n return { success: false, error: \"cardNotPlayable\" };\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hand.splice(cardIndex, 1);\n targetPile.push(card);\n emitEvent(game, {\n type: \"cardPlayed\",\n username: player.username,\n card,\n isForOtherPlayerPile,\n });\n\n if (otherPlayer.hasNoPlayableCards && hasPlayableCard(otherPlayer, game)) {\n otherPlayer.hasNoPlayableCards = false;\n }\n\n if (player.hand.length === 0 && player.drawPile.length === 0) {\n emitEvent(game, { type: \"gameCompleted\" });\n const completedGame: Game = {\n ...game,\n status: \"completed\",\n };\n this.games.set(game.id, completedGame);\n }\n\n return { success: true };\n }\n\n reportNoPlayableCards(\n gameId: string,\n playerId: string,\n ): ReportNoPlayableCardsResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" };\n }\n if (hasPlayableCard(player, game)) {\n return { success: false, error: \"hasPlayableCard\" };\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" };\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hasNoPlayableCards = true;\n\n const otherPlayer = game.players.find((p) => p !== player)!;\n if (otherPlayer.hasNoPlayableCards) {\n if (player.sidePile.length === 0 && otherPlayer.sidePile.length === 0) {\n const cards = [...player.centerPile, ...otherPlayer.centerPile];\n shuffleCards(cards);\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n } else {\n const playerSidePileCard = player.sidePile.pop()!;\n player.centerPile.push(playerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: player.username,\n card: playerSidePileCard,\n });\n const otherPlayerSidePileCard = otherPlayer.sidePile.pop()!;\n otherPlayer.centerPile.push(otherPlayerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: otherPlayer.username,\n card: otherPlayerSidePileCard,\n });\n }\n player.hasNoPlayableCards = false;\n otherPlayer.hasNoPlayableCards = false;\n game.canPlayAt = Date.now() + CAN_PLAY_AT_DELAY_MS;\n emitEvent(game, {\n type: \"canPlayAtUpdated\",\n canPlayAt: game.canPlayAt,\n });\n }\n\n return { success: true };\n }\n\n sendChat(gameId: string, playerId: string, text: string): SendChatResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const message: ChatMessage = {\n id: crypto.randomUUID(),\n username: player.username,\n text,\n };\n game.chatMessages.push(message);\n emitEvent(game, { type: \"chat\", message });\n return { success: true };\n }\n\n startGame(gameId: string, playerId: string): StartGameResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" };\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" };\n }\n const otherPlayer = game.players[1]!;\n const cards = [...CARDS];\n shuffleCards(cards);\n\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n\n player.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: player.username,\n numCards: player.drawPile.length,\n });\n\n player.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(player, { type: \"handInitialized\", cards: player.hand });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: player.username,\n numCards: player.hand.length,\n });\n\n otherPlayer.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.drawPile.length,\n });\n\n otherPlayer.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(otherPlayer, {\n type: \"handInitialized\",\n cards: otherPlayer.hand,\n });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.hand.length,\n });\n\n const startedGame: Game = {\n ...game,\n status: \"started\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS,\n };\n 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 };\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
+
let _hellacardgames_lib = require("@hellacardgames/lib");
|
|
1
2
|
//#region src/manager/constants.ts
|
|
2
|
-
const GAME_KEY = "speed";
|
|
3
|
-
const WATCHDOG_INTERVAL_MS = 1e4;
|
|
4
3
|
const EXPIRY_EXTENSION_MS = 3e5;
|
|
5
4
|
const CAN_PLAY_AT_DELAY_MS = 3e3;
|
|
6
5
|
const CARDS = [
|
|
@@ -266,25 +265,6 @@ const CARDS = [
|
|
|
266
265
|
}
|
|
267
266
|
];
|
|
268
267
|
//#endregion
|
|
269
|
-
//#region src/manager/Watchdog.ts
|
|
270
|
-
var Watchdog = class {
|
|
271
|
-
games;
|
|
272
|
-
constructor(games) {
|
|
273
|
-
this.games = games;
|
|
274
|
-
}
|
|
275
|
-
start() {
|
|
276
|
-
console.log(`watchdog start at ${Date.now()} (${GAME_KEY})`);
|
|
277
|
-
setInterval(() => this.wakeUp(), WATCHDOG_INTERVAL_MS);
|
|
278
|
-
}
|
|
279
|
-
wakeUp() {
|
|
280
|
-
const now = Date.now();
|
|
281
|
-
for (const game of this.games.values()) if (game.expiresAt <= now) {
|
|
282
|
-
this.games.delete(game.id);
|
|
283
|
-
console.log(`watchdog purged ${game.id} (${GAME_KEY})`);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
//#endregion
|
|
288
268
|
//#region src/lib/emitEvent.ts
|
|
289
269
|
function emitEvent(game, data) {
|
|
290
270
|
const event = {
|
|
@@ -326,16 +306,9 @@ function shuffleCards(cards) {
|
|
|
326
306
|
}
|
|
327
307
|
//#endregion
|
|
328
308
|
//#region src/manager/Manager.ts
|
|
329
|
-
var Manager = class {
|
|
330
|
-
games;
|
|
331
|
-
watchdog;
|
|
332
|
-
constructor() {
|
|
333
|
-
this.games = /* @__PURE__ */ new Map();
|
|
334
|
-
this.watchdog = new Watchdog(this.games);
|
|
335
|
-
this.watchdog.start();
|
|
336
|
-
}
|
|
309
|
+
var Manager = class extends _hellacardgames_lib.ManagerBase {
|
|
337
310
|
createGame(userId, username) {
|
|
338
|
-
if (this.games.size ===
|
|
311
|
+
if (this.games.size === this.maxGames) return {
|
|
339
312
|
success: false,
|
|
340
313
|
error: "maxGamesReached"
|
|
341
314
|
};
|
|
@@ -352,7 +325,7 @@ var Manager = class {
|
|
|
352
325
|
};
|
|
353
326
|
const createdAt = Date.now();
|
|
354
327
|
const game = {
|
|
355
|
-
status: "
|
|
328
|
+
status: "created",
|
|
356
329
|
id: crypto.randomUUID(),
|
|
357
330
|
createdAt,
|
|
358
331
|
expiresAt: createdAt + EXPIRY_EXTENSION_MS,
|
|
@@ -463,7 +436,7 @@ var Manager = class {
|
|
|
463
436
|
};
|
|
464
437
|
}
|
|
465
438
|
getJoinableGames() {
|
|
466
|
-
return { games: Array.from(this.games.values()).filter((g) => g.status === "
|
|
439
|
+
return { games: Array.from(this.games.values()).filter((g) => g.status === "created" && g.players.length < 2).map((g) => ({
|
|
467
440
|
id: g.id,
|
|
468
441
|
numPlayers: g.players.length
|
|
469
442
|
})) };
|
|
@@ -474,7 +447,7 @@ var Manager = class {
|
|
|
474
447
|
success: false,
|
|
475
448
|
error: "gameNotFound"
|
|
476
449
|
};
|
|
477
|
-
if (game.status !== "
|
|
450
|
+
if (game.status !== "created") return {
|
|
478
451
|
success: false,
|
|
479
452
|
error: "invalidStatus"
|
|
480
453
|
};
|
|
@@ -721,7 +694,7 @@ var Manager = class {
|
|
|
721
694
|
success: false,
|
|
722
695
|
error: "playerNotFound"
|
|
723
696
|
};
|
|
724
|
-
if (game.status !== "
|
|
697
|
+
if (game.status !== "created") return {
|
|
725
698
|
success: false,
|
|
726
699
|
error: "invalidStatus"
|
|
727
700
|
};
|
|
@@ -819,4 +792,4 @@ Object.defineProperty(exports, "Manager", {
|
|
|
819
792
|
}
|
|
820
793
|
});
|
|
821
794
|
|
|
822
|
-
//# sourceMappingURL=manager-
|
|
795
|
+
//# sourceMappingURL=manager-C9oZYA47.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager-C9oZYA47.cjs","names":["ManagerBase"],"sources":["../src/manager/constants.ts","../src/lib/emitEvent.ts","../src/lib/emitEventToPlayer.ts","../src/manager/lib/isCardPlayable.ts","../src/manager/lib/hasPlayableCard.ts","../src/lib/shuffleCards.ts","../src/manager/Manager.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","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 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","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 { ManagerBase } from \"@hellacardgames/lib\";\nimport {\n CAN_PLAY_AT_DELAY_MS,\n CARDS,\n EXPIRY_EXTENSION_MS,\n MAX_HAND_SIZE,\n MAX_PLAYERS,\n MIN_PLAYERS,\n} from \"./constants.js\";\nimport { emitEvent } from \"../lib/emitEvent.js\";\nimport { emitEventToPlayer } from \"../lib/emitEventToPlayer.js\";\nimport { isCardPlayable } from \"./lib/isCardPlayable.js\";\nimport { hasPlayableCard } from \"./lib/hasPlayableCard.js\";\nimport { shuffleCards } from \"../lib/shuffleCards.js\";\nimport type { ChatMessage } from \"./types/ChatMessage.js\";\nimport type { ClientState } from \"./types/ClientState.js\";\nimport type { Game } from \"./types/Game.js\";\nimport type { GameEvent } from \"./types/GameEvent.js\";\nimport type { Player } from \"./types/Player.js\";\n\nexport type CreateGameResult =\n | {\n readonly success: true;\n readonly gameId: string;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error: \"maxGamesReached\";\n };\n\nexport type DrawCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"handFull\"\n | \"drawPileEmpty\";\n };\n\nexport type GetClientStateAndClearEventsResult =\n | {\n readonly success: true;\n readonly state: ClientState;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetEventsAndClearAcknowledgedResult =\n | {\n readonly success: true;\n readonly events: readonly GameEvent[];\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetJoinableGamesResult = {\n readonly games: readonly {\n readonly id: string;\n readonly numPlayers: number;\n }[];\n};\n\nexport type JoinGameResult =\n | {\n readonly success: true;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"maxPlayersReached\"\n | \"alreadyInGame\";\n };\n\nexport type LeaveGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type PlayCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"cardNotFound\"\n | \"cardNotPlayable\";\n };\n\nexport type ReportNoPlayableCardsResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"alreadyReported\"\n | \"hasPlayableCard\"\n | \"canDraw\";\n };\n\nexport type SendChatResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type StartGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"playerNotFound\"\n | \"playerNotAdmin\"\n | \"minPlayersNotReached\";\n };\n\nexport class Manager extends ManagerBase<Game> {\n createGame(userId: string, username: string): CreateGameResult {\n if (this.games.size === this.maxGames) {\n return { success: false, error: \"maxGamesReached\" };\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n const createdAt = Date.now();\n const game: Game = {\n status: \"created\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n };\n this.games.set(game.id, game);\n return { success: true, gameId: game.id, playerId: player.id };\n }\n\n drawCard(gameId: string, playerId: string): DrawCardResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" };\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" };\n }\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n const card = player.drawPile.pop()!;\n player.hand.push(card);\n emitEventToPlayer(player, { type: \"drewCard\", card });\n emitEvent(game, { type: \"playerDrewCard\", username: player.username });\n return { success: true };\n }\n\n getClientStateAndClearEvents(\n gameId: string,\n playerId: string,\n ): GetClientStateAndClearEventsResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const state: ClientState = {\n status: game.status,\n gameId,\n playerId,\n username: player.username,\n players: game.players.map((p) => ({\n username: p.username,\n handSize: p.hand.length,\n drawPileSize: p.drawPile.length,\n sidePileSize: p.sidePile.length,\n centerPileTopCard: p.centerPile.length\n ? p.centerPile[p.centerPile.length - 1]!\n : null,\n })),\n expiresAt: game.expiresAt,\n chatMessages: game.chatMessages,\n hand: player.hand,\n canPlayAt: game.status === \"started\" ? game.canPlayAt : null,\n };\n player.events.length = 0;\n return { success: true, state };\n }\n\n getEventsAndClearAcknowledged(\n gameId: string,\n playerId: string,\n lastReadId: string | null,\n ): GetEventsAndClearAcknowledgedResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const lastReadEventIndex = player.events.findIndex(\n (e) => e.id === lastReadId,\n );\n player.events.splice(0, lastReadEventIndex + 1);\n return { success: true, events: player.events };\n }\n\n getJoinableGames(): GetJoinableGamesResult {\n return {\n games: Array.from(this.games.values())\n .filter((g) => g.status === \"created\" && g.players.length < MAX_PLAYERS)\n .map((g) => ({\n id: g.id,\n numPlayers: g.players.length,\n })),\n };\n }\n\n joinGame(gameId: string, userId: string, username: string): JoinGameResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" };\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" };\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n game.players.push(player);\n emitEvent(game, { type: \"playerJoined\", username });\n return { success: true, playerId: player.id };\n }\n\n leaveGame(gameId: string, playerId: string): LeaveGameResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const playerIndex = game.players.findIndex((p) => p.id === playerId);\n if (playerIndex === -1) {\n return { success: false, error: \"playerNotFound\" };\n }\n\n const player = game.players[playerIndex]!;\n emitEvent(game, { type: \"playerLeft\", username: player.username });\n\n game.players.splice(playerIndex, 1);\n\n if (game.status === \"started\" && game.players.length < MIN_PLAYERS) {\n const forfeitedGame: Game = {\n ...game,\n status: \"forfeited\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n };\n this.games.set(game.id, forfeitedGame);\n emitEvent(forfeitedGame, { type: \"gameForfeited\" });\n emitEvent(forfeitedGame, {\n type: \"expirationUpdated\",\n expiresAt: forfeitedGame.expiresAt,\n });\n }\n if (game.players.length === 0) {\n this.games.delete(game.id);\n }\n return { success: true };\n }\n\n playCard(\n gameId: string,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n ): PlayCardResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n const cardIndex = player.hand.findIndex((c) => c.id === cardId);\n if (cardIndex === -1) {\n return { success: false, error: \"cardNotFound\" };\n }\n const otherPlayer = game.players.find((p) => p !== player)!;\n const targetPile = isForOtherPlayerPile\n ? otherPlayer.centerPile\n : player.centerPile;\n const card = player.hand[cardIndex]!;\n if (!isCardPlayable(card, targetPile)) {\n return { success: false, error: \"cardNotPlayable\" };\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hand.splice(cardIndex, 1);\n targetPile.push(card);\n emitEvent(game, {\n type: \"cardPlayed\",\n username: player.username,\n card,\n isForOtherPlayerPile,\n });\n\n if (otherPlayer.hasNoPlayableCards && hasPlayableCard(otherPlayer, game)) {\n otherPlayer.hasNoPlayableCards = false;\n }\n\n if (player.hand.length === 0 && player.drawPile.length === 0) {\n emitEvent(game, { type: \"gameCompleted\" });\n const completedGame: Game = {\n ...game,\n status: \"completed\",\n };\n this.games.set(game.id, completedGame);\n }\n\n return { success: true };\n }\n\n reportNoPlayableCards(\n gameId: string,\n playerId: string,\n ): ReportNoPlayableCardsResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" };\n }\n if (hasPlayableCard(player, game)) {\n return { success: false, error: \"hasPlayableCard\" };\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" };\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hasNoPlayableCards = true;\n\n const otherPlayer = game.players.find((p) => p !== player)!;\n if (otherPlayer.hasNoPlayableCards) {\n if (player.sidePile.length === 0 && otherPlayer.sidePile.length === 0) {\n const cards = [...player.centerPile, ...otherPlayer.centerPile];\n shuffleCards(cards);\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n } else {\n const playerSidePileCard = player.sidePile.pop()!;\n player.centerPile.push(playerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: player.username,\n card: playerSidePileCard,\n });\n const otherPlayerSidePileCard = otherPlayer.sidePile.pop()!;\n otherPlayer.centerPile.push(otherPlayerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: otherPlayer.username,\n card: otherPlayerSidePileCard,\n });\n }\n player.hasNoPlayableCards = false;\n otherPlayer.hasNoPlayableCards = false;\n game.canPlayAt = Date.now() + CAN_PLAY_AT_DELAY_MS;\n emitEvent(game, {\n type: \"canPlayAtUpdated\",\n canPlayAt: game.canPlayAt,\n });\n }\n\n return { success: true };\n }\n\n sendChat(gameId: string, playerId: string, text: string): SendChatResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const message: ChatMessage = {\n id: crypto.randomUUID(),\n username: player.username,\n text,\n };\n game.chatMessages.push(message);\n emitEvent(game, { type: \"chat\", message });\n return { success: true };\n }\n\n startGame(gameId: string, playerId: string): StartGameResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"created\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" };\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" };\n }\n const otherPlayer = game.players[1]!;\n const cards = [...CARDS];\n shuffleCards(cards);\n\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n\n player.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: player.username,\n numCards: player.drawPile.length,\n });\n\n player.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(player, { type: \"handInitialized\", cards: player.hand });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: player.username,\n numCards: player.hand.length,\n });\n\n otherPlayer.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.drawPile.length,\n });\n\n otherPlayer.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(otherPlayer, {\n type: \"handInitialized\",\n cards: otherPlayer.hand,\n });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.hand.length,\n });\n\n const startedGame: Game = {\n ...game,\n status: \"started\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS,\n };\n 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 };\n }\n}\n"],"mappings":"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"}
|
package/dist/server/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_manager = require("../manager-
|
|
2
|
+
const require_manager = require("../manager-C9oZYA47.cjs");
|
|
3
3
|
let zod = require("zod");
|
|
4
4
|
//#region src/server/Server.ts
|
|
5
5
|
const drawCardInputSchema = zod.z.object({
|
|
@@ -53,7 +53,7 @@ const startGameInputSchema = zod.z.object({
|
|
|
53
53
|
playerId: zod.z.string()
|
|
54
54
|
}).transform(({ gameId, playerId }) => [gameId, playerId]);
|
|
55
55
|
var Server = class {
|
|
56
|
-
manager
|
|
56
|
+
manager;
|
|
57
57
|
actions = [
|
|
58
58
|
{
|
|
59
59
|
path: "/createGame",
|
|
@@ -100,6 +100,9 @@ var Server = class {
|
|
|
100
100
|
action: this.startGame.bind(this)
|
|
101
101
|
}
|
|
102
102
|
];
|
|
103
|
+
constructor(...args) {
|
|
104
|
+
this.manager = new require_manager.Manager(...args);
|
|
105
|
+
}
|
|
103
106
|
createGame(userId, username) {
|
|
104
107
|
return this.manager.createGame(userId, username);
|
|
105
108
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["z","Manager"],"sources":["../../src/server/Server.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { Manager } from \"../manager/index.js\";\nimport type { ClientState, GameEvent } from \"../manager/index.js\";\n\nexport type CreateGameResult =\n | {\n readonly success: true;\n readonly gameId: string;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error: \"maxGamesReached\";\n };\n\nexport type DrawCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"handFull\"\n | \"drawPileEmpty\";\n };\n\nexport type GetClientStateAndClearEventsResult =\n | {\n readonly success: true;\n readonly state: ClientState;\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetEventsAndClearAcknowledgedResult =\n | {\n readonly success: true;\n readonly events: readonly GameEvent[];\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetJoinableGamesResult = {\n readonly games: readonly {\n readonly id: string;\n readonly numPlayers: number;\n }[];\n};\n\nexport type JoinGameResult =\n | {\n readonly success: true;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"maxPlayersReached\"\n | \"alreadyInGame\";\n };\n\nexport type LeaveGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type PlayCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"cardNotFound\"\n | \"cardNotPlayable\";\n };\n\nexport type ReportNoPlayableCardsResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"alreadyReported\"\n | \"hasPlayableCard\"\n | \"canDraw\";\n };\n\nexport type SendChatResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type StartGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"playerNotFound\"\n | \"playerNotAdmin\"\n | \"minPlayersNotReached\";\n };\n\nconst drawCardInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst getClientStateAndClearEventsInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst getEventsAndClearAcknowledgedInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n lastReadId: z.string().nullable(),\n })\n .transform(\n ({ gameId, playerId, lastReadId }) =>\n [gameId, playerId, lastReadId] as const,\n );\n\nconst joinGameInputSchema = z\n .object({\n gameId: z.string(),\n })\n .transform(({ gameId }) => [gameId] as const);\n\nconst leaveGameInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst 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\nconst reportNoPlayableCardsInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst sendChatInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n text: z.string(),\n })\n .transform(({ gameId, playerId, text }) => [gameId, playerId, text] as const);\n\nconst startGameInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nexport class Server {\n private readonly manager = new Manager();\n\n readonly actions = [\n { path: \"/createGame\", action: this.createGame.bind(this) },\n { path: \"/drawCard\", action: this.drawCard.bind(this) },\n {\n path: \"/getClientStateAndClearEvents\",\n action: this.getClientStateAndClearEvents.bind(this),\n },\n {\n path: \"/getEventsAndClearAcknowledged\",\n action: this.getEventsAndClearAcknowledged.bind(this),\n },\n { path: \"/getJoinableGames\", action: this.getJoinableGames.bind(this) },\n { path: \"/joinGame\", action: this.joinGame.bind(this) },\n { path: \"/leaveGame\", action: this.leaveGame.bind(this) },\n { path: \"/playCard\", action: this.playCard.bind(this) },\n {\n path: \"/reportNoPlayableCards\",\n action: this.reportNoPlayableCards.bind(this),\n },\n { path: \"/sendChat\", action: this.sendChat.bind(this) },\n { path: \"/startGame\", action: this.startGame.bind(this) },\n ] as const;\n\n private createGame(userId: string, username: string): CreateGameResult {\n return this.manager.createGame(userId, username);\n }\n\n private drawCard(input: unknown): DrawCardResult {\n const parseResult = drawCardInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.drawCard(...parseResult.data);\n }\n\n private getClientStateAndClearEvents(\n input: unknown,\n ): GetClientStateAndClearEventsResult {\n const parseResult =\n getClientStateAndClearEventsInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.getClientStateAndClearEvents(...parseResult.data);\n }\n\n private getEventsAndClearAcknowledged(\n input: unknown,\n ): GetEventsAndClearAcknowledgedResult {\n const parseResult =\n getEventsAndClearAcknowledgedInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.getEventsAndClearAcknowledged(...parseResult.data);\n }\n\n private getJoinableGames(): GetJoinableGamesResult {\n return this.manager.getJoinableGames();\n }\n\n private joinGame(\n input: unknown,\n userId: string,\n username: string,\n ): JoinGameResult {\n const parseResult = joinGameInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.joinGame(...parseResult.data, userId, username);\n }\n\n private leaveGame(input: unknown): LeaveGameResult {\n const parseResult = leaveGameInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.leaveGame(...parseResult.data);\n }\n\n private playCard(input: unknown): PlayCardResult {\n const parseResult = playCardInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.playCard(...parseResult.data);\n }\n\n private reportNoPlayableCards(input: unknown): ReportNoPlayableCardsResult {\n const parseResult = reportNoPlayableCardsInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.reportNoPlayableCards(...parseResult.data);\n }\n\n private sendChat(input: unknown): SendChatResult {\n const parseResult = sendChatInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.sendChat(...parseResult.data);\n }\n\n private startGame(input: unknown): StartGameResult {\n const parseResult = startGameInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.startGame(...parseResult.data);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["z","Manager"],"sources":["../../src/server/Server.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { Manager } from \"../manager/index.js\";\nimport type { ClientState, GameEvent } from \"../manager/index.js\";\n\nexport type CreateGameResult =\n | {\n readonly success: true;\n readonly gameId: string;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error: \"maxGamesReached\";\n };\n\nexport type DrawCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"handFull\"\n | \"drawPileEmpty\";\n };\n\nexport type GetClientStateAndClearEventsResult =\n | {\n readonly success: true;\n readonly state: ClientState;\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetEventsAndClearAcknowledgedResult =\n | {\n readonly success: true;\n readonly events: readonly GameEvent[];\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetJoinableGamesResult = {\n readonly games: readonly {\n readonly id: string;\n readonly numPlayers: number;\n }[];\n};\n\nexport type JoinGameResult =\n | {\n readonly success: true;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"maxPlayersReached\"\n | \"alreadyInGame\";\n };\n\nexport type LeaveGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type PlayCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"cardNotFound\"\n | \"cardNotPlayable\";\n };\n\nexport type ReportNoPlayableCardsResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"alreadyReported\"\n | \"hasPlayableCard\"\n | \"canDraw\";\n };\n\nexport type SendChatResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type StartGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"playerNotFound\"\n | \"playerNotAdmin\"\n | \"minPlayersNotReached\";\n };\n\nconst drawCardInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst getClientStateAndClearEventsInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst getEventsAndClearAcknowledgedInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n lastReadId: z.string().nullable(),\n })\n .transform(\n ({ gameId, playerId, lastReadId }) =>\n [gameId, playerId, lastReadId] as const,\n );\n\nconst joinGameInputSchema = z\n .object({\n gameId: z.string(),\n })\n .transform(({ gameId }) => [gameId] as const);\n\nconst leaveGameInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst 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\nconst reportNoPlayableCardsInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst sendChatInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n text: z.string(),\n })\n .transform(({ gameId, playerId, text }) => [gameId, playerId, text] as const);\n\nconst startGameInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nexport class Server {\n private readonly manager: Manager;\n\n readonly actions = [\n { path: \"/createGame\", action: this.createGame.bind(this) },\n { path: \"/drawCard\", action: this.drawCard.bind(this) },\n {\n path: \"/getClientStateAndClearEvents\",\n action: this.getClientStateAndClearEvents.bind(this),\n },\n {\n path: \"/getEventsAndClearAcknowledged\",\n action: this.getEventsAndClearAcknowledged.bind(this),\n },\n { path: \"/getJoinableGames\", action: this.getJoinableGames.bind(this) },\n { path: \"/joinGame\", action: this.joinGame.bind(this) },\n { path: \"/leaveGame\", action: this.leaveGame.bind(this) },\n { path: \"/playCard\", action: this.playCard.bind(this) },\n {\n path: \"/reportNoPlayableCards\",\n action: this.reportNoPlayableCards.bind(this),\n },\n { path: \"/sendChat\", action: this.sendChat.bind(this) },\n { path: \"/startGame\", action: this.startGame.bind(this) },\n ] as const;\n\n constructor(...args: ConstructorParameters<typeof Manager>) {\n this.manager = new Manager(...args);\n }\n\n private createGame(userId: string, username: string): CreateGameResult {\n return this.manager.createGame(userId, username);\n }\n\n private drawCard(input: unknown): DrawCardResult {\n const parseResult = drawCardInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.drawCard(...parseResult.data);\n }\n\n private getClientStateAndClearEvents(\n input: unknown,\n ): GetClientStateAndClearEventsResult {\n const parseResult =\n getClientStateAndClearEventsInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.getClientStateAndClearEvents(...parseResult.data);\n }\n\n private getEventsAndClearAcknowledged(\n input: unknown,\n ): GetEventsAndClearAcknowledgedResult {\n const parseResult =\n getEventsAndClearAcknowledgedInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.getEventsAndClearAcknowledged(...parseResult.data);\n }\n\n private getJoinableGames(): GetJoinableGamesResult {\n return this.manager.getJoinableGames();\n }\n\n private joinGame(\n input: unknown,\n userId: string,\n username: string,\n ): JoinGameResult {\n const parseResult = joinGameInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.joinGame(...parseResult.data, userId, username);\n }\n\n private leaveGame(input: unknown): LeaveGameResult {\n const parseResult = leaveGameInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.leaveGame(...parseResult.data);\n }\n\n private playCard(input: unknown): PlayCardResult {\n const parseResult = playCardInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.playCard(...parseResult.data);\n }\n\n private reportNoPlayableCards(input: unknown): ReportNoPlayableCardsResult {\n const parseResult = reportNoPlayableCardsInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.reportNoPlayableCards(...parseResult.data);\n }\n\n private sendChat(input: unknown): SendChatResult {\n const parseResult = sendChatInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.sendChat(...parseResult.data);\n }\n\n private startGame(input: unknown): StartGameResult {\n const parseResult = startGameInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.startGame(...parseResult.data);\n }\n}\n"],"mappings":"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"}
|
package/dist/server/index.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { g as Card, h as ChatMessage, m as ClientState, p as GameEvent } from "../index-
|
|
2
|
-
import { a as GetJoinableGamesResult, c as PlayCardResult, d as Server, f as StartGameResult, i as GetEventsAndClearAcknowledgedResult, l as ReportNoPlayableCardsResult, n as DrawCardResult, o as JoinGameResult, r as GetClientStateAndClearEventsResult, s as LeaveGameResult, t as CreateGameResult, u as SendChatResult } from "../index-
|
|
1
|
+
import { g as Card, h as ChatMessage, m as ClientState, p as GameEvent } from "../index-uaOvIhKT.cjs";
|
|
2
|
+
import { a as GetJoinableGamesResult, c as PlayCardResult, d as Server, f as StartGameResult, i as GetEventsAndClearAcknowledgedResult, l as ReportNoPlayableCardsResult, n as DrawCardResult, o as JoinGameResult, r as GetClientStateAndClearEventsResult, s as LeaveGameResult, t as CreateGameResult, u as SendChatResult } from "../index-NySusLtY.cjs";
|
|
3
3
|
export { type Card, type ChatMessage, type ClientState, type CreateGameResult, type DrawCardResult, type GameEvent, type GetClientStateAndClearEventsResult, type GetEventsAndClearAcknowledgedResult, type GetJoinableGamesResult, type JoinGameResult, type LeaveGameResult, type PlayCardResult, type ReportNoPlayableCardsResult, type SendChatResult, Server, type StartGameResult };
|
package/dist/server/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { g as Card, h as ChatMessage, m as ClientState, p as GameEvent } from "../index-
|
|
2
|
-
import { a as GetJoinableGamesResult, c as PlayCardResult, d as Server, f as StartGameResult, i as GetEventsAndClearAcknowledgedResult, l as ReportNoPlayableCardsResult, n as DrawCardResult, o as JoinGameResult, r as GetClientStateAndClearEventsResult, s as LeaveGameResult, t as CreateGameResult, u as SendChatResult } from "../index-
|
|
1
|
+
import { g as Card, h as ChatMessage, m as ClientState, p as GameEvent } from "../index-uaOvIhKT.mjs";
|
|
2
|
+
import { a as GetJoinableGamesResult, c as PlayCardResult, d as Server, f as StartGameResult, i as GetEventsAndClearAcknowledgedResult, l as ReportNoPlayableCardsResult, n as DrawCardResult, o as JoinGameResult, r as GetClientStateAndClearEventsResult, s as LeaveGameResult, t as CreateGameResult, u as SendChatResult } from "../index-C5bT1Zzd.mjs";
|
|
3
3
|
export { type Card, type ChatMessage, type ClientState, type CreateGameResult, type DrawCardResult, type GameEvent, type GetClientStateAndClearEventsResult, type GetEventsAndClearAcknowledgedResult, type GetJoinableGamesResult, type JoinGameResult, type LeaveGameResult, type PlayCardResult, type ReportNoPlayableCardsResult, type SendChatResult, Server, type StartGameResult };
|
package/dist/server/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as Manager } from "../manager-
|
|
1
|
+
import { t as Manager } from "../manager-BAxBCUOk.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
//#region src/server/Server.ts
|
|
4
4
|
const drawCardInputSchema = z.object({
|
|
@@ -52,7 +52,7 @@ const startGameInputSchema = z.object({
|
|
|
52
52
|
playerId: z.string()
|
|
53
53
|
}).transform(({ gameId, playerId }) => [gameId, playerId]);
|
|
54
54
|
var Server = class {
|
|
55
|
-
manager
|
|
55
|
+
manager;
|
|
56
56
|
actions = [
|
|
57
57
|
{
|
|
58
58
|
path: "/createGame",
|
|
@@ -99,6 +99,9 @@ var Server = class {
|
|
|
99
99
|
action: this.startGame.bind(this)
|
|
100
100
|
}
|
|
101
101
|
];
|
|
102
|
+
constructor(...args) {
|
|
103
|
+
this.manager = new Manager(...args);
|
|
104
|
+
}
|
|
102
105
|
createGame(userId, username) {
|
|
103
106
|
return this.manager.createGame(userId, username);
|
|
104
107
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/server/Server.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { Manager } from \"../manager/index.js\";\nimport type { ClientState, GameEvent } from \"../manager/index.js\";\n\nexport type CreateGameResult =\n | {\n readonly success: true;\n readonly gameId: string;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error: \"maxGamesReached\";\n };\n\nexport type DrawCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"handFull\"\n | \"drawPileEmpty\";\n };\n\nexport type GetClientStateAndClearEventsResult =\n | {\n readonly success: true;\n readonly state: ClientState;\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetEventsAndClearAcknowledgedResult =\n | {\n readonly success: true;\n readonly events: readonly GameEvent[];\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetJoinableGamesResult = {\n readonly games: readonly {\n readonly id: string;\n readonly numPlayers: number;\n }[];\n};\n\nexport type JoinGameResult =\n | {\n readonly success: true;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"maxPlayersReached\"\n | \"alreadyInGame\";\n };\n\nexport type LeaveGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type PlayCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"cardNotFound\"\n | \"cardNotPlayable\";\n };\n\nexport type ReportNoPlayableCardsResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"alreadyReported\"\n | \"hasPlayableCard\"\n | \"canDraw\";\n };\n\nexport type SendChatResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type StartGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"playerNotFound\"\n | \"playerNotAdmin\"\n | \"minPlayersNotReached\";\n };\n\nconst drawCardInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst getClientStateAndClearEventsInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst getEventsAndClearAcknowledgedInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n lastReadId: z.string().nullable(),\n })\n .transform(\n ({ gameId, playerId, lastReadId }) =>\n [gameId, playerId, lastReadId] as const,\n );\n\nconst joinGameInputSchema = z\n .object({\n gameId: z.string(),\n })\n .transform(({ gameId }) => [gameId] as const);\n\nconst leaveGameInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst 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\nconst reportNoPlayableCardsInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst sendChatInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n text: z.string(),\n })\n .transform(({ gameId, playerId, text }) => [gameId, playerId, text] as const);\n\nconst startGameInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nexport class Server {\n private readonly manager = new Manager();\n\n readonly actions = [\n { path: \"/createGame\", action: this.createGame.bind(this) },\n { path: \"/drawCard\", action: this.drawCard.bind(this) },\n {\n path: \"/getClientStateAndClearEvents\",\n action: this.getClientStateAndClearEvents.bind(this),\n },\n {\n path: \"/getEventsAndClearAcknowledged\",\n action: this.getEventsAndClearAcknowledged.bind(this),\n },\n { path: \"/getJoinableGames\", action: this.getJoinableGames.bind(this) },\n { path: \"/joinGame\", action: this.joinGame.bind(this) },\n { path: \"/leaveGame\", action: this.leaveGame.bind(this) },\n { path: \"/playCard\", action: this.playCard.bind(this) },\n {\n path: \"/reportNoPlayableCards\",\n action: this.reportNoPlayableCards.bind(this),\n },\n { path: \"/sendChat\", action: this.sendChat.bind(this) },\n { path: \"/startGame\", action: this.startGame.bind(this) },\n ] as const;\n\n private createGame(userId: string, username: string): CreateGameResult {\n return this.manager.createGame(userId, username);\n }\n\n private drawCard(input: unknown): DrawCardResult {\n const parseResult = drawCardInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.drawCard(...parseResult.data);\n }\n\n private getClientStateAndClearEvents(\n input: unknown,\n ): GetClientStateAndClearEventsResult {\n const parseResult =\n getClientStateAndClearEventsInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.getClientStateAndClearEvents(...parseResult.data);\n }\n\n private getEventsAndClearAcknowledged(\n input: unknown,\n ): GetEventsAndClearAcknowledgedResult {\n const parseResult =\n getEventsAndClearAcknowledgedInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.getEventsAndClearAcknowledged(...parseResult.data);\n }\n\n private getJoinableGames(): GetJoinableGamesResult {\n return this.manager.getJoinableGames();\n }\n\n private joinGame(\n input: unknown,\n userId: string,\n username: string,\n ): JoinGameResult {\n const parseResult = joinGameInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.joinGame(...parseResult.data, userId, username);\n }\n\n private leaveGame(input: unknown): LeaveGameResult {\n const parseResult = leaveGameInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.leaveGame(...parseResult.data);\n }\n\n private playCard(input: unknown): PlayCardResult {\n const parseResult = playCardInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.playCard(...parseResult.data);\n }\n\n private reportNoPlayableCards(input: unknown): ReportNoPlayableCardsResult {\n const parseResult = reportNoPlayableCardsInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.reportNoPlayableCards(...parseResult.data);\n }\n\n private sendChat(input: unknown): SendChatResult {\n const parseResult = sendChatInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.sendChat(...parseResult.data);\n }\n\n private startGame(input: unknown): StartGameResult {\n const parseResult = startGameInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.startGame(...parseResult.data);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/server/Server.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { Manager } from \"../manager/index.js\";\nimport type { ClientState, GameEvent } from \"../manager/index.js\";\n\nexport type CreateGameResult =\n | {\n readonly success: true;\n readonly gameId: string;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error: \"maxGamesReached\";\n };\n\nexport type DrawCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"handFull\"\n | \"drawPileEmpty\";\n };\n\nexport type GetClientStateAndClearEventsResult =\n | {\n readonly success: true;\n readonly state: ClientState;\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetEventsAndClearAcknowledgedResult =\n | {\n readonly success: true;\n readonly events: readonly GameEvent[];\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetJoinableGamesResult = {\n readonly games: readonly {\n readonly id: string;\n readonly numPlayers: number;\n }[];\n};\n\nexport type JoinGameResult =\n | {\n readonly success: true;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"maxPlayersReached\"\n | \"alreadyInGame\";\n };\n\nexport type LeaveGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type PlayCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"cardNotFound\"\n | \"cardNotPlayable\";\n };\n\nexport type ReportNoPlayableCardsResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"alreadyReported\"\n | \"hasPlayableCard\"\n | \"canDraw\";\n };\n\nexport type SendChatResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"invalidInput\" | \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type StartGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"invalidInput\"\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"playerNotFound\"\n | \"playerNotAdmin\"\n | \"minPlayersNotReached\";\n };\n\nconst drawCardInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst getClientStateAndClearEventsInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst getEventsAndClearAcknowledgedInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n lastReadId: z.string().nullable(),\n })\n .transform(\n ({ gameId, playerId, lastReadId }) =>\n [gameId, playerId, lastReadId] as const,\n );\n\nconst joinGameInputSchema = z\n .object({\n gameId: z.string(),\n })\n .transform(({ gameId }) => [gameId] as const);\n\nconst leaveGameInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst 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\nconst reportNoPlayableCardsInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nconst sendChatInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n text: z.string(),\n })\n .transform(({ gameId, playerId, text }) => [gameId, playerId, text] as const);\n\nconst startGameInputSchema = z\n .object({\n gameId: z.string(),\n playerId: z.string(),\n })\n .transform(({ gameId, playerId }) => [gameId, playerId] as const);\n\nexport class Server {\n private readonly manager: Manager;\n\n readonly actions = [\n { path: \"/createGame\", action: this.createGame.bind(this) },\n { path: \"/drawCard\", action: this.drawCard.bind(this) },\n {\n path: \"/getClientStateAndClearEvents\",\n action: this.getClientStateAndClearEvents.bind(this),\n },\n {\n path: \"/getEventsAndClearAcknowledged\",\n action: this.getEventsAndClearAcknowledged.bind(this),\n },\n { path: \"/getJoinableGames\", action: this.getJoinableGames.bind(this) },\n { path: \"/joinGame\", action: this.joinGame.bind(this) },\n { path: \"/leaveGame\", action: this.leaveGame.bind(this) },\n { path: \"/playCard\", action: this.playCard.bind(this) },\n {\n path: \"/reportNoPlayableCards\",\n action: this.reportNoPlayableCards.bind(this),\n },\n { path: \"/sendChat\", action: this.sendChat.bind(this) },\n { path: \"/startGame\", action: this.startGame.bind(this) },\n ] as const;\n\n constructor(...args: ConstructorParameters<typeof Manager>) {\n this.manager = new Manager(...args);\n }\n\n private createGame(userId: string, username: string): CreateGameResult {\n return this.manager.createGame(userId, username);\n }\n\n private drawCard(input: unknown): DrawCardResult {\n const parseResult = drawCardInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.drawCard(...parseResult.data);\n }\n\n private getClientStateAndClearEvents(\n input: unknown,\n ): GetClientStateAndClearEventsResult {\n const parseResult =\n getClientStateAndClearEventsInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.getClientStateAndClearEvents(...parseResult.data);\n }\n\n private getEventsAndClearAcknowledged(\n input: unknown,\n ): GetEventsAndClearAcknowledgedResult {\n const parseResult =\n getEventsAndClearAcknowledgedInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.getEventsAndClearAcknowledged(...parseResult.data);\n }\n\n private getJoinableGames(): GetJoinableGamesResult {\n return this.manager.getJoinableGames();\n }\n\n private joinGame(\n input: unknown,\n userId: string,\n username: string,\n ): JoinGameResult {\n const parseResult = joinGameInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.joinGame(...parseResult.data, userId, username);\n }\n\n private leaveGame(input: unknown): LeaveGameResult {\n const parseResult = leaveGameInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.leaveGame(...parseResult.data);\n }\n\n private playCard(input: unknown): PlayCardResult {\n const parseResult = playCardInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.playCard(...parseResult.data);\n }\n\n private reportNoPlayableCards(input: unknown): ReportNoPlayableCardsResult {\n const parseResult = reportNoPlayableCardsInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.reportNoPlayableCards(...parseResult.data);\n }\n\n private sendChat(input: unknown): SendChatResult {\n const parseResult = sendChatInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.sendChat(...parseResult.data);\n }\n\n private startGame(input: unknown): StartGameResult {\n const parseResult = startGameInputSchema.safeParse(input);\n if (!parseResult.success) {\n return { success: false, error: \"invalidInput\" };\n }\n return this.manager.startGame(...parseResult.data);\n }\n}\n"],"mappings":";;;AA2IA,MAAM,sBAAsB,EACzB,OAAO;CACN,QAAQ,EAAE,OAAO;CACjB,UAAU,EAAE,OAAO;AACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;AAElE,MAAM,0CAA0C,EAC7C,OAAO;CACN,QAAQ,EAAE,OAAO;CACjB,UAAU,EAAE,OAAO;AACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;AAElE,MAAM,2CAA2C,EAC9C,OAAO;CACN,QAAQ,EAAE,OAAO;CACjB,UAAU,EAAE,OAAO;CACnB,YAAY,EAAE,OAAO,CAAC,CAAC,SAAS;AAClC,CAAC,CAAC,CACD,WACE,EAAE,QAAQ,UAAU,iBACnB;CAAC;CAAQ;CAAU;AAAU,CACjC;AAEF,MAAM,sBAAsB,EACzB,OAAO,EACN,QAAQ,EAAE,OAAO,EACnB,CAAC,CAAC,CACD,WAAW,EAAE,aAAa,CAAC,MAAM,CAAU;AAE9C,MAAM,uBAAuB,EAC1B,OAAO;CACN,QAAQ,EAAE,OAAO;CACjB,UAAU,EAAE,OAAO;AACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;AAElE,MAAM,sBAAsB,EACzB,OAAO;CACN,QAAQ,EAAE,OAAO;CACjB,UAAU,EAAE,OAAO;CACnB,QAAQ,EAAE,OAAO;CACjB,sBAAsB,EAAE,QAAQ;AAClC,CAAC,CAAC,CACD,WACE,EAAE,QAAQ,UAAU,QAAQ,2BAC3B;CAAC;CAAQ;CAAU;CAAQ;AAAoB,CACnD;AAEF,MAAM,mCAAmC,EACtC,OAAO;CACN,QAAQ,EAAE,OAAO;CACjB,UAAU,EAAE,OAAO;AACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;AAElE,MAAM,sBAAsB,EACzB,OAAO;CACN,QAAQ,EAAE,OAAO;CACjB,UAAU,EAAE,OAAO;CACnB,MAAM,EAAE,OAAO;AACjB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,UAAU,WAAW;CAAC;CAAQ;CAAU;AAAI,CAAU;AAE9E,MAAM,uBAAuB,EAC1B,OAAO;CACN,QAAQ,EAAE,OAAO;CACjB,UAAU,EAAE,OAAO;AACrB,CAAC,CAAC,CACD,WAAW,EAAE,QAAQ,eAAe,CAAC,QAAQ,QAAQ,CAAU;AAElE,IAAa,SAAb,MAAoB;CAClB;CAEA,UAAmB;EACjB;GAAE,MAAM;GAAe,QAAQ,KAAK,WAAW,KAAK,IAAI;EAAE;EAC1D;GAAE,MAAM;GAAa,QAAQ,KAAK,SAAS,KAAK,IAAI;EAAE;EACtD;GACE,MAAM;GACN,QAAQ,KAAK,6BAA6B,KAAK,IAAI;EACrD;EACA;GACE,MAAM;GACN,QAAQ,KAAK,8BAA8B,KAAK,IAAI;EACtD;EACA;GAAE,MAAM;GAAqB,QAAQ,KAAK,iBAAiB,KAAK,IAAI;EAAE;EACtE;GAAE,MAAM;GAAa,QAAQ,KAAK,SAAS,KAAK,IAAI;EAAE;EACtD;GAAE,MAAM;GAAc,QAAQ,KAAK,UAAU,KAAK,IAAI;EAAE;EACxD;GAAE,MAAM;GAAa,QAAQ,KAAK,SAAS,KAAK,IAAI;EAAE;EACtD;GACE,MAAM;GACN,QAAQ,KAAK,sBAAsB,KAAK,IAAI;EAC9C;EACA;GAAE,MAAM;GAAa,QAAQ,KAAK,SAAS,KAAK,IAAI;EAAE;EACtD;GAAE,MAAM;GAAc,QAAQ,KAAK,UAAU,KAAK,IAAI;EAAE;CAC1D;CAEA,YAAY,GAAG,MAA6C;EAC1D,KAAK,UAAU,IAAI,QAAQ,GAAG,IAAI;CACpC;CAEA,WAAmB,QAAgB,UAAoC;EACrE,OAAO,KAAK,QAAQ,WAAW,QAAQ,QAAQ;CACjD;CAEA,SAAiB,OAAgC;EAC/C,MAAM,cAAc,oBAAoB,UAAU,KAAK;EACvD,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,KAAK,QAAQ,SAAS,GAAG,YAAY,IAAI;CAClD;CAEA,6BACE,OACoC;EACpC,MAAM,cACJ,wCAAwC,UAAU,KAAK;EACzD,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,KAAK,QAAQ,6BAA6B,GAAG,YAAY,IAAI;CACtE;CAEA,8BACE,OACqC;EACrC,MAAM,cACJ,yCAAyC,UAAU,KAAK;EAC1D,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,KAAK,QAAQ,8BAA8B,GAAG,YAAY,IAAI;CACvE;CAEA,mBAAmD;EACjD,OAAO,KAAK,QAAQ,iBAAiB;CACvC;CAEA,SACE,OACA,QACA,UACgB;EAChB,MAAM,cAAc,oBAAoB,UAAU,KAAK;EACvD,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,KAAK,QAAQ,SAAS,GAAG,YAAY,MAAM,QAAQ,QAAQ;CACpE;CAEA,UAAkB,OAAiC;EACjD,MAAM,cAAc,qBAAqB,UAAU,KAAK;EACxD,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,KAAK,QAAQ,UAAU,GAAG,YAAY,IAAI;CACnD;CAEA,SAAiB,OAAgC;EAC/C,MAAM,cAAc,oBAAoB,UAAU,KAAK;EACvD,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,KAAK,QAAQ,SAAS,GAAG,YAAY,IAAI;CAClD;CAEA,sBAA8B,OAA6C;EACzE,MAAM,cAAc,iCAAiC,UAAU,KAAK;EACpE,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,KAAK,QAAQ,sBAAsB,GAAG,YAAY,IAAI;CAC/D;CAEA,SAAiB,OAAgC;EAC/C,MAAM,cAAc,oBAAoB,UAAU,KAAK;EACvD,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,KAAK,QAAQ,SAAS,GAAG,YAAY,IAAI;CAClD;CAEA,UAAkB,OAAiC;EACjD,MAAM,cAAc,qBAAqB,UAAU,KAAK;EACxD,IAAI,CAAC,YAAY,SACf,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;EAEjD,OAAO,KAAK,QAAQ,UAAU,GAAG,YAAY,IAAI;CACnD;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hellacardgames/speed",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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.
|
|
89
|
+
"@hellacardgames/lib": "^0.6.1",
|
|
90
90
|
"zod": "^4.4.3"
|
|
91
91
|
}
|
|
92
92
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-YAYbNr-s.d.cts","names":[],"sources":["../src/manager/types/Card.ts","../src/manager/types/ChatMessage.ts","../src/manager/types/ClientState.ts","../src/manager/types/GameEvent.ts","../src/manager/Manager.ts"],"mappings":";KAAY;WACD;WACA;WACA;;;;KCHC;WACD;WACA;WACA;;;;KCAC;WACD;WACA;WACA;WACA;WACA,kBAAkB;WAClB;WACA,uBAAuB;WACvB,eAAe;WACf;;KAGN;WACM;WACA;WACA;WACA;WACA,mBAAmB;;;;KCjBlB;WAEG;WACA;WACA;;WAGA;WACA;WACA;WACA,MAAM;;WAGN;WACA;WACA;WACA,MAAM;WACN;;WAGA;WACA;WACA,SAAS;;WAGT;WACA;WACA,MAAM;;WAGN;WACA;WACA;;WAGA;WACA;;WAGA;WACA;;WAGA;WACA;;WAGA;WACA;WACA,gBAAgB;;WAGhB;WACA;WACA;WACA,MAAM;;WAGN;WACA;WACA;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;;;;KCtEH;WAEG;WACA;WACA;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;KASH;WAEG;WACA,OAAO;;WAGP;WACA;;KAGH;WAEG;WACA,iBAAiB;;WAGjB;WACA;;KAGH;WACD;aACE;aACA;;;KAID;WAEG;WACA;;WAGA;WACA;;KAOH;WAEG;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;KASH;WAEG;;WAGA;WACA;;KAUH;WAEG;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;cAQF;mBACM;mBACA;;EAQjB,WAAW,gBAAgB,mBAAmB;EA4B9C,SAAS,gBAAgB,mBAAmB;EA8B5C,6BACE,gBACA,mBACC;EAgCH,8BACE,gBACA,kBACA,4BACC;EAgBH,oBAAoB;EAWpB,SAAS,gBAAgB,gBAAgB,mBAAmB;EA8B5D,UAAU,gBAAgB,mBAAmB;EAkC7C,SACE,gBACA,kBACA,gBACA,gCACC;EAwDH,sBACE,gBACA,mBACC;EAuFH,SAAS,gBAAgB,kBAAkB,eAAe;EAmB1D,UAAU,gBAAgB,mBAAmB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-YAYbNr-s.d.mts","names":[],"sources":["../src/manager/types/Card.ts","../src/manager/types/ChatMessage.ts","../src/manager/types/ClientState.ts","../src/manager/types/GameEvent.ts","../src/manager/Manager.ts"],"mappings":";KAAY;WACD;WACA;WACA;;;;KCHC;WACD;WACA;WACA;;;;KCAC;WACD;WACA;WACA;WACA;WACA,kBAAkB;WAClB;WACA,uBAAuB;WACvB,eAAe;WACf;;KAGN;WACM;WACA;WACA;WACA;WACA,mBAAmB;;;;KCjBlB;WAEG;WACA;WACA;;WAGA;WACA;WACA;WACA,MAAM;;WAGN;WACA;WACA;WACA,MAAM;WACN;;WAGA;WACA;WACA,SAAS;;WAGT;WACA;WACA,MAAM;;WAGN;WACA;WACA;;WAGA;WACA;;WAGA;WACA;;WAGA;WACA;;WAGA;WACA;WACA,gBAAgB;;WAGhB;WACA;WACA;WACA,MAAM;;WAGN;WACA;WACA;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;;;;KCtEH;WAEG;WACA;WACA;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;KASH;WAEG;WACA,OAAO;;WAGP;WACA;;KAGH;WAEG;WACA,iBAAiB;;WAGjB;WACA;;KAGH;WACD;aACE;aACA;;;KAID;WAEG;WACA;;WAGA;WACA;;KAOH;WAEG;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;KASH;WAEG;;WAGA;WACA;;KAUH;WAEG;;WAGA;WACA;;KAGH;WAEG;;WAGA;WACA;;cAQF;mBACM;mBACA;;EAQjB,WAAW,gBAAgB,mBAAmB;EA4B9C,SAAS,gBAAgB,mBAAmB;EA8B5C,6BACE,gBACA,mBACC;EAgCH,8BACE,gBACA,kBACA,4BACC;EAgBH,oBAAoB;EAWpB,SAAS,gBAAgB,gBAAgB,mBAAmB;EA8B5D,UAAU,gBAAgB,mBAAmB;EAkC7C,SACE,gBACA,kBACA,gBACA,gCACC;EAwDH,sBACE,gBACA,mBACC;EAuFH,SAAS,gBAAgB,kBAAkB,eAAe;EAmB1D,UAAU,gBAAgB,mBAAmB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manager-BOymBQ4E.mjs","names":[],"sources":["../src/manager/constants.ts","../src/manager/Watchdog.ts","../src/lib/emitEvent.ts","../src/lib/emitEventToPlayer.ts","../src/manager/lib/isCardPlayable.ts","../src/manager/lib/hasPlayableCard.ts","../src/lib/shuffleCards.ts","../src/manager/Manager.ts"],"sourcesContent":["import type { Card } from \"./types/Card.js\";\n\nexport const GAME_KEY = \"speed\";\nexport const MAX_GAMES = 50;\nexport const WATCHDOG_INTERVAL_MS = 10000;\n\nexport const EXPIRY_EXTENSION_MS = 300000; // 5 minutes\nexport const MIN_PLAYERS = 2;\nexport const MAX_PLAYERS = 2;\nexport const MAX_HAND_SIZE = 5;\nexport const CAN_PLAY_AT_DELAY_MS = 3000;\n\nexport const CARDS: readonly Card[] = [\n { id: crypto.randomUUID(), rank: 2, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"spades\" },\n];\n","import { GAME_KEY, WATCHDOG_INTERVAL_MS } from \"./constants.js\";\n\ntype Game = {\n readonly id: string;\n readonly expiresAt: number;\n};\n\nexport class Watchdog<TGame extends Game> {\n private readonly games: Map<string, TGame>;\n\n constructor(games: Map<string, TGame>) {\n this.games = games;\n }\n\n start() {\n console.log(`watchdog start at ${Date.now()} (${GAME_KEY})`);\n setInterval(() => this.wakeUp(), WATCHDOG_INTERVAL_MS);\n }\n\n wakeUp() {\n const now = Date.now();\n // console.log(`watchdog wakeUp at ${now} (${GAME_KEY})`);\n for (const game of this.games.values()) {\n if (game.expiresAt <= now) {\n this.games.delete(game.id);\n console.log(`watchdog purged ${game.id} (${GAME_KEY})`);\n }\n }\n }\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 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","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 {\n CAN_PLAY_AT_DELAY_MS,\n CARDS,\n EXPIRY_EXTENSION_MS,\n MAX_GAMES,\n MAX_HAND_SIZE,\n MAX_PLAYERS,\n MIN_PLAYERS,\n} from \"./constants.js\";\nimport { Watchdog } from \"./Watchdog.js\";\nimport { emitEvent } from \"../lib/emitEvent.js\";\nimport { emitEventToPlayer } from \"../lib/emitEventToPlayer.js\";\nimport { isCardPlayable } from \"./lib/isCardPlayable.js\";\nimport { hasPlayableCard } from \"./lib/hasPlayableCard.js\";\nimport { shuffleCards } from \"../lib/shuffleCards.js\";\nimport type { ChatMessage } from \"./types/ChatMessage.js\";\nimport type { ClientState } from \"./types/ClientState.js\";\nimport type { Game } from \"./types/Game.js\";\nimport type { GameEvent } from \"./types/GameEvent.js\";\nimport type { Player } from \"./types/Player.js\";\n\nexport type CreateGameResult =\n | {\n readonly success: true;\n readonly gameId: string;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error: \"maxGamesReached\";\n };\n\nexport type DrawCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"handFull\"\n | \"drawPileEmpty\";\n };\n\nexport type GetClientStateAndClearEventsResult =\n | {\n readonly success: true;\n readonly state: ClientState;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetEventsAndClearAcknowledgedResult =\n | {\n readonly success: true;\n readonly events: readonly GameEvent[];\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetJoinableGamesResult = {\n readonly games: readonly {\n readonly id: string;\n readonly numPlayers: number;\n }[];\n};\n\nexport type JoinGameResult =\n | {\n readonly success: true;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"maxPlayersReached\"\n | \"alreadyInGame\";\n };\n\nexport type LeaveGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type PlayCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"cardNotFound\"\n | \"cardNotPlayable\";\n };\n\nexport type ReportNoPlayableCardsResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"alreadyReported\"\n | \"hasPlayableCard\"\n | \"canDraw\";\n };\n\nexport type SendChatResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type StartGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"playerNotFound\"\n | \"playerNotAdmin\"\n | \"minPlayersNotReached\";\n };\n\nexport class Manager {\n private readonly games: Map<string, Game>;\n private readonly watchdog: Watchdog<Game>;\n\n constructor() {\n this.games = new Map<string, Game>();\n this.watchdog = new Watchdog(this.games);\n this.watchdog.start();\n }\n\n createGame(userId: string, username: string): CreateGameResult {\n if (this.games.size === MAX_GAMES) {\n return { success: false, error: \"maxGamesReached\" };\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n const createdAt = Date.now();\n const game: Game = {\n status: \"open\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n };\n this.games.set(game.id, game);\n return { success: true, gameId: game.id, playerId: player.id };\n }\n\n drawCard(gameId: string, playerId: string): DrawCardResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" };\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" };\n }\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n const card = player.drawPile.pop()!;\n player.hand.push(card);\n emitEventToPlayer(player, { type: \"drewCard\", card });\n emitEvent(game, { type: \"playerDrewCard\", username: player.username });\n return { success: true };\n }\n\n getClientStateAndClearEvents(\n gameId: string,\n playerId: string,\n ): GetClientStateAndClearEventsResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const state: ClientState = {\n status: game.status,\n gameId,\n playerId,\n username: player.username,\n players: game.players.map((p) => ({\n username: p.username,\n handSize: p.hand.length,\n drawPileSize: p.drawPile.length,\n sidePileSize: p.sidePile.length,\n centerPileTopCard: p.centerPile.length\n ? p.centerPile[p.centerPile.length - 1]!\n : null,\n })),\n expiresAt: game.expiresAt,\n chatMessages: game.chatMessages,\n hand: player.hand,\n canPlayAt: game.status === \"started\" ? game.canPlayAt : null,\n };\n player.events.length = 0;\n return { success: true, state };\n }\n\n getEventsAndClearAcknowledged(\n gameId: string,\n playerId: string,\n lastReadId: string | null,\n ): GetEventsAndClearAcknowledgedResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const lastReadEventIndex = player.events.findIndex(\n (e) => e.id === lastReadId,\n );\n player.events.splice(0, lastReadEventIndex + 1);\n return { success: true, events: player.events };\n }\n\n getJoinableGames(): GetJoinableGamesResult {\n return {\n games: Array.from(this.games.values())\n .filter((g) => g.status === \"open\" && g.players.length < MAX_PLAYERS)\n .map((g) => ({\n id: g.id,\n numPlayers: g.players.length,\n })),\n };\n }\n\n joinGame(gameId: string, userId: string, username: string): JoinGameResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n if (game.status !== \"open\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" };\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" };\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n game.players.push(player);\n emitEvent(game, { type: \"playerJoined\", username });\n return { success: true, playerId: player.id };\n }\n\n leaveGame(gameId: string, playerId: string): LeaveGameResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const playerIndex = game.players.findIndex((p) => p.id === playerId);\n if (playerIndex === -1) {\n return { success: false, error: \"playerNotFound\" };\n }\n\n const player = game.players[playerIndex]!;\n emitEvent(game, { type: \"playerLeft\", username: player.username });\n\n game.players.splice(playerIndex, 1);\n\n if (game.status === \"started\" && game.players.length < MIN_PLAYERS) {\n const forfeitedGame: Game = {\n ...game,\n status: \"forfeited\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n };\n this.games.set(game.id, forfeitedGame);\n emitEvent(forfeitedGame, { type: \"gameForfeited\" });\n emitEvent(forfeitedGame, {\n type: \"expirationUpdated\",\n expiresAt: forfeitedGame.expiresAt,\n });\n }\n if (game.players.length === 0) {\n this.games.delete(game.id);\n }\n return { success: true };\n }\n\n playCard(\n gameId: string,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n ): PlayCardResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n const cardIndex = player.hand.findIndex((c) => c.id === cardId);\n if (cardIndex === -1) {\n return { success: false, error: \"cardNotFound\" };\n }\n const otherPlayer = game.players.find((p) => p !== player)!;\n const targetPile = isForOtherPlayerPile\n ? otherPlayer.centerPile\n : player.centerPile;\n const card = player.hand[cardIndex]!;\n if (!isCardPlayable(card, targetPile)) {\n return { success: false, error: \"cardNotPlayable\" };\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hand.splice(cardIndex, 1);\n targetPile.push(card);\n emitEvent(game, {\n type: \"cardPlayed\",\n username: player.username,\n card,\n isForOtherPlayerPile,\n });\n\n if (otherPlayer.hasNoPlayableCards && hasPlayableCard(otherPlayer, game)) {\n otherPlayer.hasNoPlayableCards = false;\n }\n\n if (player.hand.length === 0 && player.drawPile.length === 0) {\n emitEvent(game, { type: \"gameCompleted\" });\n const completedGame: Game = {\n ...game,\n status: \"completed\",\n };\n this.games.set(game.id, completedGame);\n }\n\n return { success: true };\n }\n\n reportNoPlayableCards(\n gameId: string,\n playerId: string,\n ): ReportNoPlayableCardsResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" };\n }\n if (hasPlayableCard(player, game)) {\n return { success: false, error: \"hasPlayableCard\" };\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" };\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hasNoPlayableCards = true;\n\n const otherPlayer = game.players.find((p) => p !== player)!;\n if (otherPlayer.hasNoPlayableCards) {\n if (player.sidePile.length === 0 && otherPlayer.sidePile.length === 0) {\n const cards = [...player.centerPile, ...otherPlayer.centerPile];\n shuffleCards(cards);\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n } else {\n const playerSidePileCard = player.sidePile.pop()!;\n player.centerPile.push(playerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: player.username,\n card: playerSidePileCard,\n });\n const otherPlayerSidePileCard = otherPlayer.sidePile.pop()!;\n otherPlayer.centerPile.push(otherPlayerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: otherPlayer.username,\n card: otherPlayerSidePileCard,\n });\n }\n player.hasNoPlayableCards = false;\n otherPlayer.hasNoPlayableCards = false;\n game.canPlayAt = Date.now() + CAN_PLAY_AT_DELAY_MS;\n emitEvent(game, {\n type: \"canPlayAtUpdated\",\n canPlayAt: game.canPlayAt,\n });\n }\n\n return { success: true };\n }\n\n sendChat(gameId: string, playerId: string, text: string): SendChatResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const message: ChatMessage = {\n id: crypto.randomUUID(),\n username: player.username,\n text,\n };\n game.chatMessages.push(message);\n emitEvent(game, { type: \"chat\", message });\n return { success: true };\n }\n\n startGame(gameId: string, playerId: string): StartGameResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"open\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" };\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" };\n }\n const otherPlayer = game.players[1]!;\n const cards = [...CARDS];\n shuffleCards(cards);\n\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n\n player.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: player.username,\n numCards: player.drawPile.length,\n });\n\n player.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(player, { type: \"handInitialized\", cards: player.hand });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: player.username,\n numCards: player.hand.length,\n });\n\n otherPlayer.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.drawPile.length,\n });\n\n otherPlayer.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(otherPlayer, {\n type: \"handInitialized\",\n cards: otherPlayer.hand,\n });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.hand.length,\n });\n\n const startedGame: Game = {\n ...game,\n status: \"started\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS,\n };\n 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 };\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manager-BpKvQbcp.cjs","names":[],"sources":["../src/manager/constants.ts","../src/manager/Watchdog.ts","../src/lib/emitEvent.ts","../src/lib/emitEventToPlayer.ts","../src/manager/lib/isCardPlayable.ts","../src/manager/lib/hasPlayableCard.ts","../src/lib/shuffleCards.ts","../src/manager/Manager.ts"],"sourcesContent":["import type { Card } from \"./types/Card.js\";\n\nexport const GAME_KEY = \"speed\";\nexport const MAX_GAMES = 50;\nexport const WATCHDOG_INTERVAL_MS = 10000;\n\nexport const EXPIRY_EXTENSION_MS = 300000; // 5 minutes\nexport const MIN_PLAYERS = 2;\nexport const MAX_PLAYERS = 2;\nexport const MAX_HAND_SIZE = 5;\nexport const CAN_PLAY_AT_DELAY_MS = 3000;\n\nexport const CARDS: readonly Card[] = [\n { id: crypto.randomUUID(), rank: 2, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"clubs\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"diamonds\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"hearts\" },\n { id: crypto.randomUUID(), rank: 2, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 3, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 4, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 5, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 6, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 7, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 8, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 9, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 10, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 11, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 12, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 13, suite: \"spades\" },\n { id: crypto.randomUUID(), rank: 14, suite: \"spades\" },\n];\n","import { GAME_KEY, WATCHDOG_INTERVAL_MS } from \"./constants.js\";\n\ntype Game = {\n readonly id: string;\n readonly expiresAt: number;\n};\n\nexport class Watchdog<TGame extends Game> {\n private readonly games: Map<string, TGame>;\n\n constructor(games: Map<string, TGame>) {\n this.games = games;\n }\n\n start() {\n console.log(`watchdog start at ${Date.now()} (${GAME_KEY})`);\n setInterval(() => this.wakeUp(), WATCHDOG_INTERVAL_MS);\n }\n\n wakeUp() {\n const now = Date.now();\n // console.log(`watchdog wakeUp at ${now} (${GAME_KEY})`);\n for (const game of this.games.values()) {\n if (game.expiresAt <= now) {\n this.games.delete(game.id);\n console.log(`watchdog purged ${game.id} (${GAME_KEY})`);\n }\n }\n }\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 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","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 {\n CAN_PLAY_AT_DELAY_MS,\n CARDS,\n EXPIRY_EXTENSION_MS,\n MAX_GAMES,\n MAX_HAND_SIZE,\n MAX_PLAYERS,\n MIN_PLAYERS,\n} from \"./constants.js\";\nimport { Watchdog } from \"./Watchdog.js\";\nimport { emitEvent } from \"../lib/emitEvent.js\";\nimport { emitEventToPlayer } from \"../lib/emitEventToPlayer.js\";\nimport { isCardPlayable } from \"./lib/isCardPlayable.js\";\nimport { hasPlayableCard } from \"./lib/hasPlayableCard.js\";\nimport { shuffleCards } from \"../lib/shuffleCards.js\";\nimport type { ChatMessage } from \"./types/ChatMessage.js\";\nimport type { ClientState } from \"./types/ClientState.js\";\nimport type { Game } from \"./types/Game.js\";\nimport type { GameEvent } from \"./types/GameEvent.js\";\nimport type { Player } from \"./types/Player.js\";\n\nexport type CreateGameResult =\n | {\n readonly success: true;\n readonly gameId: string;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error: \"maxGamesReached\";\n };\n\nexport type DrawCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"handFull\"\n | \"drawPileEmpty\";\n };\n\nexport type GetClientStateAndClearEventsResult =\n | {\n readonly success: true;\n readonly state: ClientState;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetEventsAndClearAcknowledgedResult =\n | {\n readonly success: true;\n readonly events: readonly GameEvent[];\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type GetJoinableGamesResult = {\n readonly games: readonly {\n readonly id: string;\n readonly numPlayers: number;\n }[];\n};\n\nexport type JoinGameResult =\n | {\n readonly success: true;\n readonly playerId: string;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"maxPlayersReached\"\n | \"alreadyInGame\";\n };\n\nexport type LeaveGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type PlayCardResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"cardNotFound\"\n | \"cardNotPlayable\";\n };\n\nexport type ReportNoPlayableCardsResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"playerNotFound\"\n | \"invalidStatus\"\n | \"canPlayAtNotReached\"\n | \"alreadyReported\"\n | \"hasPlayableCard\"\n | \"canDraw\";\n };\n\nexport type SendChatResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error: \"gameNotFound\" | \"playerNotFound\";\n };\n\nexport type StartGameResult =\n | {\n readonly success: true;\n }\n | {\n readonly success: false;\n readonly error:\n | \"gameNotFound\"\n | \"invalidStatus\"\n | \"playerNotFound\"\n | \"playerNotAdmin\"\n | \"minPlayersNotReached\";\n };\n\nexport class Manager {\n private readonly games: Map<string, Game>;\n private readonly watchdog: Watchdog<Game>;\n\n constructor() {\n this.games = new Map<string, Game>();\n this.watchdog = new Watchdog(this.games);\n this.watchdog.start();\n }\n\n createGame(userId: string, username: string): CreateGameResult {\n if (this.games.size === MAX_GAMES) {\n return { success: false, error: \"maxGamesReached\" };\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n const createdAt = Date.now();\n const game: Game = {\n status: \"open\",\n id: crypto.randomUUID(),\n createdAt,\n expiresAt: createdAt + EXPIRY_EXTENSION_MS,\n chatMessages: [],\n players: [player],\n };\n this.games.set(game.id, game);\n return { success: true, gameId: game.id, playerId: player.id };\n }\n\n drawCard(gameId: string, playerId: string): DrawCardResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n if (player.hand.length >= MAX_HAND_SIZE) {\n return { success: false, error: \"handFull\" };\n }\n if (player.drawPile.length === 0) {\n return { success: false, error: \"drawPileEmpty\" };\n }\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n const card = player.drawPile.pop()!;\n player.hand.push(card);\n emitEventToPlayer(player, { type: \"drewCard\", card });\n emitEvent(game, { type: \"playerDrewCard\", username: player.username });\n return { success: true };\n }\n\n getClientStateAndClearEvents(\n gameId: string,\n playerId: string,\n ): GetClientStateAndClearEventsResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const state: ClientState = {\n status: game.status,\n gameId,\n playerId,\n username: player.username,\n players: game.players.map((p) => ({\n username: p.username,\n handSize: p.hand.length,\n drawPileSize: p.drawPile.length,\n sidePileSize: p.sidePile.length,\n centerPileTopCard: p.centerPile.length\n ? p.centerPile[p.centerPile.length - 1]!\n : null,\n })),\n expiresAt: game.expiresAt,\n chatMessages: game.chatMessages,\n hand: player.hand,\n canPlayAt: game.status === \"started\" ? game.canPlayAt : null,\n };\n player.events.length = 0;\n return { success: true, state };\n }\n\n getEventsAndClearAcknowledged(\n gameId: string,\n playerId: string,\n lastReadId: string | null,\n ): GetEventsAndClearAcknowledgedResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const lastReadEventIndex = player.events.findIndex(\n (e) => e.id === lastReadId,\n );\n player.events.splice(0, lastReadEventIndex + 1);\n return { success: true, events: player.events };\n }\n\n getJoinableGames(): GetJoinableGamesResult {\n return {\n games: Array.from(this.games.values())\n .filter((g) => g.status === \"open\" && g.players.length < MAX_PLAYERS)\n .map((g) => ({\n id: g.id,\n numPlayers: g.players.length,\n })),\n };\n }\n\n joinGame(gameId: string, userId: string, username: string): JoinGameResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n if (game.status !== \"open\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (game.players.length === MAX_PLAYERS) {\n return { success: false, error: \"maxPlayersReached\" };\n }\n if (game.players.find((p) => p.userId === userId)) {\n return { success: false, error: \"alreadyInGame\" };\n }\n const player: Player = {\n id: crypto.randomUUID(),\n userId,\n username,\n events: [],\n hand: [],\n drawPile: [],\n sidePile: [],\n centerPile: [],\n hasNoPlayableCards: false,\n };\n game.players.push(player);\n emitEvent(game, { type: \"playerJoined\", username });\n return { success: true, playerId: player.id };\n }\n\n leaveGame(gameId: string, playerId: string): LeaveGameResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const playerIndex = game.players.findIndex((p) => p.id === playerId);\n if (playerIndex === -1) {\n return { success: false, error: \"playerNotFound\" };\n }\n\n const player = game.players[playerIndex]!;\n emitEvent(game, { type: \"playerLeft\", username: player.username });\n\n game.players.splice(playerIndex, 1);\n\n if (game.status === \"started\" && game.players.length < MIN_PLAYERS) {\n const forfeitedGame: Game = {\n ...game,\n status: \"forfeited\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n };\n this.games.set(game.id, forfeitedGame);\n emitEvent(forfeitedGame, { type: \"gameForfeited\" });\n emitEvent(forfeitedGame, {\n type: \"expirationUpdated\",\n expiresAt: forfeitedGame.expiresAt,\n });\n }\n if (game.players.length === 0) {\n this.games.delete(game.id);\n }\n return { success: true };\n }\n\n playCard(\n gameId: string,\n playerId: string,\n cardId: string,\n isForOtherPlayerPile: boolean,\n ): PlayCardResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n const cardIndex = player.hand.findIndex((c) => c.id === cardId);\n if (cardIndex === -1) {\n return { success: false, error: \"cardNotFound\" };\n }\n const otherPlayer = game.players.find((p) => p !== player)!;\n const targetPile = isForOtherPlayerPile\n ? otherPlayer.centerPile\n : player.centerPile;\n const card = player.hand[cardIndex]!;\n if (!isCardPlayable(card, targetPile)) {\n return { success: false, error: \"cardNotPlayable\" };\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hand.splice(cardIndex, 1);\n targetPile.push(card);\n emitEvent(game, {\n type: \"cardPlayed\",\n username: player.username,\n card,\n isForOtherPlayerPile,\n });\n\n if (otherPlayer.hasNoPlayableCards && hasPlayableCard(otherPlayer, game)) {\n otherPlayer.hasNoPlayableCards = false;\n }\n\n if (player.hand.length === 0 && player.drawPile.length === 0) {\n emitEvent(game, { type: \"gameCompleted\" });\n const completedGame: Game = {\n ...game,\n status: \"completed\",\n };\n this.games.set(game.id, completedGame);\n }\n\n return { success: true };\n }\n\n reportNoPlayableCards(\n gameId: string,\n playerId: string,\n ): ReportNoPlayableCardsResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"started\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (Date.now() < game.canPlayAt) {\n return { success: false, error: \"canPlayAtNotReached\" };\n }\n if (player.hasNoPlayableCards) {\n return { success: false, error: \"alreadyReported\" };\n }\n if (hasPlayableCard(player, game)) {\n return { success: false, error: \"hasPlayableCard\" };\n }\n if (player.drawPile.length > 0 && player.hand.length < MAX_HAND_SIZE) {\n return { success: false, error: \"canDraw\" };\n }\n\n game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;\n emitEvent(game, { type: \"expirationUpdated\", expiresAt: game.expiresAt });\n\n player.hasNoPlayableCards = true;\n\n const otherPlayer = game.players.find((p) => p !== player)!;\n if (otherPlayer.hasNoPlayableCards) {\n if (player.sidePile.length === 0 && otherPlayer.sidePile.length === 0) {\n const cards = [...player.centerPile, ...otherPlayer.centerPile];\n shuffleCards(cards);\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n } else {\n const playerSidePileCard = player.sidePile.pop()!;\n player.centerPile.push(playerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: player.username,\n card: playerSidePileCard,\n });\n const otherPlayerSidePileCard = otherPlayer.sidePile.pop()!;\n otherPlayer.centerPile.push(otherPlayerSidePileCard);\n emitEvent(game, {\n type: \"cardDrawnFromSidePileToCenterPile\",\n username: otherPlayer.username,\n card: otherPlayerSidePileCard,\n });\n }\n player.hasNoPlayableCards = false;\n otherPlayer.hasNoPlayableCards = false;\n game.canPlayAt = Date.now() + CAN_PLAY_AT_DELAY_MS;\n emitEvent(game, {\n type: \"canPlayAtUpdated\",\n canPlayAt: game.canPlayAt,\n });\n }\n\n return { success: true };\n }\n\n sendChat(gameId: string, playerId: string, text: string): SendChatResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n const message: ChatMessage = {\n id: crypto.randomUUID(),\n username: player.username,\n text,\n };\n game.chatMessages.push(message);\n emitEvent(game, { type: \"chat\", message });\n return { success: true };\n }\n\n startGame(gameId: string, playerId: string): StartGameResult {\n const game = this.games.get(gameId);\n if (!game) {\n return { success: false, error: \"gameNotFound\" };\n }\n const player = game.players.find((p) => p.id === playerId);\n if (!player) {\n return { success: false, error: \"playerNotFound\" };\n }\n if (game.status !== \"open\") {\n return { success: false, error: \"invalidStatus\" };\n }\n if (game.players.indexOf(player) !== 0) {\n return { success: false, error: \"playerNotAdmin\" };\n }\n if (game.players.length < MIN_PLAYERS) {\n return { success: false, error: \"minPlayersNotReached\" };\n }\n const otherPlayer = game.players[1]!;\n const cards = [...CARDS];\n shuffleCards(cards);\n\n player.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: player.username,\n numCards: player.sidePile.length,\n });\n\n player.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: player.username,\n card: player.centerPile[player.centerPile.length - 1]!,\n });\n\n otherPlayer.centerPile.push(...cards.splice(0, 1));\n emitEvent(game, {\n type: \"playerCenterPileInitialized\",\n username: otherPlayer.username,\n card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]!,\n });\n\n otherPlayer.sidePile.push(...cards.splice(0, 5));\n emitEvent(game, {\n type: \"playerSidePileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.sidePile.length,\n });\n\n player.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: player.username,\n numCards: player.drawPile.length,\n });\n\n player.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(player, { type: \"handInitialized\", cards: player.hand });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: player.username,\n numCards: player.hand.length,\n });\n\n otherPlayer.drawPile.push(...cards.splice(0, 15));\n emitEvent(game, {\n type: \"playerDrawPileInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.drawPile.length,\n });\n\n otherPlayer.hand.push(...cards.splice(0, 5));\n emitEventToPlayer(otherPlayer, {\n type: \"handInitialized\",\n cards: otherPlayer.hand,\n });\n emitEvent(game, {\n type: \"playerHandInitialized\",\n username: otherPlayer.username,\n numCards: otherPlayer.hand.length,\n });\n\n const startedGame: Game = {\n ...game,\n status: \"started\",\n expiresAt: Date.now() + EXPIRY_EXTENSION_MS,\n canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS,\n };\n 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 };\n }\n}\n"],"mappings":"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"}
|