@thegeem/protocol 0.1.32 → 0.1.34

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
@@ -90,6 +90,7 @@ var HelpType = import_zod.z.enum([
90
90
  var Pv = import_zod.z.number().int().min(1).max(1e6).optional();
91
91
  var IdToken = import_zod.z.string().max(4096).optional();
92
92
  var Platform = import_zod.z.enum(["web", "ios", "android"]).optional();
93
+ var AppVersion = import_zod.z.string().trim().max(24).regex(/^[0-9]+(\.[0-9]+){0,3}([-+][0-9A-Za-z.-]+)?$/, "bad app version").optional();
93
94
  var Avatar = import_zod.z.object({
94
95
  emoji: import_zod.z.string().min(1).max(16).transform((s) => s.replace(UNSAFE_CHARS, "")).refine((s) => s.length >= 1, "empty emoji"),
95
96
  color: import_zod.z.string().regex(/^#[0-9a-fA-F]{6}$/, "color must be #rrggbb")
@@ -97,7 +98,7 @@ var Avatar = import_zod.z.object({
97
98
  var Character = import_zod.z.enum(CHARACTER_IDS);
98
99
  var ClientMsg = import_zod.z.discriminatedUnion("t", [
99
100
  // room / lobby
100
- import_zod.z.object({ t: import_zod.z.literal("createRoom"), name: DisplayName.optional(), avatar: Avatar.optional(), game: import_zod.z.enum(GAME_IDS).optional(), character: Character.optional(), pv: Pv, idToken: IdToken, platform: Platform }),
101
+ import_zod.z.object({ t: import_zod.z.literal("createRoom"), name: DisplayName.optional(), avatar: Avatar.optional(), game: import_zod.z.enum(GAME_IDS).optional(), character: Character.optional(), pv: Pv, idToken: IdToken, platform: Platform, appVersion: AppVersion }),
101
102
  // Host sets/changes their display name AFTER createRoom (for anonymous one-tap
102
103
  // hosts who started nameless). Host-only; the relay re-broadcasts the lobby.
103
104
  // SUPERSEDED by setProfile (kept working for shipped builds).
@@ -111,8 +112,8 @@ var ClientMsg = import_zod.z.discriminatedUnion("t", [
111
112
  // view carries names+avatars so it updates live; dama/ersimha views are id-keyed (clients
112
113
  // map ids→names from the lobby roster), so a change there lands on the next lobby.
113
114
  import_zod.z.object({ t: import_zod.z.literal("setProfile"), name: DisplayName.optional(), avatar: Avatar.optional(), character: Character.optional() }),
114
- import_zod.z.object({ t: import_zod.z.literal("joinRoom"), code: RoomCode, name: DisplayName, avatar: Avatar.optional(), character: Character.optional(), pv: Pv, idToken: IdToken, platform: Platform }),
115
- import_zod.z.object({ t: import_zod.z.literal("resume"), code: RoomCode, token: import_zod.z.string().max(120), avatar: Avatar.optional(), character: Character.optional(), pv: Pv, idToken: IdToken, platform: Platform }),
115
+ import_zod.z.object({ t: import_zod.z.literal("joinRoom"), code: RoomCode, name: DisplayName, avatar: Avatar.optional(), character: Character.optional(), pv: Pv, idToken: IdToken, platform: Platform, appVersion: AppVersion }),
116
+ import_zod.z.object({ t: import_zod.z.literal("resume"), code: RoomCode, token: import_zod.z.string().max(120), avatar: Avatar.optional(), character: Character.optional(), pv: Pv, idToken: IdToken, platform: Platform, appVersion: AppVersion }),
116
117
  // `tally` (gs#46) = wins per PLAYER across every game this room has played tonight — «نتيجة الليلة».
117
118
  // Keyed by playerId, NOT by team: team names are recycled each game, so a per-team count means nothing
118
119
  // across a night. Survives playAgain. A One Device game credits nobody (its team slots hold no players).
@@ -176,6 +177,13 @@ var ClientMsg = import_zod.z.discriminatedUnion("t", [
176
177
  // an explicit seating beats an implicit one.
177
178
  // Violations are rejected with `invalid_seat`. Consumed by دامة (the only fixed-seat game today).
178
179
  players: import_zod.z.array(PlayerId).min(1).max(LIMITS.MAX_PLAYERS).optional(),
180
+ // SOLO vs the machine (gs#68). Fills the seats a game needs that no human took, so one person can
181
+ // play with nobody else around — دامة's «تمرين». Additive, no pv bump; omit it and nothing changes.
182
+ // The bot is a SEAT the relay drives, never something a client runs: Shape B means the server is
183
+ // still the referee, and a client-side opponent could not be trusted with the board anyway.
184
+ // `difficulty` is one search with different depth+noise, not three implementations.
185
+ // Solo games are deliberately NOT RATED and never touch the دامة ELO ladder — see the driver.
186
+ bot: import_zod.z.object({ difficulty: import_zod.z.enum(["easy", "medium", "hard"]).optional() }).optional(),
179
187
  // PREFERRED: pick a mode from the registry (see MODES). The server maps it to the engine
180
188
  // rules. Send this and omit buzzerMode/noHost. Falls back to the legacy flags below if omitted.
181
189
  modeId: import_zod.z.enum(MODE_IDS).optional(),
package/dist/index.d.cts CHANGED
@@ -122,6 +122,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
122
122
  pv: z.ZodOptional<z.ZodNumber>;
123
123
  idToken: z.ZodOptional<z.ZodString>;
124
124
  platform: z.ZodOptional<z.ZodEnum<["web", "ios", "android"]>>;
125
+ appVersion: z.ZodOptional<z.ZodString>;
125
126
  }, "strip", z.ZodTypeAny, {
126
127
  t: "createRoom";
127
128
  name?: string | undefined;
@@ -134,6 +135,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
134
135
  pv?: number | undefined;
135
136
  idToken?: string | undefined;
136
137
  platform?: "web" | "ios" | "android" | undefined;
138
+ appVersion?: string | undefined;
137
139
  }, {
138
140
  t: "createRoom";
139
141
  name?: string | undefined;
@@ -146,6 +148,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
146
148
  pv?: number | undefined;
147
149
  idToken?: string | undefined;
148
150
  platform?: "web" | "ios" | "android" | undefined;
151
+ appVersion?: string | undefined;
149
152
  }>, z.ZodObject<{
150
153
  t: z.ZodLiteral<"renameHost">;
151
154
  name: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
@@ -203,6 +206,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
203
206
  pv: z.ZodOptional<z.ZodNumber>;
204
207
  idToken: z.ZodOptional<z.ZodString>;
205
208
  platform: z.ZodOptional<z.ZodEnum<["web", "ios", "android"]>>;
209
+ appVersion: z.ZodOptional<z.ZodString>;
206
210
  }, "strip", z.ZodTypeAny, {
207
211
  code: string;
208
212
  t: "joinRoom";
@@ -215,6 +219,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
215
219
  pv?: number | undefined;
216
220
  idToken?: string | undefined;
217
221
  platform?: "web" | "ios" | "android" | undefined;
222
+ appVersion?: string | undefined;
218
223
  }, {
219
224
  code: string;
220
225
  t: "joinRoom";
@@ -227,6 +232,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
227
232
  pv?: number | undefined;
228
233
  idToken?: string | undefined;
229
234
  platform?: "web" | "ios" | "android" | undefined;
235
+ appVersion?: string | undefined;
230
236
  }>, z.ZodObject<{
231
237
  t: z.ZodLiteral<"resume">;
232
238
  code: z.ZodString;
@@ -245,6 +251,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
245
251
  pv: z.ZodOptional<z.ZodNumber>;
246
252
  idToken: z.ZodOptional<z.ZodString>;
247
253
  platform: z.ZodOptional<z.ZodEnum<["web", "ios", "android"]>>;
254
+ appVersion: z.ZodOptional<z.ZodString>;
248
255
  }, "strip", z.ZodTypeAny, {
249
256
  code: string;
250
257
  t: "resume";
@@ -257,6 +264,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
257
264
  pv?: number | undefined;
258
265
  idToken?: string | undefined;
259
266
  platform?: "web" | "ios" | "android" | undefined;
267
+ appVersion?: string | undefined;
260
268
  }, {
261
269
  code: string;
262
270
  t: "resume";
@@ -269,6 +277,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
269
277
  pv?: number | undefined;
270
278
  idToken?: string | undefined;
271
279
  platform?: "web" | "ios" | "android" | undefined;
280
+ appVersion?: string | undefined;
272
281
  }>, z.ZodObject<{
273
282
  t: z.ZodLiteral<"setPlaying">;
274
283
  playerId: z.ZodOptional<z.ZodString>;
@@ -369,6 +378,13 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
369
378
  categoryIds: z.ZodArray<z.ZodString, "many">;
370
379
  hostPlays: z.ZodOptional<z.ZodBoolean>;
371
380
  players: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
381
+ bot: z.ZodOptional<z.ZodObject<{
382
+ difficulty: z.ZodOptional<z.ZodEnum<["easy", "medium", "hard"]>>;
383
+ }, "strip", z.ZodTypeAny, {
384
+ difficulty?: "easy" | "medium" | "hard" | undefined;
385
+ }, {
386
+ difficulty?: "easy" | "medium" | "hard" | undefined;
387
+ }>>;
372
388
  modeId: z.ZodOptional<z.ZodEnum<["solo", "oneDevice", "snag", "multiplayer"]>>;
373
389
  buzzerMode: z.ZodOptional<z.ZodEnum<["off", "solo", "race", "controller"]>>;
374
390
  noHost: z.ZodOptional<z.ZodBoolean>;
@@ -380,6 +396,9 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
380
396
  modeId?: "snag" | "solo" | "oneDevice" | "multiplayer" | undefined;
381
397
  hostPlays?: boolean | undefined;
382
398
  players?: string[] | undefined;
399
+ bot?: {
400
+ difficulty?: "easy" | "medium" | "hard" | undefined;
401
+ } | undefined;
383
402
  buzzerMode?: "solo" | "off" | "race" | "controller" | undefined;
384
403
  noHost?: boolean | undefined;
385
404
  }, {
@@ -390,6 +409,9 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
390
409
  modeId?: "snag" | "solo" | "oneDevice" | "multiplayer" | undefined;
391
410
  hostPlays?: boolean | undefined;
392
411
  players?: string[] | undefined;
412
+ bot?: {
413
+ difficulty?: "easy" | "medium" | "hard" | undefined;
414
+ } | undefined;
393
415
  buzzerMode?: "solo" | "off" | "race" | "controller" | undefined;
394
416
  noHost?: boolean | undefined;
395
417
  }>, z.ZodObject<{
package/dist/index.d.ts CHANGED
@@ -122,6 +122,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
122
122
  pv: z.ZodOptional<z.ZodNumber>;
123
123
  idToken: z.ZodOptional<z.ZodString>;
124
124
  platform: z.ZodOptional<z.ZodEnum<["web", "ios", "android"]>>;
125
+ appVersion: z.ZodOptional<z.ZodString>;
125
126
  }, "strip", z.ZodTypeAny, {
126
127
  t: "createRoom";
127
128
  name?: string | undefined;
@@ -134,6 +135,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
134
135
  pv?: number | undefined;
135
136
  idToken?: string | undefined;
136
137
  platform?: "web" | "ios" | "android" | undefined;
138
+ appVersion?: string | undefined;
137
139
  }, {
138
140
  t: "createRoom";
139
141
  name?: string | undefined;
@@ -146,6 +148,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
146
148
  pv?: number | undefined;
147
149
  idToken?: string | undefined;
148
150
  platform?: "web" | "ios" | "android" | undefined;
151
+ appVersion?: string | undefined;
149
152
  }>, z.ZodObject<{
150
153
  t: z.ZodLiteral<"renameHost">;
151
154
  name: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
@@ -203,6 +206,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
203
206
  pv: z.ZodOptional<z.ZodNumber>;
204
207
  idToken: z.ZodOptional<z.ZodString>;
205
208
  platform: z.ZodOptional<z.ZodEnum<["web", "ios", "android"]>>;
209
+ appVersion: z.ZodOptional<z.ZodString>;
206
210
  }, "strip", z.ZodTypeAny, {
207
211
  code: string;
208
212
  t: "joinRoom";
@@ -215,6 +219,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
215
219
  pv?: number | undefined;
216
220
  idToken?: string | undefined;
217
221
  platform?: "web" | "ios" | "android" | undefined;
222
+ appVersion?: string | undefined;
218
223
  }, {
219
224
  code: string;
220
225
  t: "joinRoom";
@@ -227,6 +232,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
227
232
  pv?: number | undefined;
228
233
  idToken?: string | undefined;
229
234
  platform?: "web" | "ios" | "android" | undefined;
235
+ appVersion?: string | undefined;
230
236
  }>, z.ZodObject<{
231
237
  t: z.ZodLiteral<"resume">;
232
238
  code: z.ZodString;
@@ -245,6 +251,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
245
251
  pv: z.ZodOptional<z.ZodNumber>;
246
252
  idToken: z.ZodOptional<z.ZodString>;
247
253
  platform: z.ZodOptional<z.ZodEnum<["web", "ios", "android"]>>;
254
+ appVersion: z.ZodOptional<z.ZodString>;
248
255
  }, "strip", z.ZodTypeAny, {
249
256
  code: string;
250
257
  t: "resume";
@@ -257,6 +264,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
257
264
  pv?: number | undefined;
258
265
  idToken?: string | undefined;
259
266
  platform?: "web" | "ios" | "android" | undefined;
267
+ appVersion?: string | undefined;
260
268
  }, {
261
269
  code: string;
262
270
  t: "resume";
@@ -269,6 +277,7 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
269
277
  pv?: number | undefined;
270
278
  idToken?: string | undefined;
271
279
  platform?: "web" | "ios" | "android" | undefined;
280
+ appVersion?: string | undefined;
272
281
  }>, z.ZodObject<{
273
282
  t: z.ZodLiteral<"setPlaying">;
274
283
  playerId: z.ZodOptional<z.ZodString>;
@@ -369,6 +378,13 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
369
378
  categoryIds: z.ZodArray<z.ZodString, "many">;
370
379
  hostPlays: z.ZodOptional<z.ZodBoolean>;
371
380
  players: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
381
+ bot: z.ZodOptional<z.ZodObject<{
382
+ difficulty: z.ZodOptional<z.ZodEnum<["easy", "medium", "hard"]>>;
383
+ }, "strip", z.ZodTypeAny, {
384
+ difficulty?: "easy" | "medium" | "hard" | undefined;
385
+ }, {
386
+ difficulty?: "easy" | "medium" | "hard" | undefined;
387
+ }>>;
372
388
  modeId: z.ZodOptional<z.ZodEnum<["solo", "oneDevice", "snag", "multiplayer"]>>;
373
389
  buzzerMode: z.ZodOptional<z.ZodEnum<["off", "solo", "race", "controller"]>>;
374
390
  noHost: z.ZodOptional<z.ZodBoolean>;
@@ -380,6 +396,9 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
380
396
  modeId?: "snag" | "solo" | "oneDevice" | "multiplayer" | undefined;
381
397
  hostPlays?: boolean | undefined;
382
398
  players?: string[] | undefined;
399
+ bot?: {
400
+ difficulty?: "easy" | "medium" | "hard" | undefined;
401
+ } | undefined;
383
402
  buzzerMode?: "solo" | "off" | "race" | "controller" | undefined;
384
403
  noHost?: boolean | undefined;
385
404
  }, {
@@ -390,6 +409,9 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
390
409
  modeId?: "snag" | "solo" | "oneDevice" | "multiplayer" | undefined;
391
410
  hostPlays?: boolean | undefined;
392
411
  players?: string[] | undefined;
412
+ bot?: {
413
+ difficulty?: "easy" | "medium" | "hard" | undefined;
414
+ } | undefined;
393
415
  buzzerMode?: "solo" | "off" | "race" | "controller" | undefined;
394
416
  noHost?: boolean | undefined;
395
417
  }>, z.ZodObject<{
package/dist/index.js CHANGED
@@ -53,6 +53,7 @@ var HelpType = z.enum([
53
53
  var Pv = z.number().int().min(1).max(1e6).optional();
54
54
  var IdToken = z.string().max(4096).optional();
55
55
  var Platform = z.enum(["web", "ios", "android"]).optional();
56
+ var AppVersion = z.string().trim().max(24).regex(/^[0-9]+(\.[0-9]+){0,3}([-+][0-9A-Za-z.-]+)?$/, "bad app version").optional();
56
57
  var Avatar = z.object({
57
58
  emoji: z.string().min(1).max(16).transform((s) => s.replace(UNSAFE_CHARS, "")).refine((s) => s.length >= 1, "empty emoji"),
58
59
  color: z.string().regex(/^#[0-9a-fA-F]{6}$/, "color must be #rrggbb")
@@ -60,7 +61,7 @@ var Avatar = z.object({
60
61
  var Character = z.enum(CHARACTER_IDS);
61
62
  var ClientMsg = z.discriminatedUnion("t", [
62
63
  // room / lobby
63
- z.object({ t: z.literal("createRoom"), name: DisplayName.optional(), avatar: Avatar.optional(), game: z.enum(GAME_IDS).optional(), character: Character.optional(), pv: Pv, idToken: IdToken, platform: Platform }),
64
+ z.object({ t: z.literal("createRoom"), name: DisplayName.optional(), avatar: Avatar.optional(), game: z.enum(GAME_IDS).optional(), character: Character.optional(), pv: Pv, idToken: IdToken, platform: Platform, appVersion: AppVersion }),
64
65
  // Host sets/changes their display name AFTER createRoom (for anonymous one-tap
65
66
  // hosts who started nameless). Host-only; the relay re-broadcasts the lobby.
66
67
  // SUPERSEDED by setProfile (kept working for shipped builds).
@@ -74,8 +75,8 @@ var ClientMsg = z.discriminatedUnion("t", [
74
75
  // view carries names+avatars so it updates live; dama/ersimha views are id-keyed (clients
75
76
  // map ids→names from the lobby roster), so a change there lands on the next lobby.
76
77
  z.object({ t: z.literal("setProfile"), name: DisplayName.optional(), avatar: Avatar.optional(), character: Character.optional() }),
77
- z.object({ t: z.literal("joinRoom"), code: RoomCode, name: DisplayName, avatar: Avatar.optional(), character: Character.optional(), pv: Pv, idToken: IdToken, platform: Platform }),
78
- z.object({ t: z.literal("resume"), code: RoomCode, token: z.string().max(120), avatar: Avatar.optional(), character: Character.optional(), pv: Pv, idToken: IdToken, platform: Platform }),
78
+ z.object({ t: z.literal("joinRoom"), code: RoomCode, name: DisplayName, avatar: Avatar.optional(), character: Character.optional(), pv: Pv, idToken: IdToken, platform: Platform, appVersion: AppVersion }),
79
+ z.object({ t: z.literal("resume"), code: RoomCode, token: z.string().max(120), avatar: Avatar.optional(), character: Character.optional(), pv: Pv, idToken: IdToken, platform: Platform, appVersion: AppVersion }),
79
80
  // `tally` (gs#46) = wins per PLAYER across every game this room has played tonight — «نتيجة الليلة».
80
81
  // Keyed by playerId, NOT by team: team names are recycled each game, so a per-team count means nothing
81
82
  // across a night. Survives playAgain. A One Device game credits nobody (its team slots hold no players).
@@ -139,6 +140,13 @@ var ClientMsg = z.discriminatedUnion("t", [
139
140
  // an explicit seating beats an implicit one.
140
141
  // Violations are rejected with `invalid_seat`. Consumed by دامة (the only fixed-seat game today).
141
142
  players: z.array(PlayerId).min(1).max(LIMITS.MAX_PLAYERS).optional(),
143
+ // SOLO vs the machine (gs#68). Fills the seats a game needs that no human took, so one person can
144
+ // play with nobody else around — دامة's «تمرين». Additive, no pv bump; omit it and nothing changes.
145
+ // The bot is a SEAT the relay drives, never something a client runs: Shape B means the server is
146
+ // still the referee, and a client-side opponent could not be trusted with the board anyway.
147
+ // `difficulty` is one search with different depth+noise, not three implementations.
148
+ // Solo games are deliberately NOT RATED and never touch the دامة ELO ladder — see the driver.
149
+ bot: z.object({ difficulty: z.enum(["easy", "medium", "hard"]).optional() }).optional(),
142
150
  // PREFERRED: pick a mode from the registry (see MODES). The server maps it to the engine
143
151
  // rules. Send this and omit buzzerMode/noHost. Falls back to the legacy flags below if omitted.
144
152
  modeId: z.enum(MODE_IDS).optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thegeem/protocol",
3
- "version": "0.1.32",
3
+ "version": "0.1.34",
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",