@thegeem/protocol 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -52,15 +52,25 @@ var HelpType = import_zod.z.enum([
52
52
  ]);
53
53
  var Pv = import_zod.z.number().int().min(1).max(1e6).optional();
54
54
  var IdToken = import_zod.z.string().max(4096).optional();
55
+ var Avatar = import_zod.z.object({
56
+ emoji: import_zod.z.string().min(1).max(16).transform((s) => s.replace(UNSAFE_CHARS, "")).refine((s) => s.length >= 1, "empty emoji"),
57
+ color: import_zod.z.string().regex(/^#[0-9a-fA-F]{6}$/, "color must be #rrggbb")
58
+ });
55
59
  var ClientMsg = import_zod.z.discriminatedUnion("t", [
56
60
  // room / lobby
57
- import_zod.z.object({ t: import_zod.z.literal("createRoom"), name: DisplayName.optional(), pv: Pv, idToken: IdToken }),
58
- import_zod.z.object({ t: import_zod.z.literal("joinRoom"), code: RoomCode, name: DisplayName, pv: Pv, idToken: IdToken }),
59
- import_zod.z.object({ t: import_zod.z.literal("resume"), code: RoomCode, token: import_zod.z.string().max(120), pv: Pv, idToken: IdToken }),
61
+ import_zod.z.object({ t: import_zod.z.literal("createRoom"), name: DisplayName.optional(), avatar: Avatar.optional(), pv: Pv, idToken: IdToken }),
62
+ // Host sets/changes their display name AFTER createRoom (for anonymous one-tap
63
+ // hosts who started nameless). Host-only; the relay re-broadcasts the lobby.
64
+ import_zod.z.object({ t: import_zod.z.literal("renameHost"), name: DisplayName }),
65
+ import_zod.z.object({ t: import_zod.z.literal("joinRoom"), code: RoomCode, name: DisplayName, avatar: Avatar.optional(), pv: Pv, idToken: IdToken }),
66
+ import_zod.z.object({ t: import_zod.z.literal("resume"), code: RoomCode, token: import_zod.z.string().max(120), avatar: Avatar.optional(), pv: Pv, idToken: IdToken }),
60
67
  import_zod.z.object({ t: import_zod.z.literal("leaveRoom") }),
61
68
  import_zod.z.object({ t: import_zod.z.literal("approve"), playerId: PlayerId }),
62
69
  import_zod.z.object({ t: import_zod.z.literal("reject"), playerId: PlayerId }),
63
70
  import_zod.z.object({ t: import_zod.z.literal("kick"), playerId: PlayerId }),
71
+ // Host's IN-PROGRESS category selection in the lobby — a live preview for waiting
72
+ // players. Distinct from startGame.categoryIds, which COMMITS the board. Empty = cleared.
73
+ import_zod.z.object({ t: import_zod.z.literal("setCategories"), categoryIds: import_zod.z.array(import_zod.z.string().max(60)).max(12) }),
64
74
  // host game actions
65
75
  import_zod.z.object({
66
76
  t: import_zod.z.literal("startGame"),
@@ -75,14 +85,17 @@ var ClientMsg = import_zod.z.discriminatedUnion("t", [
75
85
  // host: after a game ends, return the SAME players to the lobby
76
86
  import_zod.z.object({ t: import_zod.z.literal("markOpen"), correct: import_zod.z.boolean() }),
77
87
  import_zod.z.object({ t: import_zod.z.literal("revealNoHost") }),
78
- import_zod.z.object({ t: import_zod.z.literal("awardNoHost"), teamIndex: import_zod.z.number().int().min(0).max(LIMITS.MAX_PLAYERS) }),
88
+ import_zod.z.object({ t: import_zod.z.literal("awardNoHost"), teamIndex: import_zod.z.number().int().min(0).max(LIMITS.MAX_PLAYERS - 1) }),
89
+ // 0-based team index
79
90
  import_zod.z.object({ t: import_zod.z.literal("noHostNobody") }),
80
91
  // player actions
81
92
  import_zod.z.object({ t: import_zod.z.literal("buzz") }),
82
- import_zod.z.object({ t: import_zod.z.literal("answer"), index: import_zod.z.number().int().min(0).max(10) }),
93
+ import_zod.z.object({ t: import_zod.z.literal("answer"), index: import_zod.z.number().int().min(0).max(3) }),
94
+ // trivia is 4-option (0–3)
83
95
  import_zod.z.object({ t: import_zod.z.literal("useHelp"), helpType: HelpType }),
84
96
  // sabotage a rival (active team only): spend a sabotage help to debuff targetTeam's next question
85
- import_zod.z.object({ t: import_zod.z.literal("sabotage"), helpType: HelpType, targetTeam: import_zod.z.number().int().min(0).max(LIMITS.MAX_PLAYERS) })
97
+ import_zod.z.object({ t: import_zod.z.literal("sabotage"), helpType: HelpType, targetTeam: import_zod.z.number().int().min(0).max(LIMITS.MAX_PLAYERS - 1) })
98
+ // 0-based team index
86
99
  ]);
87
100
  // Annotate the CommonJS export names for ESM import in node:
88
101
  0 && (module.exports = {
package/dist/index.d.cts CHANGED
@@ -43,52 +43,115 @@ declare const HelpType: z.ZodEnum<["removeTwoAnswers", "changeQuestion", "extraT
43
43
  declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
44
44
  t: z.ZodLiteral<"createRoom">;
45
45
  name: z.ZodOptional<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>>;
46
+ avatar: z.ZodOptional<z.ZodObject<{
47
+ emoji: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
48
+ color: z.ZodString;
49
+ }, "strip", z.ZodTypeAny, {
50
+ emoji: string;
51
+ color: string;
52
+ }, {
53
+ emoji: string;
54
+ color: string;
55
+ }>>;
46
56
  pv: z.ZodOptional<z.ZodNumber>;
47
57
  idToken: z.ZodOptional<z.ZodString>;
48
58
  }, "strip", z.ZodTypeAny, {
49
59
  t: "createRoom";
50
60
  name?: string | undefined;
61
+ avatar?: {
62
+ emoji: string;
63
+ color: string;
64
+ } | undefined;
51
65
  pv?: number | undefined;
52
66
  idToken?: string | undefined;
53
67
  }, {
54
68
  t: "createRoom";
55
69
  name?: string | undefined;
70
+ avatar?: {
71
+ emoji: string;
72
+ color: string;
73
+ } | undefined;
56
74
  pv?: number | undefined;
57
75
  idToken?: string | undefined;
76
+ }>, z.ZodObject<{
77
+ t: z.ZodLiteral<"renameHost">;
78
+ name: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
79
+ }, "strip", z.ZodTypeAny, {
80
+ t: "renameHost";
81
+ name: string;
82
+ }, {
83
+ t: "renameHost";
84
+ name: string;
58
85
  }>, z.ZodObject<{
59
86
  t: z.ZodLiteral<"joinRoom">;
60
87
  code: z.ZodString;
61
88
  name: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
89
+ avatar: z.ZodOptional<z.ZodObject<{
90
+ emoji: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
91
+ color: z.ZodString;
92
+ }, "strip", z.ZodTypeAny, {
93
+ emoji: string;
94
+ color: string;
95
+ }, {
96
+ emoji: string;
97
+ color: string;
98
+ }>>;
62
99
  pv: z.ZodOptional<z.ZodNumber>;
63
100
  idToken: z.ZodOptional<z.ZodString>;
64
101
  }, "strip", z.ZodTypeAny, {
65
102
  code: string;
66
103
  t: "joinRoom";
67
104
  name: string;
105
+ avatar?: {
106
+ emoji: string;
107
+ color: string;
108
+ } | undefined;
68
109
  pv?: number | undefined;
69
110
  idToken?: string | undefined;
70
111
  }, {
71
112
  code: string;
72
113
  t: "joinRoom";
73
114
  name: string;
115
+ avatar?: {
116
+ emoji: string;
117
+ color: string;
118
+ } | undefined;
74
119
  pv?: number | undefined;
75
120
  idToken?: string | undefined;
76
121
  }>, z.ZodObject<{
77
122
  t: z.ZodLiteral<"resume">;
78
123
  code: z.ZodString;
79
124
  token: z.ZodString;
125
+ avatar: z.ZodOptional<z.ZodObject<{
126
+ emoji: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
127
+ color: z.ZodString;
128
+ }, "strip", z.ZodTypeAny, {
129
+ emoji: string;
130
+ color: string;
131
+ }, {
132
+ emoji: string;
133
+ color: string;
134
+ }>>;
80
135
  pv: z.ZodOptional<z.ZodNumber>;
81
136
  idToken: z.ZodOptional<z.ZodString>;
82
137
  }, "strip", z.ZodTypeAny, {
83
138
  code: string;
84
139
  t: "resume";
85
140
  token: string;
141
+ avatar?: {
142
+ emoji: string;
143
+ color: string;
144
+ } | undefined;
86
145
  pv?: number | undefined;
87
146
  idToken?: string | undefined;
88
147
  }, {
89
148
  code: string;
90
149
  t: "resume";
91
150
  token: string;
151
+ avatar?: {
152
+ emoji: string;
153
+ color: string;
154
+ } | undefined;
92
155
  pv?: number | undefined;
93
156
  idToken?: string | undefined;
94
157
  }>, z.ZodObject<{
@@ -124,6 +187,15 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
124
187
  }, {
125
188
  t: "kick";
126
189
  playerId: string;
190
+ }>, z.ZodObject<{
191
+ t: z.ZodLiteral<"setCategories">;
192
+ categoryIds: z.ZodArray<z.ZodString, "many">;
193
+ }, "strip", z.ZodTypeAny, {
194
+ t: "setCategories";
195
+ categoryIds: string[];
196
+ }, {
197
+ t: "setCategories";
198
+ categoryIds: string[];
127
199
  }>, z.ZodObject<{
128
200
  t: z.ZodLiteral<"startGame">;
129
201
  game: z.ZodOptional<z.ZodEnum<["trivia"]>>;
@@ -131,13 +203,13 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
131
203
  categoryIds: z.ZodArray<z.ZodString, "many">;
132
204
  }, "strip", z.ZodTypeAny, {
133
205
  t: "startGame";
134
- totalRounds: number;
135
206
  categoryIds: string[];
207
+ totalRounds: number;
136
208
  game?: "trivia" | undefined;
137
209
  }, {
138
210
  t: "startGame";
139
- totalRounds: number;
140
211
  categoryIds: string[];
212
+ totalRounds: number;
141
213
  game?: "trivia" | undefined;
142
214
  }>, z.ZodObject<{
143
215
  t: z.ZodLiteral<"pickLevel">;
@@ -231,11 +303,20 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
231
303
  targetTeam: number;
232
304
  }>]>;
233
305
  type ClientMsg = z.infer<typeof ClientMsg>;
306
+ /** A player's privacy-safe avatar (emoji + circle color) for in-room display. */
307
+ interface AvatarView {
308
+ emoji: string;
309
+ color: string;
310
+ }
234
311
  interface LobbyPlayer {
235
312
  id: string;
236
313
  name: string;
237
314
  approved: boolean;
238
315
  connected: boolean;
316
+ /** Privacy-safe avatar (emoji + color); absent if the player didn't set one. */
317
+ avatar?: AvatarView;
318
+ /** Team index once the game has started; null/absent in the lobby. */
319
+ teamIndex?: number | null;
239
320
  }
240
321
  /** Per-recipient context attached to lobby/state pushes. */
241
322
  interface YouContext {
@@ -271,6 +352,8 @@ interface TeamView {
271
352
  type: HelpName;
272
353
  isUsed: boolean;
273
354
  }[];
355
+ /** The seated player's privacy-safe avatar (relay-enriched; engine view omits it). */
356
+ avatar?: AvatarView;
274
357
  }
275
358
  interface QuestionView {
276
359
  text: string;
@@ -381,6 +464,7 @@ type ServerMsg = {
381
464
  hostName: string;
382
465
  players: LobbyPlayer[];
383
466
  categories: CategoryView[];
467
+ selectedCategoryIds: string[];
384
468
  you: YouContext;
385
469
  } | {
386
470
  t: 'state';
@@ -397,4 +481,4 @@ type ServerMsg = {
397
481
  message: string;
398
482
  };
399
483
 
400
- export { type BuzzerGameMode, type CategoryView, ClientMsg, type Effect, GAME_IDS, type GameId, type GameStateView, type GameStatus, type GameplayFlow, type HelpName, LIMITS, type LobbyPlayer, PROTOCOL_VERSION, type QuestionView, ROOM_ALPHABET, type ServerMsg, type SoundName, type TeamView, type YouContext };
484
+ export { type AvatarView, type BuzzerGameMode, type CategoryView, ClientMsg, type Effect, GAME_IDS, type GameId, type GameStateView, type GameStatus, type GameplayFlow, type HelpName, LIMITS, type LobbyPlayer, PROTOCOL_VERSION, type QuestionView, ROOM_ALPHABET, type ServerMsg, type SoundName, type TeamView, type YouContext };
package/dist/index.d.ts CHANGED
@@ -43,52 +43,115 @@ declare const HelpType: z.ZodEnum<["removeTwoAnswers", "changeQuestion", "extraT
43
43
  declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
44
44
  t: z.ZodLiteral<"createRoom">;
45
45
  name: z.ZodOptional<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>>;
46
+ avatar: z.ZodOptional<z.ZodObject<{
47
+ emoji: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
48
+ color: z.ZodString;
49
+ }, "strip", z.ZodTypeAny, {
50
+ emoji: string;
51
+ color: string;
52
+ }, {
53
+ emoji: string;
54
+ color: string;
55
+ }>>;
46
56
  pv: z.ZodOptional<z.ZodNumber>;
47
57
  idToken: z.ZodOptional<z.ZodString>;
48
58
  }, "strip", z.ZodTypeAny, {
49
59
  t: "createRoom";
50
60
  name?: string | undefined;
61
+ avatar?: {
62
+ emoji: string;
63
+ color: string;
64
+ } | undefined;
51
65
  pv?: number | undefined;
52
66
  idToken?: string | undefined;
53
67
  }, {
54
68
  t: "createRoom";
55
69
  name?: string | undefined;
70
+ avatar?: {
71
+ emoji: string;
72
+ color: string;
73
+ } | undefined;
56
74
  pv?: number | undefined;
57
75
  idToken?: string | undefined;
76
+ }>, z.ZodObject<{
77
+ t: z.ZodLiteral<"renameHost">;
78
+ name: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
79
+ }, "strip", z.ZodTypeAny, {
80
+ t: "renameHost";
81
+ name: string;
82
+ }, {
83
+ t: "renameHost";
84
+ name: string;
58
85
  }>, z.ZodObject<{
59
86
  t: z.ZodLiteral<"joinRoom">;
60
87
  code: z.ZodString;
61
88
  name: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
89
+ avatar: z.ZodOptional<z.ZodObject<{
90
+ emoji: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
91
+ color: z.ZodString;
92
+ }, "strip", z.ZodTypeAny, {
93
+ emoji: string;
94
+ color: string;
95
+ }, {
96
+ emoji: string;
97
+ color: string;
98
+ }>>;
62
99
  pv: z.ZodOptional<z.ZodNumber>;
63
100
  idToken: z.ZodOptional<z.ZodString>;
64
101
  }, "strip", z.ZodTypeAny, {
65
102
  code: string;
66
103
  t: "joinRoom";
67
104
  name: string;
105
+ avatar?: {
106
+ emoji: string;
107
+ color: string;
108
+ } | undefined;
68
109
  pv?: number | undefined;
69
110
  idToken?: string | undefined;
70
111
  }, {
71
112
  code: string;
72
113
  t: "joinRoom";
73
114
  name: string;
115
+ avatar?: {
116
+ emoji: string;
117
+ color: string;
118
+ } | undefined;
74
119
  pv?: number | undefined;
75
120
  idToken?: string | undefined;
76
121
  }>, z.ZodObject<{
77
122
  t: z.ZodLiteral<"resume">;
78
123
  code: z.ZodString;
79
124
  token: z.ZodString;
125
+ avatar: z.ZodOptional<z.ZodObject<{
126
+ emoji: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
127
+ color: z.ZodString;
128
+ }, "strip", z.ZodTypeAny, {
129
+ emoji: string;
130
+ color: string;
131
+ }, {
132
+ emoji: string;
133
+ color: string;
134
+ }>>;
80
135
  pv: z.ZodOptional<z.ZodNumber>;
81
136
  idToken: z.ZodOptional<z.ZodString>;
82
137
  }, "strip", z.ZodTypeAny, {
83
138
  code: string;
84
139
  t: "resume";
85
140
  token: string;
141
+ avatar?: {
142
+ emoji: string;
143
+ color: string;
144
+ } | undefined;
86
145
  pv?: number | undefined;
87
146
  idToken?: string | undefined;
88
147
  }, {
89
148
  code: string;
90
149
  t: "resume";
91
150
  token: string;
151
+ avatar?: {
152
+ emoji: string;
153
+ color: string;
154
+ } | undefined;
92
155
  pv?: number | undefined;
93
156
  idToken?: string | undefined;
94
157
  }>, z.ZodObject<{
@@ -124,6 +187,15 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
124
187
  }, {
125
188
  t: "kick";
126
189
  playerId: string;
190
+ }>, z.ZodObject<{
191
+ t: z.ZodLiteral<"setCategories">;
192
+ categoryIds: z.ZodArray<z.ZodString, "many">;
193
+ }, "strip", z.ZodTypeAny, {
194
+ t: "setCategories";
195
+ categoryIds: string[];
196
+ }, {
197
+ t: "setCategories";
198
+ categoryIds: string[];
127
199
  }>, z.ZodObject<{
128
200
  t: z.ZodLiteral<"startGame">;
129
201
  game: z.ZodOptional<z.ZodEnum<["trivia"]>>;
@@ -131,13 +203,13 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
131
203
  categoryIds: z.ZodArray<z.ZodString, "many">;
132
204
  }, "strip", z.ZodTypeAny, {
133
205
  t: "startGame";
134
- totalRounds: number;
135
206
  categoryIds: string[];
207
+ totalRounds: number;
136
208
  game?: "trivia" | undefined;
137
209
  }, {
138
210
  t: "startGame";
139
- totalRounds: number;
140
211
  categoryIds: string[];
212
+ totalRounds: number;
141
213
  game?: "trivia" | undefined;
142
214
  }>, z.ZodObject<{
143
215
  t: z.ZodLiteral<"pickLevel">;
@@ -231,11 +303,20 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
231
303
  targetTeam: number;
232
304
  }>]>;
233
305
  type ClientMsg = z.infer<typeof ClientMsg>;
306
+ /** A player's privacy-safe avatar (emoji + circle color) for in-room display. */
307
+ interface AvatarView {
308
+ emoji: string;
309
+ color: string;
310
+ }
234
311
  interface LobbyPlayer {
235
312
  id: string;
236
313
  name: string;
237
314
  approved: boolean;
238
315
  connected: boolean;
316
+ /** Privacy-safe avatar (emoji + color); absent if the player didn't set one. */
317
+ avatar?: AvatarView;
318
+ /** Team index once the game has started; null/absent in the lobby. */
319
+ teamIndex?: number | null;
239
320
  }
240
321
  /** Per-recipient context attached to lobby/state pushes. */
241
322
  interface YouContext {
@@ -271,6 +352,8 @@ interface TeamView {
271
352
  type: HelpName;
272
353
  isUsed: boolean;
273
354
  }[];
355
+ /** The seated player's privacy-safe avatar (relay-enriched; engine view omits it). */
356
+ avatar?: AvatarView;
274
357
  }
275
358
  interface QuestionView {
276
359
  text: string;
@@ -381,6 +464,7 @@ type ServerMsg = {
381
464
  hostName: string;
382
465
  players: LobbyPlayer[];
383
466
  categories: CategoryView[];
467
+ selectedCategoryIds: string[];
384
468
  you: YouContext;
385
469
  } | {
386
470
  t: 'state';
@@ -397,4 +481,4 @@ type ServerMsg = {
397
481
  message: string;
398
482
  };
399
483
 
400
- export { type BuzzerGameMode, type CategoryView, ClientMsg, type Effect, GAME_IDS, type GameId, type GameStateView, type GameStatus, type GameplayFlow, type HelpName, LIMITS, type LobbyPlayer, PROTOCOL_VERSION, type QuestionView, ROOM_ALPHABET, type ServerMsg, type SoundName, type TeamView, type YouContext };
484
+ export { type AvatarView, type BuzzerGameMode, type CategoryView, ClientMsg, type Effect, GAME_IDS, type GameId, type GameStateView, type GameStatus, type GameplayFlow, type HelpName, LIMITS, type LobbyPlayer, PROTOCOL_VERSION, type QuestionView, ROOM_ALPHABET, type ServerMsg, type SoundName, type TeamView, type YouContext };
package/dist/index.js CHANGED
@@ -24,15 +24,25 @@ var HelpType = z.enum([
24
24
  ]);
25
25
  var Pv = z.number().int().min(1).max(1e6).optional();
26
26
  var IdToken = z.string().max(4096).optional();
27
+ var Avatar = z.object({
28
+ emoji: z.string().min(1).max(16).transform((s) => s.replace(UNSAFE_CHARS, "")).refine((s) => s.length >= 1, "empty emoji"),
29
+ color: z.string().regex(/^#[0-9a-fA-F]{6}$/, "color must be #rrggbb")
30
+ });
27
31
  var ClientMsg = z.discriminatedUnion("t", [
28
32
  // room / lobby
29
- z.object({ t: z.literal("createRoom"), name: DisplayName.optional(), pv: Pv, idToken: IdToken }),
30
- z.object({ t: z.literal("joinRoom"), code: RoomCode, name: DisplayName, pv: Pv, idToken: IdToken }),
31
- z.object({ t: z.literal("resume"), code: RoomCode, token: z.string().max(120), pv: Pv, idToken: IdToken }),
33
+ z.object({ t: z.literal("createRoom"), name: DisplayName.optional(), avatar: Avatar.optional(), pv: Pv, idToken: IdToken }),
34
+ // Host sets/changes their display name AFTER createRoom (for anonymous one-tap
35
+ // hosts who started nameless). Host-only; the relay re-broadcasts the lobby.
36
+ z.object({ t: z.literal("renameHost"), name: DisplayName }),
37
+ z.object({ t: z.literal("joinRoom"), code: RoomCode, name: DisplayName, avatar: Avatar.optional(), pv: Pv, idToken: IdToken }),
38
+ z.object({ t: z.literal("resume"), code: RoomCode, token: z.string().max(120), avatar: Avatar.optional(), pv: Pv, idToken: IdToken }),
32
39
  z.object({ t: z.literal("leaveRoom") }),
33
40
  z.object({ t: z.literal("approve"), playerId: PlayerId }),
34
41
  z.object({ t: z.literal("reject"), playerId: PlayerId }),
35
42
  z.object({ t: z.literal("kick"), playerId: PlayerId }),
43
+ // Host's IN-PROGRESS category selection in the lobby — a live preview for waiting
44
+ // players. Distinct from startGame.categoryIds, which COMMITS the board. Empty = cleared.
45
+ z.object({ t: z.literal("setCategories"), categoryIds: z.array(z.string().max(60)).max(12) }),
36
46
  // host game actions
37
47
  z.object({
38
48
  t: z.literal("startGame"),
@@ -47,14 +57,17 @@ var ClientMsg = z.discriminatedUnion("t", [
47
57
  // host: after a game ends, return the SAME players to the lobby
48
58
  z.object({ t: z.literal("markOpen"), correct: z.boolean() }),
49
59
  z.object({ t: z.literal("revealNoHost") }),
50
- z.object({ t: z.literal("awardNoHost"), teamIndex: z.number().int().min(0).max(LIMITS.MAX_PLAYERS) }),
60
+ z.object({ t: z.literal("awardNoHost"), teamIndex: z.number().int().min(0).max(LIMITS.MAX_PLAYERS - 1) }),
61
+ // 0-based team index
51
62
  z.object({ t: z.literal("noHostNobody") }),
52
63
  // player actions
53
64
  z.object({ t: z.literal("buzz") }),
54
- z.object({ t: z.literal("answer"), index: z.number().int().min(0).max(10) }),
65
+ z.object({ t: z.literal("answer"), index: z.number().int().min(0).max(3) }),
66
+ // trivia is 4-option (0–3)
55
67
  z.object({ t: z.literal("useHelp"), helpType: HelpType }),
56
68
  // sabotage a rival (active team only): spend a sabotage help to debuff targetTeam's next question
57
- z.object({ t: z.literal("sabotage"), helpType: HelpType, targetTeam: z.number().int().min(0).max(LIMITS.MAX_PLAYERS) })
69
+ z.object({ t: z.literal("sabotage"), helpType: HelpType, targetTeam: z.number().int().min(0).max(LIMITS.MAX_PLAYERS - 1) })
70
+ // 0-based team index
58
71
  ]);
59
72
  export {
60
73
  ClientMsg,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thegeem/protocol",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
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",