@thegeem/protocol 0.1.2 → 0.1.4
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 +16 -6
- package/dist/index.d.cts +83 -3
- package/dist/index.d.ts +83 -3
- package/dist/index.js +16 -6
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -52,18 +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 }),
|
|
61
|
+
import_zod.z.object({ t: import_zod.z.literal("createRoom"), name: DisplayName.optional(), avatar: Avatar.optional(), pv: Pv, idToken: IdToken }),
|
|
58
62
|
// Host sets/changes their display name AFTER createRoom (for anonymous one-tap
|
|
59
63
|
// hosts who started nameless). Host-only; the relay re-broadcasts the lobby.
|
|
60
64
|
import_zod.z.object({ t: import_zod.z.literal("renameHost"), name: DisplayName }),
|
|
61
|
-
import_zod.z.object({ t: import_zod.z.literal("joinRoom"), code: RoomCode, name: DisplayName, pv: Pv, idToken: IdToken }),
|
|
62
|
-
import_zod.z.object({ t: import_zod.z.literal("resume"), code: RoomCode, token: import_zod.z.string().max(120), pv: Pv, idToken: IdToken }),
|
|
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 }),
|
|
63
67
|
import_zod.z.object({ t: import_zod.z.literal("leaveRoom") }),
|
|
64
68
|
import_zod.z.object({ t: import_zod.z.literal("approve"), playerId: PlayerId }),
|
|
65
69
|
import_zod.z.object({ t: import_zod.z.literal("reject"), playerId: PlayerId }),
|
|
66
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) }),
|
|
67
74
|
// host game actions
|
|
68
75
|
import_zod.z.object({
|
|
69
76
|
t: import_zod.z.literal("startGame"),
|
|
@@ -78,14 +85,17 @@ var ClientMsg = import_zod.z.discriminatedUnion("t", [
|
|
|
78
85
|
// host: after a game ends, return the SAME players to the lobby
|
|
79
86
|
import_zod.z.object({ t: import_zod.z.literal("markOpen"), correct: import_zod.z.boolean() }),
|
|
80
87
|
import_zod.z.object({ t: import_zod.z.literal("revealNoHost") }),
|
|
81
|
-
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
|
|
82
90
|
import_zod.z.object({ t: import_zod.z.literal("noHostNobody") }),
|
|
83
91
|
// player actions
|
|
84
92
|
import_zod.z.object({ t: import_zod.z.literal("buzz") }),
|
|
85
|
-
import_zod.z.object({ t: import_zod.z.literal("answer"), index: import_zod.z.number().int().min(0).max(
|
|
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)
|
|
86
95
|
import_zod.z.object({ t: import_zod.z.literal("useHelp"), helpType: HelpType }),
|
|
87
96
|
// sabotage a rival (active team only): spend a sabotage help to debuff targetTeam's next question
|
|
88
|
-
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
|
|
89
99
|
]);
|
|
90
100
|
// Annotate the CommonJS export names for ESM import in node:
|
|
91
101
|
0 && (module.exports = {
|
package/dist/index.d.cts
CHANGED
|
@@ -43,16 +43,34 @@ 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;
|
|
58
76
|
}>, z.ZodObject<{
|
|
@@ -68,36 +86,72 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
68
86
|
t: z.ZodLiteral<"joinRoom">;
|
|
69
87
|
code: z.ZodString;
|
|
70
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
|
+
}>>;
|
|
71
99
|
pv: z.ZodOptional<z.ZodNumber>;
|
|
72
100
|
idToken: z.ZodOptional<z.ZodString>;
|
|
73
101
|
}, "strip", z.ZodTypeAny, {
|
|
74
102
|
code: string;
|
|
75
103
|
t: "joinRoom";
|
|
76
104
|
name: string;
|
|
105
|
+
avatar?: {
|
|
106
|
+
emoji: string;
|
|
107
|
+
color: string;
|
|
108
|
+
} | undefined;
|
|
77
109
|
pv?: number | undefined;
|
|
78
110
|
idToken?: string | undefined;
|
|
79
111
|
}, {
|
|
80
112
|
code: string;
|
|
81
113
|
t: "joinRoom";
|
|
82
114
|
name: string;
|
|
115
|
+
avatar?: {
|
|
116
|
+
emoji: string;
|
|
117
|
+
color: string;
|
|
118
|
+
} | undefined;
|
|
83
119
|
pv?: number | undefined;
|
|
84
120
|
idToken?: string | undefined;
|
|
85
121
|
}>, z.ZodObject<{
|
|
86
122
|
t: z.ZodLiteral<"resume">;
|
|
87
123
|
code: z.ZodString;
|
|
88
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
|
+
}>>;
|
|
89
135
|
pv: z.ZodOptional<z.ZodNumber>;
|
|
90
136
|
idToken: z.ZodOptional<z.ZodString>;
|
|
91
137
|
}, "strip", z.ZodTypeAny, {
|
|
92
138
|
code: string;
|
|
93
139
|
t: "resume";
|
|
94
140
|
token: string;
|
|
141
|
+
avatar?: {
|
|
142
|
+
emoji: string;
|
|
143
|
+
color: string;
|
|
144
|
+
} | undefined;
|
|
95
145
|
pv?: number | undefined;
|
|
96
146
|
idToken?: string | undefined;
|
|
97
147
|
}, {
|
|
98
148
|
code: string;
|
|
99
149
|
t: "resume";
|
|
100
150
|
token: string;
|
|
151
|
+
avatar?: {
|
|
152
|
+
emoji: string;
|
|
153
|
+
color: string;
|
|
154
|
+
} | undefined;
|
|
101
155
|
pv?: number | undefined;
|
|
102
156
|
idToken?: string | undefined;
|
|
103
157
|
}>, z.ZodObject<{
|
|
@@ -133,6 +187,15 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
133
187
|
}, {
|
|
134
188
|
t: "kick";
|
|
135
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[];
|
|
136
199
|
}>, z.ZodObject<{
|
|
137
200
|
t: z.ZodLiteral<"startGame">;
|
|
138
201
|
game: z.ZodOptional<z.ZodEnum<["trivia"]>>;
|
|
@@ -140,13 +203,13 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
140
203
|
categoryIds: z.ZodArray<z.ZodString, "many">;
|
|
141
204
|
}, "strip", z.ZodTypeAny, {
|
|
142
205
|
t: "startGame";
|
|
143
|
-
totalRounds: number;
|
|
144
206
|
categoryIds: string[];
|
|
207
|
+
totalRounds: number;
|
|
145
208
|
game?: "trivia" | undefined;
|
|
146
209
|
}, {
|
|
147
210
|
t: "startGame";
|
|
148
|
-
totalRounds: number;
|
|
149
211
|
categoryIds: string[];
|
|
212
|
+
totalRounds: number;
|
|
150
213
|
game?: "trivia" | undefined;
|
|
151
214
|
}>, z.ZodObject<{
|
|
152
215
|
t: z.ZodLiteral<"pickLevel">;
|
|
@@ -240,11 +303,20 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
240
303
|
targetTeam: number;
|
|
241
304
|
}>]>;
|
|
242
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
|
+
}
|
|
243
311
|
interface LobbyPlayer {
|
|
244
312
|
id: string;
|
|
245
313
|
name: string;
|
|
246
314
|
approved: boolean;
|
|
247
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;
|
|
248
320
|
}
|
|
249
321
|
/** Per-recipient context attached to lobby/state pushes. */
|
|
250
322
|
interface YouContext {
|
|
@@ -280,6 +352,8 @@ interface TeamView {
|
|
|
280
352
|
type: HelpName;
|
|
281
353
|
isUsed: boolean;
|
|
282
354
|
}[];
|
|
355
|
+
/** The seated player's privacy-safe avatar (relay-enriched; engine view omits it). */
|
|
356
|
+
avatar?: AvatarView;
|
|
283
357
|
}
|
|
284
358
|
interface QuestionView {
|
|
285
359
|
text: string;
|
|
@@ -313,6 +387,11 @@ interface GameStateView {
|
|
|
313
387
|
usedLevels: {
|
|
314
388
|
[categoryId: string]: number[];
|
|
315
389
|
};
|
|
390
|
+
/** Live question countdown: ms remaining while the timer is **ticking** (relay-
|
|
391
|
+
* enriched from the server-authoritative timer). Absent between questions, while
|
|
392
|
+
* paused (e.g. steal intro), or after time-up. Present ⇒ animate a countdown from
|
|
393
|
+
* it; the server remains the authority on actual time-up. */
|
|
394
|
+
timerRemainingMs?: number;
|
|
316
395
|
}
|
|
317
396
|
/** Transient presentation effects the relay emits; clients play them once. */
|
|
318
397
|
type Effect = {
|
|
@@ -390,6 +469,7 @@ type ServerMsg = {
|
|
|
390
469
|
hostName: string;
|
|
391
470
|
players: LobbyPlayer[];
|
|
392
471
|
categories: CategoryView[];
|
|
472
|
+
selectedCategoryIds: string[];
|
|
393
473
|
you: YouContext;
|
|
394
474
|
} | {
|
|
395
475
|
t: 'state';
|
|
@@ -406,4 +486,4 @@ type ServerMsg = {
|
|
|
406
486
|
message: string;
|
|
407
487
|
};
|
|
408
488
|
|
|
409
|
-
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 };
|
|
489
|
+
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,16 +43,34 @@ 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;
|
|
58
76
|
}>, z.ZodObject<{
|
|
@@ -68,36 +86,72 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
68
86
|
t: z.ZodLiteral<"joinRoom">;
|
|
69
87
|
code: z.ZodString;
|
|
70
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
|
+
}>>;
|
|
71
99
|
pv: z.ZodOptional<z.ZodNumber>;
|
|
72
100
|
idToken: z.ZodOptional<z.ZodString>;
|
|
73
101
|
}, "strip", z.ZodTypeAny, {
|
|
74
102
|
code: string;
|
|
75
103
|
t: "joinRoom";
|
|
76
104
|
name: string;
|
|
105
|
+
avatar?: {
|
|
106
|
+
emoji: string;
|
|
107
|
+
color: string;
|
|
108
|
+
} | undefined;
|
|
77
109
|
pv?: number | undefined;
|
|
78
110
|
idToken?: string | undefined;
|
|
79
111
|
}, {
|
|
80
112
|
code: string;
|
|
81
113
|
t: "joinRoom";
|
|
82
114
|
name: string;
|
|
115
|
+
avatar?: {
|
|
116
|
+
emoji: string;
|
|
117
|
+
color: string;
|
|
118
|
+
} | undefined;
|
|
83
119
|
pv?: number | undefined;
|
|
84
120
|
idToken?: string | undefined;
|
|
85
121
|
}>, z.ZodObject<{
|
|
86
122
|
t: z.ZodLiteral<"resume">;
|
|
87
123
|
code: z.ZodString;
|
|
88
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
|
+
}>>;
|
|
89
135
|
pv: z.ZodOptional<z.ZodNumber>;
|
|
90
136
|
idToken: z.ZodOptional<z.ZodString>;
|
|
91
137
|
}, "strip", z.ZodTypeAny, {
|
|
92
138
|
code: string;
|
|
93
139
|
t: "resume";
|
|
94
140
|
token: string;
|
|
141
|
+
avatar?: {
|
|
142
|
+
emoji: string;
|
|
143
|
+
color: string;
|
|
144
|
+
} | undefined;
|
|
95
145
|
pv?: number | undefined;
|
|
96
146
|
idToken?: string | undefined;
|
|
97
147
|
}, {
|
|
98
148
|
code: string;
|
|
99
149
|
t: "resume";
|
|
100
150
|
token: string;
|
|
151
|
+
avatar?: {
|
|
152
|
+
emoji: string;
|
|
153
|
+
color: string;
|
|
154
|
+
} | undefined;
|
|
101
155
|
pv?: number | undefined;
|
|
102
156
|
idToken?: string | undefined;
|
|
103
157
|
}>, z.ZodObject<{
|
|
@@ -133,6 +187,15 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
133
187
|
}, {
|
|
134
188
|
t: "kick";
|
|
135
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[];
|
|
136
199
|
}>, z.ZodObject<{
|
|
137
200
|
t: z.ZodLiteral<"startGame">;
|
|
138
201
|
game: z.ZodOptional<z.ZodEnum<["trivia"]>>;
|
|
@@ -140,13 +203,13 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
140
203
|
categoryIds: z.ZodArray<z.ZodString, "many">;
|
|
141
204
|
}, "strip", z.ZodTypeAny, {
|
|
142
205
|
t: "startGame";
|
|
143
|
-
totalRounds: number;
|
|
144
206
|
categoryIds: string[];
|
|
207
|
+
totalRounds: number;
|
|
145
208
|
game?: "trivia" | undefined;
|
|
146
209
|
}, {
|
|
147
210
|
t: "startGame";
|
|
148
|
-
totalRounds: number;
|
|
149
211
|
categoryIds: string[];
|
|
212
|
+
totalRounds: number;
|
|
150
213
|
game?: "trivia" | undefined;
|
|
151
214
|
}>, z.ZodObject<{
|
|
152
215
|
t: z.ZodLiteral<"pickLevel">;
|
|
@@ -240,11 +303,20 @@ declare const ClientMsg: z.ZodDiscriminatedUnion<"t", [z.ZodObject<{
|
|
|
240
303
|
targetTeam: number;
|
|
241
304
|
}>]>;
|
|
242
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
|
+
}
|
|
243
311
|
interface LobbyPlayer {
|
|
244
312
|
id: string;
|
|
245
313
|
name: string;
|
|
246
314
|
approved: boolean;
|
|
247
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;
|
|
248
320
|
}
|
|
249
321
|
/** Per-recipient context attached to lobby/state pushes. */
|
|
250
322
|
interface YouContext {
|
|
@@ -280,6 +352,8 @@ interface TeamView {
|
|
|
280
352
|
type: HelpName;
|
|
281
353
|
isUsed: boolean;
|
|
282
354
|
}[];
|
|
355
|
+
/** The seated player's privacy-safe avatar (relay-enriched; engine view omits it). */
|
|
356
|
+
avatar?: AvatarView;
|
|
283
357
|
}
|
|
284
358
|
interface QuestionView {
|
|
285
359
|
text: string;
|
|
@@ -313,6 +387,11 @@ interface GameStateView {
|
|
|
313
387
|
usedLevels: {
|
|
314
388
|
[categoryId: string]: number[];
|
|
315
389
|
};
|
|
390
|
+
/** Live question countdown: ms remaining while the timer is **ticking** (relay-
|
|
391
|
+
* enriched from the server-authoritative timer). Absent between questions, while
|
|
392
|
+
* paused (e.g. steal intro), or after time-up. Present ⇒ animate a countdown from
|
|
393
|
+
* it; the server remains the authority on actual time-up. */
|
|
394
|
+
timerRemainingMs?: number;
|
|
316
395
|
}
|
|
317
396
|
/** Transient presentation effects the relay emits; clients play them once. */
|
|
318
397
|
type Effect = {
|
|
@@ -390,6 +469,7 @@ type ServerMsg = {
|
|
|
390
469
|
hostName: string;
|
|
391
470
|
players: LobbyPlayer[];
|
|
392
471
|
categories: CategoryView[];
|
|
472
|
+
selectedCategoryIds: string[];
|
|
393
473
|
you: YouContext;
|
|
394
474
|
} | {
|
|
395
475
|
t: 'state';
|
|
@@ -406,4 +486,4 @@ type ServerMsg = {
|
|
|
406
486
|
message: string;
|
|
407
487
|
};
|
|
408
488
|
|
|
409
|
-
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 };
|
|
489
|
+
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,18 +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 }),
|
|
33
|
+
z.object({ t: z.literal("createRoom"), name: DisplayName.optional(), avatar: Avatar.optional(), pv: Pv, idToken: IdToken }),
|
|
30
34
|
// Host sets/changes their display name AFTER createRoom (for anonymous one-tap
|
|
31
35
|
// hosts who started nameless). Host-only; the relay re-broadcasts the lobby.
|
|
32
36
|
z.object({ t: z.literal("renameHost"), name: DisplayName }),
|
|
33
|
-
z.object({ t: z.literal("joinRoom"), code: RoomCode, name: DisplayName, pv: Pv, idToken: IdToken }),
|
|
34
|
-
z.object({ t: z.literal("resume"), code: RoomCode, token: z.string().max(120), pv: Pv, idToken: IdToken }),
|
|
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 }),
|
|
35
39
|
z.object({ t: z.literal("leaveRoom") }),
|
|
36
40
|
z.object({ t: z.literal("approve"), playerId: PlayerId }),
|
|
37
41
|
z.object({ t: z.literal("reject"), playerId: PlayerId }),
|
|
38
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) }),
|
|
39
46
|
// host game actions
|
|
40
47
|
z.object({
|
|
41
48
|
t: z.literal("startGame"),
|
|
@@ -50,14 +57,17 @@ var ClientMsg = z.discriminatedUnion("t", [
|
|
|
50
57
|
// host: after a game ends, return the SAME players to the lobby
|
|
51
58
|
z.object({ t: z.literal("markOpen"), correct: z.boolean() }),
|
|
52
59
|
z.object({ t: z.literal("revealNoHost") }),
|
|
53
|
-
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
|
|
54
62
|
z.object({ t: z.literal("noHostNobody") }),
|
|
55
63
|
// player actions
|
|
56
64
|
z.object({ t: z.literal("buzz") }),
|
|
57
|
-
z.object({ t: z.literal("answer"), index: z.number().int().min(0).max(
|
|
65
|
+
z.object({ t: z.literal("answer"), index: z.number().int().min(0).max(3) }),
|
|
66
|
+
// trivia is 4-option (0–3)
|
|
58
67
|
z.object({ t: z.literal("useHelp"), helpType: HelpType }),
|
|
59
68
|
// sabotage a rival (active team only): spend a sabotage help to debuff targetTeam's next question
|
|
60
|
-
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
|
|
61
71
|
]);
|
|
62
72
|
export {
|
|
63
73
|
ClientMsg,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thegeem/protocol",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
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",
|