@thegeem/protocol 0.1.17 → 0.1.19
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/index.cjs +20 -5
- package/dist/index.d.cts +110 -6
- package/dist/index.d.ts +110 -6
- package/dist/index.js +20 -5
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -41,12 +41,14 @@ var LIMITS = {
|
|
|
41
41
|
MAX_PLAYERS: 12,
|
|
42
42
|
MAX_MSG_PER_SEC: 8
|
|
43
43
|
};
|
|
44
|
-
var PROTOCOL_VERSION =
|
|
44
|
+
var PROTOCOL_VERSION = 3;
|
|
45
45
|
var MIN_SUPPORTED_PV = 1;
|
|
46
|
-
var GAME_IDS = ["seedha", "snag", "trivia"];
|
|
46
|
+
var GAME_IDS = ["seedha", "snag", "trivia", "dama"];
|
|
47
47
|
var GAMES = [
|
|
48
48
|
{ id: "seedha", label: "Seedha", minPv: 2 },
|
|
49
49
|
{ id: "snag", label: "Snag", minPv: 2 },
|
|
50
|
+
{ id: "dama", label: "Dama", minPv: 3 },
|
|
51
|
+
// engine #2 (D-027) — offered only to pv≥3 clients
|
|
50
52
|
{ id: "trivia", label: "Trivia", minPv: 1, deprecated: true }
|
|
51
53
|
];
|
|
52
54
|
var gamesForPv = (pv) => GAMES.filter((g) => !g.deprecated && g.minPv <= pv);
|
|
@@ -85,7 +87,7 @@ var Avatar = import_zod.z.object({
|
|
|
85
87
|
});
|
|
86
88
|
var ClientMsg = import_zod.z.discriminatedUnion("t", [
|
|
87
89
|
// room / lobby
|
|
88
|
-
import_zod.z.object({ t: import_zod.z.literal("createRoom"), name: DisplayName.optional(), avatar: Avatar.optional(), pv: Pv, idToken: IdToken, platform: Platform }),
|
|
90
|
+
import_zod.z.object({ t: import_zod.z.literal("createRoom"), name: DisplayName.optional(), avatar: Avatar.optional(), game: import_zod.z.enum(GAME_IDS).optional(), pv: Pv, idToken: IdToken, platform: Platform }),
|
|
89
91
|
// Host sets/changes their display name AFTER createRoom (for anonymous one-tap
|
|
90
92
|
// hosts who started nameless). Host-only; the relay re-broadcasts the lobby.
|
|
91
93
|
import_zod.z.object({ t: import_zod.z.literal("renameHost"), name: DisplayName }),
|
|
@@ -116,7 +118,8 @@ var ClientMsg = import_zod.z.discriminatedUnion("t", [
|
|
|
116
118
|
game: import_zod.z.enum(GAME_IDS).optional(),
|
|
117
119
|
// which game to play; defaults to 'trivia'
|
|
118
120
|
totalRounds: import_zod.z.number().int().min(1).max(50),
|
|
119
|
-
categoryIds: import_zod.z.array(import_zod.z.string().max(60)).min(
|
|
121
|
+
categoryIds: import_zod.z.array(import_zod.z.string().max(60)).min(0).max(12),
|
|
122
|
+
// empty for games without categories (Dama); trivia rejects empty in-handler
|
|
120
123
|
// PREFERRED: pick a mode from the registry (see MODES). The server maps it to the engine
|
|
121
124
|
// rules. Send this and omit buzzerMode/noHost. Falls back to the legacy flags below if omitted.
|
|
122
125
|
modeId: import_zod.z.enum(MODE_IDS).optional(),
|
|
@@ -153,7 +156,19 @@ var ClientMsg = import_zod.z.discriminatedUnion("t", [
|
|
|
153
156
|
// Report the CURRENT question as bad (wrong answer / typo / offensive). The relay resolves WHICH
|
|
154
157
|
// question from its authoritative room state — the client never sees the question id (anti-cheat),
|
|
155
158
|
// so it only sends an optional `reason`. Only meaningful while a question is on screen.
|
|
156
|
-
import_zod.z.object({ t: import_zod.z.literal("reportQuestion"), reason: import_zod.z.string().max(500).optional() })
|
|
159
|
+
import_zod.z.object({ t: import_zod.z.literal("reportQuestion"), reason: import_zod.z.string().max(500).optional() }),
|
|
160
|
+
// ── Dama slice (gameId 'dama', engine #2 — D-027) ──
|
|
161
|
+
// Make a Dama move: from → to (board coords, 0–7). The relay validates legality against the engine
|
|
162
|
+
// (Shape B) and rejects anything not in legalMoves. If two capture chains share from+to (rare), the
|
|
163
|
+
// relay picks the max-capture one; a client MAY send the full landing `path` to disambiguate.
|
|
164
|
+
import_zod.z.object({
|
|
165
|
+
t: import_zod.z.literal("damaMove"),
|
|
166
|
+
from: import_zod.z.object({ r: import_zod.z.number().int().min(0).max(7), c: import_zod.z.number().int().min(0).max(7) }),
|
|
167
|
+
to: import_zod.z.object({ r: import_zod.z.number().int().min(0).max(7), c: import_zod.z.number().int().min(0).max(7) }),
|
|
168
|
+
path: import_zod.z.array(import_zod.z.object({ r: import_zod.z.number().int().min(0).max(7), c: import_zod.z.number().int().min(0).max(7) })).max(12).optional()
|
|
169
|
+
}),
|
|
170
|
+
// Resign the current Dama game (concede) → opponent wins.
|
|
171
|
+
import_zod.z.object({ t: import_zod.z.literal("damaResign") })
|
|
157
172
|
]);
|
|
158
173
|
// Annotate the CommonJS export names for ESM import in node:
|
|
159
174
|
0 && (module.exports = {
|
package/dist/index.d.cts
CHANGED
|
@@ -33,7 +33,7 @@ declare const LIMITS: {
|
|
|
33
33
|
* `seedha`/`snag`). Raise the floor SLOWLY to retire ancient builds. Unversioned clients (no `pv`,
|
|
34
34
|
* e.g. the legacy web harness) are treated as the floor and never rejected.
|
|
35
35
|
*/
|
|
36
|
-
declare const PROTOCOL_VERSION =
|
|
36
|
+
declare const PROTOCOL_VERSION = 3;
|
|
37
37
|
declare const MIN_SUPPORTED_PV = 1;
|
|
38
38
|
/**
|
|
39
39
|
* Geem is a PLATFORM of GAMES (jackbox-style). The trivia board split (D-023) into TWO player-facing
|
|
@@ -42,7 +42,7 @@ declare const MIN_SUPPORTED_PV = 1;
|
|
|
42
42
|
* pre-pv2 clients (they never saw seedha/snag), and what old clients send on startGame. Every room
|
|
43
43
|
* runs one game, identified by `gameId`.
|
|
44
44
|
*/
|
|
45
|
-
declare const GAME_IDS: readonly ["seedha", "snag", "trivia"];
|
|
45
|
+
declare const GAME_IDS: readonly ["seedha", "snag", "trivia", "dama"];
|
|
46
46
|
type GameId = (typeof GAME_IDS)[number];
|
|
47
47
|
/**
|
|
48
48
|
* The GAME REGISTRY — player-facing games + the version gating (D-024/D-025). A client renders a tile
|
|
@@ -96,6 +96,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
96
96
|
emoji: string;
|
|
97
97
|
color: string;
|
|
98
98
|
}>>;
|
|
99
|
+
game: z.ZodOptional<z.ZodEnum<["seedha", "snag", "trivia", "dama"]>>;
|
|
99
100
|
pv: z.ZodOptional<z.ZodNumber>;
|
|
100
101
|
idToken: z.ZodOptional<z.ZodString>;
|
|
101
102
|
platform: z.ZodOptional<z.ZodEnum<["web", "ios", "android"]>>;
|
|
@@ -106,6 +107,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
106
107
|
emoji: string;
|
|
107
108
|
color: string;
|
|
108
109
|
} | undefined;
|
|
110
|
+
game?: "seedha" | "snag" | "trivia" | "dama" | undefined;
|
|
109
111
|
pv?: number | undefined;
|
|
110
112
|
idToken?: string | undefined;
|
|
111
113
|
platform?: "web" | "ios" | "android" | undefined;
|
|
@@ -116,6 +118,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
116
118
|
emoji: string;
|
|
117
119
|
color: string;
|
|
118
120
|
} | undefined;
|
|
121
|
+
game?: "seedha" | "snag" | "trivia" | "dama" | undefined;
|
|
119
122
|
pv?: number | undefined;
|
|
120
123
|
idToken?: string | undefined;
|
|
121
124
|
platform?: "web" | "ios" | "android" | undefined;
|
|
@@ -286,7 +289,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
286
289
|
activity: "configuring" | "idle";
|
|
287
290
|
}>, z.ZodObject<{
|
|
288
291
|
t: z.ZodLiteral<"startGame">;
|
|
289
|
-
game: z.ZodOptional<z.ZodEnum<["seedha", "snag", "trivia"]>>;
|
|
292
|
+
game: z.ZodOptional<z.ZodEnum<["seedha", "snag", "trivia", "dama"]>>;
|
|
290
293
|
totalRounds: z.ZodNumber;
|
|
291
294
|
categoryIds: z.ZodArray<z.ZodString, "many">;
|
|
292
295
|
modeId: z.ZodOptional<z.ZodEnum<["solo", "oneDevice", "snag", "multiplayer"]>>;
|
|
@@ -296,16 +299,16 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
296
299
|
t: "startGame";
|
|
297
300
|
categoryIds: string[];
|
|
298
301
|
totalRounds: number;
|
|
302
|
+
game?: "seedha" | "snag" | "trivia" | "dama" | undefined;
|
|
299
303
|
modeId?: "snag" | "solo" | "oneDevice" | "multiplayer" | undefined;
|
|
300
|
-
game?: "seedha" | "snag" | "trivia" | undefined;
|
|
301
304
|
buzzerMode?: "solo" | "off" | "race" | "controller" | undefined;
|
|
302
305
|
noHost?: boolean | undefined;
|
|
303
306
|
}, {
|
|
304
307
|
t: "startGame";
|
|
305
308
|
categoryIds: string[];
|
|
306
309
|
totalRounds: number;
|
|
310
|
+
game?: "seedha" | "snag" | "trivia" | "dama" | undefined;
|
|
307
311
|
modeId?: "snag" | "solo" | "oneDevice" | "multiplayer" | undefined;
|
|
308
|
-
game?: "seedha" | "snag" | "trivia" | undefined;
|
|
309
312
|
buzzerMode?: "solo" | "off" | "race" | "controller" | undefined;
|
|
310
313
|
noHost?: boolean | undefined;
|
|
311
314
|
}>, z.ZodObject<{
|
|
@@ -419,6 +422,72 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
419
422
|
}, {
|
|
420
423
|
t: "reportQuestion";
|
|
421
424
|
reason?: string | undefined;
|
|
425
|
+
}>, z.ZodObject<{
|
|
426
|
+
t: z.ZodLiteral<"damaMove">;
|
|
427
|
+
from: z.ZodObject<{
|
|
428
|
+
r: z.ZodNumber;
|
|
429
|
+
c: z.ZodNumber;
|
|
430
|
+
}, "strip", z.ZodTypeAny, {
|
|
431
|
+
r: number;
|
|
432
|
+
c: number;
|
|
433
|
+
}, {
|
|
434
|
+
r: number;
|
|
435
|
+
c: number;
|
|
436
|
+
}>;
|
|
437
|
+
to: z.ZodObject<{
|
|
438
|
+
r: z.ZodNumber;
|
|
439
|
+
c: z.ZodNumber;
|
|
440
|
+
}, "strip", z.ZodTypeAny, {
|
|
441
|
+
r: number;
|
|
442
|
+
c: number;
|
|
443
|
+
}, {
|
|
444
|
+
r: number;
|
|
445
|
+
c: number;
|
|
446
|
+
}>;
|
|
447
|
+
path: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
448
|
+
r: z.ZodNumber;
|
|
449
|
+
c: z.ZodNumber;
|
|
450
|
+
}, "strip", z.ZodTypeAny, {
|
|
451
|
+
r: number;
|
|
452
|
+
c: number;
|
|
453
|
+
}, {
|
|
454
|
+
r: number;
|
|
455
|
+
c: number;
|
|
456
|
+
}>, "many">>;
|
|
457
|
+
}, "strip", z.ZodTypeAny, {
|
|
458
|
+
t: "damaMove";
|
|
459
|
+
from: {
|
|
460
|
+
r: number;
|
|
461
|
+
c: number;
|
|
462
|
+
};
|
|
463
|
+
to: {
|
|
464
|
+
r: number;
|
|
465
|
+
c: number;
|
|
466
|
+
};
|
|
467
|
+
path?: {
|
|
468
|
+
r: number;
|
|
469
|
+
c: number;
|
|
470
|
+
}[] | undefined;
|
|
471
|
+
}, {
|
|
472
|
+
t: "damaMove";
|
|
473
|
+
from: {
|
|
474
|
+
r: number;
|
|
475
|
+
c: number;
|
|
476
|
+
};
|
|
477
|
+
to: {
|
|
478
|
+
r: number;
|
|
479
|
+
c: number;
|
|
480
|
+
};
|
|
481
|
+
path?: {
|
|
482
|
+
r: number;
|
|
483
|
+
c: number;
|
|
484
|
+
}[] | undefined;
|
|
485
|
+
}>, z.ZodObject<{
|
|
486
|
+
t: z.ZodLiteral<"damaResign">;
|
|
487
|
+
}, "strip", z.ZodTypeAny, {
|
|
488
|
+
t: "damaResign";
|
|
489
|
+
}, {
|
|
490
|
+
t: "damaResign";
|
|
422
491
|
}>]>;
|
|
423
492
|
type ClientMsg = z.infer<typeof ClientMsg>;
|
|
424
493
|
/** A player's privacy-safe avatar (emoji + circle color) for in-room display. */
|
|
@@ -574,6 +643,36 @@ type Effect = {
|
|
|
574
643
|
} | {
|
|
575
644
|
t: 'endGame';
|
|
576
645
|
};
|
|
646
|
+
/** A Dama piece as clients see it. */
|
|
647
|
+
interface DamaPieceView {
|
|
648
|
+
color: 'black' | 'white';
|
|
649
|
+
king: boolean;
|
|
650
|
+
}
|
|
651
|
+
/** A legal Dama move offered to the player to move (for highlighting). `captures` = pieces it takes. */
|
|
652
|
+
interface DamaMoveView {
|
|
653
|
+
from: {
|
|
654
|
+
r: number;
|
|
655
|
+
c: number;
|
|
656
|
+
};
|
|
657
|
+
to: {
|
|
658
|
+
r: number;
|
|
659
|
+
c: number;
|
|
660
|
+
};
|
|
661
|
+
captures: number;
|
|
662
|
+
path: {
|
|
663
|
+
r: number;
|
|
664
|
+
c: number;
|
|
665
|
+
}[];
|
|
666
|
+
}
|
|
667
|
+
/** The authoritative Dama board pushed to a client. `board[r][c]` is null on empty/light squares; r=0 is the top. */
|
|
668
|
+
interface DamaStateView {
|
|
669
|
+
board: (DamaPieceView | null)[][];
|
|
670
|
+
turn: 'black' | 'white';
|
|
671
|
+
winner: 'black' | 'white' | null;
|
|
672
|
+
yourColor: 'black' | 'white' | null;
|
|
673
|
+
legalMoves: DamaMoveView[];
|
|
674
|
+
moveCount: number;
|
|
675
|
+
}
|
|
577
676
|
type ServerMsg = {
|
|
578
677
|
t: 'roomCreated';
|
|
579
678
|
code: string;
|
|
@@ -618,6 +717,11 @@ type ServerMsg = {
|
|
|
618
717
|
view: GameStateView;
|
|
619
718
|
you: YouContext;
|
|
620
719
|
teamConnected: boolean[];
|
|
720
|
+
} | {
|
|
721
|
+
t: 'damaState';
|
|
722
|
+
gameId: 'dama';
|
|
723
|
+
view: DamaStateView;
|
|
724
|
+
you: YouContext;
|
|
621
725
|
} | {
|
|
622
726
|
t: 'fx';
|
|
623
727
|
effects: Effect[];
|
|
@@ -634,4 +738,4 @@ type ServerMsg = {
|
|
|
634
738
|
message: string;
|
|
635
739
|
};
|
|
636
740
|
|
|
637
|
-
export { type AvatarView, type BuzzerGameMode, type CategoryView, ClientMsg, type Effect, GAMES, GAME_IDS, type GameId, type GameInfo, type GameStateView, type GameStatus, type GameplayFlow, type HelpName, LIMITS, type LobbyPlayer, MIN_SUPPORTED_PV, MODES, MODE_IDS, type ModeId, type ModeInfo, PROTOCOL_VERSION, type QuestionView, ROOM_ALPHABET, type ServerMsg, type SoundName, type TeamSlotView, type TeamView, type YouContext, gameIdForPv, gamesForPv, modesForGame };
|
|
741
|
+
export { type AvatarView, type BuzzerGameMode, type CategoryView, ClientMsg, type DamaMoveView, type DamaPieceView, type DamaStateView, type Effect, GAMES, GAME_IDS, type GameId, type GameInfo, type GameStateView, type GameStatus, type GameplayFlow, type HelpName, LIMITS, type LobbyPlayer, MIN_SUPPORTED_PV, MODES, MODE_IDS, type ModeId, type ModeInfo, PROTOCOL_VERSION, type QuestionView, ROOM_ALPHABET, type ServerMsg, type SoundName, type TeamSlotView, type TeamView, type YouContext, gameIdForPv, gamesForPv, modesForGame };
|
package/dist/index.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ declare const LIMITS: {
|
|
|
33
33
|
* `seedha`/`snag`). Raise the floor SLOWLY to retire ancient builds. Unversioned clients (no `pv`,
|
|
34
34
|
* e.g. the legacy web harness) are treated as the floor and never rejected.
|
|
35
35
|
*/
|
|
36
|
-
declare const PROTOCOL_VERSION =
|
|
36
|
+
declare const PROTOCOL_VERSION = 3;
|
|
37
37
|
declare const MIN_SUPPORTED_PV = 1;
|
|
38
38
|
/**
|
|
39
39
|
* Geem is a PLATFORM of GAMES (jackbox-style). The trivia board split (D-023) into TWO player-facing
|
|
@@ -42,7 +42,7 @@ declare const MIN_SUPPORTED_PV = 1;
|
|
|
42
42
|
* pre-pv2 clients (they never saw seedha/snag), and what old clients send on startGame. Every room
|
|
43
43
|
* runs one game, identified by `gameId`.
|
|
44
44
|
*/
|
|
45
|
-
declare const GAME_IDS: readonly ["seedha", "snag", "trivia"];
|
|
45
|
+
declare const GAME_IDS: readonly ["seedha", "snag", "trivia", "dama"];
|
|
46
46
|
type GameId = (typeof GAME_IDS)[number];
|
|
47
47
|
/**
|
|
48
48
|
* The GAME REGISTRY — player-facing games + the version gating (D-024/D-025). A client renders a tile
|
|
@@ -96,6 +96,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
96
96
|
emoji: string;
|
|
97
97
|
color: string;
|
|
98
98
|
}>>;
|
|
99
|
+
game: z.ZodOptional<z.ZodEnum<["seedha", "snag", "trivia", "dama"]>>;
|
|
99
100
|
pv: z.ZodOptional<z.ZodNumber>;
|
|
100
101
|
idToken: z.ZodOptional<z.ZodString>;
|
|
101
102
|
platform: z.ZodOptional<z.ZodEnum<["web", "ios", "android"]>>;
|
|
@@ -106,6 +107,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
106
107
|
emoji: string;
|
|
107
108
|
color: string;
|
|
108
109
|
} | undefined;
|
|
110
|
+
game?: "seedha" | "snag" | "trivia" | "dama" | undefined;
|
|
109
111
|
pv?: number | undefined;
|
|
110
112
|
idToken?: string | undefined;
|
|
111
113
|
platform?: "web" | "ios" | "android" | undefined;
|
|
@@ -116,6 +118,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
116
118
|
emoji: string;
|
|
117
119
|
color: string;
|
|
118
120
|
} | undefined;
|
|
121
|
+
game?: "seedha" | "snag" | "trivia" | "dama" | undefined;
|
|
119
122
|
pv?: number | undefined;
|
|
120
123
|
idToken?: string | undefined;
|
|
121
124
|
platform?: "web" | "ios" | "android" | undefined;
|
|
@@ -286,7 +289,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
286
289
|
activity: "configuring" | "idle";
|
|
287
290
|
}>, z.ZodObject<{
|
|
288
291
|
t: z.ZodLiteral<"startGame">;
|
|
289
|
-
game: z.ZodOptional<z.ZodEnum<["seedha", "snag", "trivia"]>>;
|
|
292
|
+
game: z.ZodOptional<z.ZodEnum<["seedha", "snag", "trivia", "dama"]>>;
|
|
290
293
|
totalRounds: z.ZodNumber;
|
|
291
294
|
categoryIds: z.ZodArray<z.ZodString, "many">;
|
|
292
295
|
modeId: z.ZodOptional<z.ZodEnum<["solo", "oneDevice", "snag", "multiplayer"]>>;
|
|
@@ -296,16 +299,16 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
296
299
|
t: "startGame";
|
|
297
300
|
categoryIds: string[];
|
|
298
301
|
totalRounds: number;
|
|
302
|
+
game?: "seedha" | "snag" | "trivia" | "dama" | undefined;
|
|
299
303
|
modeId?: "snag" | "solo" | "oneDevice" | "multiplayer" | undefined;
|
|
300
|
-
game?: "seedha" | "snag" | "trivia" | undefined;
|
|
301
304
|
buzzerMode?: "solo" | "off" | "race" | "controller" | undefined;
|
|
302
305
|
noHost?: boolean | undefined;
|
|
303
306
|
}, {
|
|
304
307
|
t: "startGame";
|
|
305
308
|
categoryIds: string[];
|
|
306
309
|
totalRounds: number;
|
|
310
|
+
game?: "seedha" | "snag" | "trivia" | "dama" | undefined;
|
|
307
311
|
modeId?: "snag" | "solo" | "oneDevice" | "multiplayer" | undefined;
|
|
308
|
-
game?: "seedha" | "snag" | "trivia" | undefined;
|
|
309
312
|
buzzerMode?: "solo" | "off" | "race" | "controller" | undefined;
|
|
310
313
|
noHost?: boolean | undefined;
|
|
311
314
|
}>, z.ZodObject<{
|
|
@@ -419,6 +422,72 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
419
422
|
}, {
|
|
420
423
|
t: "reportQuestion";
|
|
421
424
|
reason?: string | undefined;
|
|
425
|
+
}>, z.ZodObject<{
|
|
426
|
+
t: z.ZodLiteral<"damaMove">;
|
|
427
|
+
from: z.ZodObject<{
|
|
428
|
+
r: z.ZodNumber;
|
|
429
|
+
c: z.ZodNumber;
|
|
430
|
+
}, "strip", z.ZodTypeAny, {
|
|
431
|
+
r: number;
|
|
432
|
+
c: number;
|
|
433
|
+
}, {
|
|
434
|
+
r: number;
|
|
435
|
+
c: number;
|
|
436
|
+
}>;
|
|
437
|
+
to: z.ZodObject<{
|
|
438
|
+
r: z.ZodNumber;
|
|
439
|
+
c: z.ZodNumber;
|
|
440
|
+
}, "strip", z.ZodTypeAny, {
|
|
441
|
+
r: number;
|
|
442
|
+
c: number;
|
|
443
|
+
}, {
|
|
444
|
+
r: number;
|
|
445
|
+
c: number;
|
|
446
|
+
}>;
|
|
447
|
+
path: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
448
|
+
r: z.ZodNumber;
|
|
449
|
+
c: z.ZodNumber;
|
|
450
|
+
}, "strip", z.ZodTypeAny, {
|
|
451
|
+
r: number;
|
|
452
|
+
c: number;
|
|
453
|
+
}, {
|
|
454
|
+
r: number;
|
|
455
|
+
c: number;
|
|
456
|
+
}>, "many">>;
|
|
457
|
+
}, "strip", z.ZodTypeAny, {
|
|
458
|
+
t: "damaMove";
|
|
459
|
+
from: {
|
|
460
|
+
r: number;
|
|
461
|
+
c: number;
|
|
462
|
+
};
|
|
463
|
+
to: {
|
|
464
|
+
r: number;
|
|
465
|
+
c: number;
|
|
466
|
+
};
|
|
467
|
+
path?: {
|
|
468
|
+
r: number;
|
|
469
|
+
c: number;
|
|
470
|
+
}[] | undefined;
|
|
471
|
+
}, {
|
|
472
|
+
t: "damaMove";
|
|
473
|
+
from: {
|
|
474
|
+
r: number;
|
|
475
|
+
c: number;
|
|
476
|
+
};
|
|
477
|
+
to: {
|
|
478
|
+
r: number;
|
|
479
|
+
c: number;
|
|
480
|
+
};
|
|
481
|
+
path?: {
|
|
482
|
+
r: number;
|
|
483
|
+
c: number;
|
|
484
|
+
}[] | undefined;
|
|
485
|
+
}>, z.ZodObject<{
|
|
486
|
+
t: z.ZodLiteral<"damaResign">;
|
|
487
|
+
}, "strip", z.ZodTypeAny, {
|
|
488
|
+
t: "damaResign";
|
|
489
|
+
}, {
|
|
490
|
+
t: "damaResign";
|
|
422
491
|
}>]>;
|
|
423
492
|
type ClientMsg = z.infer<typeof ClientMsg>;
|
|
424
493
|
/** A player's privacy-safe avatar (emoji + circle color) for in-room display. */
|
|
@@ -574,6 +643,36 @@ type Effect = {
|
|
|
574
643
|
} | {
|
|
575
644
|
t: 'endGame';
|
|
576
645
|
};
|
|
646
|
+
/** A Dama piece as clients see it. */
|
|
647
|
+
interface DamaPieceView {
|
|
648
|
+
color: 'black' | 'white';
|
|
649
|
+
king: boolean;
|
|
650
|
+
}
|
|
651
|
+
/** A legal Dama move offered to the player to move (for highlighting). `captures` = pieces it takes. */
|
|
652
|
+
interface DamaMoveView {
|
|
653
|
+
from: {
|
|
654
|
+
r: number;
|
|
655
|
+
c: number;
|
|
656
|
+
};
|
|
657
|
+
to: {
|
|
658
|
+
r: number;
|
|
659
|
+
c: number;
|
|
660
|
+
};
|
|
661
|
+
captures: number;
|
|
662
|
+
path: {
|
|
663
|
+
r: number;
|
|
664
|
+
c: number;
|
|
665
|
+
}[];
|
|
666
|
+
}
|
|
667
|
+
/** The authoritative Dama board pushed to a client. `board[r][c]` is null on empty/light squares; r=0 is the top. */
|
|
668
|
+
interface DamaStateView {
|
|
669
|
+
board: (DamaPieceView | null)[][];
|
|
670
|
+
turn: 'black' | 'white';
|
|
671
|
+
winner: 'black' | 'white' | null;
|
|
672
|
+
yourColor: 'black' | 'white' | null;
|
|
673
|
+
legalMoves: DamaMoveView[];
|
|
674
|
+
moveCount: number;
|
|
675
|
+
}
|
|
577
676
|
type ServerMsg = {
|
|
578
677
|
t: 'roomCreated';
|
|
579
678
|
code: string;
|
|
@@ -618,6 +717,11 @@ type ServerMsg = {
|
|
|
618
717
|
view: GameStateView;
|
|
619
718
|
you: YouContext;
|
|
620
719
|
teamConnected: boolean[];
|
|
720
|
+
} | {
|
|
721
|
+
t: 'damaState';
|
|
722
|
+
gameId: 'dama';
|
|
723
|
+
view: DamaStateView;
|
|
724
|
+
you: YouContext;
|
|
621
725
|
} | {
|
|
622
726
|
t: 'fx';
|
|
623
727
|
effects: Effect[];
|
|
@@ -634,4 +738,4 @@ type ServerMsg = {
|
|
|
634
738
|
message: string;
|
|
635
739
|
};
|
|
636
740
|
|
|
637
|
-
export { type AvatarView, type BuzzerGameMode, type CategoryView, ClientMsg, type Effect, GAMES, GAME_IDS, type GameId, type GameInfo, type GameStateView, type GameStatus, type GameplayFlow, type HelpName, LIMITS, type LobbyPlayer, MIN_SUPPORTED_PV, MODES, MODE_IDS, type ModeId, type ModeInfo, PROTOCOL_VERSION, type QuestionView, ROOM_ALPHABET, type ServerMsg, type SoundName, type TeamSlotView, type TeamView, type YouContext, gameIdForPv, gamesForPv, modesForGame };
|
|
741
|
+
export { type AvatarView, type BuzzerGameMode, type CategoryView, ClientMsg, type DamaMoveView, type DamaPieceView, type DamaStateView, type Effect, GAMES, GAME_IDS, type GameId, type GameInfo, type GameStateView, type GameStatus, type GameplayFlow, type HelpName, LIMITS, type LobbyPlayer, MIN_SUPPORTED_PV, MODES, MODE_IDS, type ModeId, type ModeInfo, PROTOCOL_VERSION, type QuestionView, ROOM_ALPHABET, type ServerMsg, type SoundName, type TeamSlotView, type TeamView, type YouContext, gameIdForPv, gamesForPv, modesForGame };
|
package/dist/index.js
CHANGED
|
@@ -6,12 +6,14 @@ var LIMITS = {
|
|
|
6
6
|
MAX_PLAYERS: 12,
|
|
7
7
|
MAX_MSG_PER_SEC: 8
|
|
8
8
|
};
|
|
9
|
-
var PROTOCOL_VERSION =
|
|
9
|
+
var PROTOCOL_VERSION = 3;
|
|
10
10
|
var MIN_SUPPORTED_PV = 1;
|
|
11
|
-
var GAME_IDS = ["seedha", "snag", "trivia"];
|
|
11
|
+
var GAME_IDS = ["seedha", "snag", "trivia", "dama"];
|
|
12
12
|
var GAMES = [
|
|
13
13
|
{ id: "seedha", label: "Seedha", minPv: 2 },
|
|
14
14
|
{ id: "snag", label: "Snag", minPv: 2 },
|
|
15
|
+
{ id: "dama", label: "Dama", minPv: 3 },
|
|
16
|
+
// engine #2 (D-027) — offered only to pv≥3 clients
|
|
15
17
|
{ id: "trivia", label: "Trivia", minPv: 1, deprecated: true }
|
|
16
18
|
];
|
|
17
19
|
var gamesForPv = (pv) => GAMES.filter((g) => !g.deprecated && g.minPv <= pv);
|
|
@@ -50,7 +52,7 @@ var Avatar = z.object({
|
|
|
50
52
|
});
|
|
51
53
|
var ClientMsg = z.discriminatedUnion("t", [
|
|
52
54
|
// room / lobby
|
|
53
|
-
z.object({ t: z.literal("createRoom"), name: DisplayName.optional(), avatar: Avatar.optional(), pv: Pv, idToken: IdToken, platform: Platform }),
|
|
55
|
+
z.object({ t: z.literal("createRoom"), name: DisplayName.optional(), avatar: Avatar.optional(), game: z.enum(GAME_IDS).optional(), pv: Pv, idToken: IdToken, platform: Platform }),
|
|
54
56
|
// Host sets/changes their display name AFTER createRoom (for anonymous one-tap
|
|
55
57
|
// hosts who started nameless). Host-only; the relay re-broadcasts the lobby.
|
|
56
58
|
z.object({ t: z.literal("renameHost"), name: DisplayName }),
|
|
@@ -81,7 +83,8 @@ var ClientMsg = z.discriminatedUnion("t", [
|
|
|
81
83
|
game: z.enum(GAME_IDS).optional(),
|
|
82
84
|
// which game to play; defaults to 'trivia'
|
|
83
85
|
totalRounds: z.number().int().min(1).max(50),
|
|
84
|
-
categoryIds: z.array(z.string().max(60)).min(
|
|
86
|
+
categoryIds: z.array(z.string().max(60)).min(0).max(12),
|
|
87
|
+
// empty for games without categories (Dama); trivia rejects empty in-handler
|
|
85
88
|
// PREFERRED: pick a mode from the registry (see MODES). The server maps it to the engine
|
|
86
89
|
// rules. Send this and omit buzzerMode/noHost. Falls back to the legacy flags below if omitted.
|
|
87
90
|
modeId: z.enum(MODE_IDS).optional(),
|
|
@@ -118,7 +121,19 @@ var ClientMsg = z.discriminatedUnion("t", [
|
|
|
118
121
|
// Report the CURRENT question as bad (wrong answer / typo / offensive). The relay resolves WHICH
|
|
119
122
|
// question from its authoritative room state — the client never sees the question id (anti-cheat),
|
|
120
123
|
// so it only sends an optional `reason`. Only meaningful while a question is on screen.
|
|
121
|
-
z.object({ t: z.literal("reportQuestion"), reason: z.string().max(500).optional() })
|
|
124
|
+
z.object({ t: z.literal("reportQuestion"), reason: z.string().max(500).optional() }),
|
|
125
|
+
// ── Dama slice (gameId 'dama', engine #2 — D-027) ──
|
|
126
|
+
// Make a Dama move: from → to (board coords, 0–7). The relay validates legality against the engine
|
|
127
|
+
// (Shape B) and rejects anything not in legalMoves. If two capture chains share from+to (rare), the
|
|
128
|
+
// relay picks the max-capture one; a client MAY send the full landing `path` to disambiguate.
|
|
129
|
+
z.object({
|
|
130
|
+
t: z.literal("damaMove"),
|
|
131
|
+
from: z.object({ r: z.number().int().min(0).max(7), c: z.number().int().min(0).max(7) }),
|
|
132
|
+
to: z.object({ r: z.number().int().min(0).max(7), c: z.number().int().min(0).max(7) }),
|
|
133
|
+
path: z.array(z.object({ r: z.number().int().min(0).max(7), c: z.number().int().min(0).max(7) })).max(12).optional()
|
|
134
|
+
}),
|
|
135
|
+
// Resign the current Dama game (concede) → opponent wins.
|
|
136
|
+
z.object({ t: z.literal("damaResign") })
|
|
122
137
|
]);
|
|
123
138
|
export {
|
|
124
139
|
ClientMsg,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thegeem/protocol",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "Geem's wire protocol — shared zod schemas + TypeScript types for talking to the Geem game server over Socket.IO. The source of truth all clients implement against.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"homepage": "https://geem.tv",
|