@orakl/shared 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/LICENSE +662 -0
  2. package/dist/analytics.d.ts +21 -0
  3. package/dist/analytics.js +21 -0
  4. package/dist/avatar-helpers.d.ts +46 -0
  5. package/dist/avatar-helpers.js +69 -0
  6. package/dist/avatars.d.ts +6 -0
  7. package/dist/avatars.js +138 -0
  8. package/dist/badges.d.ts +126 -0
  9. package/dist/badges.js +667 -0
  10. package/dist/constants/auth.constants.d.ts +26 -0
  11. package/dist/constants/auth.constants.js +94 -0
  12. package/dist/constants/feature-flags.constants.d.ts +138 -0
  13. package/dist/constants/feature-flags.constants.js +119 -0
  14. package/dist/constants/font.constants.d.ts +9 -0
  15. package/dist/constants/font.constants.js +14 -0
  16. package/dist/constants/lobby.constants.d.ts +2 -0
  17. package/dist/constants/lobby.constants.js +438 -0
  18. package/dist/constants/patterns.constants.d.ts +4 -0
  19. package/dist/constants/patterns.constants.js +4 -0
  20. package/dist/constants/theme.constants.d.ts +24 -0
  21. package/dist/constants/theme.constants.js +69 -0
  22. package/dist/env.d.ts +3 -0
  23. package/dist/env.js +5 -0
  24. package/dist/font.d.ts +4 -0
  25. package/dist/font.js +8 -0
  26. package/dist/history-range.d.ts +13 -0
  27. package/dist/history-range.js +29 -0
  28. package/dist/index.d.ts +23 -0
  29. package/dist/index.js +26 -0
  30. package/dist/lobby.d.ts +16 -0
  31. package/dist/lobby.js +50 -0
  32. package/dist/manage-questions.d.ts +52 -0
  33. package/dist/manage-questions.js +26 -0
  34. package/dist/math.d.ts +27 -0
  35. package/dist/math.js +30 -0
  36. package/dist/murmurhash.d.ts +9 -0
  37. package/dist/murmurhash.js +52 -0
  38. package/dist/pricing.d.ts +32 -0
  39. package/dist/pricing.js +32 -0
  40. package/dist/profile-tabs.d.ts +8 -0
  41. package/dist/profile-tabs.js +18 -0
  42. package/dist/quiz-routes.d.ts +28 -0
  43. package/dist/quiz-routes.js +65 -0
  44. package/dist/sanitize.d.ts +38 -0
  45. package/dist/sanitize.js +109 -0
  46. package/dist/schemas/question.schema.d.ts +1 -0
  47. package/dist/schemas/question.schema.js +1 -0
  48. package/dist/solo-entitlements.d.ts +28 -0
  49. package/dist/solo-entitlements.js +56 -0
  50. package/dist/theme.d.ts +39 -0
  51. package/dist/theme.js +139 -0
  52. package/dist/types/auth.d.ts +143 -0
  53. package/dist/types/auth.js +28 -0
  54. package/dist/utils.d.ts +50 -0
  55. package/dist/utils.js +133 -0
  56. package/package.json +45 -0
@@ -0,0 +1,438 @@
1
+ export const ADJECTIVES = [
2
+ // battle / strength
3
+ "iron",
4
+ "bold",
5
+ "grim",
6
+ "dire",
7
+ "fell",
8
+ "gale",
9
+ "war",
10
+ "wild",
11
+ "swift",
12
+ "keen",
13
+ "raw",
14
+ "dread",
15
+ "true",
16
+ "lone",
17
+ "blind",
18
+ "bright",
19
+ "cold",
20
+ "deep",
21
+ "far",
22
+ "last",
23
+ "old",
24
+ "pale",
25
+ "red",
26
+ "salt",
27
+ "dry",
28
+ "dark",
29
+ "dead",
30
+ // nature / elements
31
+ "ash",
32
+ "frost",
33
+ "gold",
34
+ "jade",
35
+ "oak",
36
+ "stone",
37
+ "wolf",
38
+ "crow",
39
+ "hawk",
40
+ "fog",
41
+ "ice",
42
+ "ember",
43
+ "dusk",
44
+ "dawn",
45
+ "moon",
46
+ "sun",
47
+ "storm",
48
+ "blood",
49
+ "bone",
50
+ "thorn",
51
+ "mud",
52
+ "dust",
53
+ "sand",
54
+ "clay",
55
+ "steel",
56
+ "smoke",
57
+ "snow",
58
+ "rain",
59
+ "wind",
60
+ "fire",
61
+ "earth",
62
+ "sea",
63
+ "sky",
64
+ "star",
65
+ "haze",
66
+ "mist",
67
+ // arcane / mythic
68
+ "sage",
69
+ "myth",
70
+ "rune",
71
+ "lost",
72
+ "cursed",
73
+ "fated",
74
+ "divine",
75
+ "hollow",
76
+ "elder",
77
+ "ever",
78
+ "vale",
79
+ "silver",
80
+ "ever",
81
+ "bright",
82
+ "dusk",
83
+ "night",
84
+ "veiled",
85
+ "cursed",
86
+ "sunken",
87
+ "ruined",
88
+ "broken",
89
+ "silent",
90
+ "risen",
91
+ "fallen",
92
+ "sealed",
93
+ "bound",
94
+ "unbound",
95
+ "woven",
96
+ "blessed",
97
+ "damned",
98
+ "marked",
99
+ "scorned",
100
+ "chosen",
101
+ "exiled",
102
+ "hidden",
103
+ "ancient",
104
+ "eternal",
105
+ "mortal",
106
+ "sacred",
107
+ "hollow",
108
+ "ashen",
109
+ "gilded",
110
+ "sundered",
111
+ "twisted",
112
+ "spectral",
113
+ "forsaken",
114
+ "hallowed",
115
+ "forlorn",
116
+ "withered",
117
+ "undying",
118
+ "blazing",
119
+ "frozen",
120
+ "thirsting",
121
+ "wandering",
122
+ "burning",
123
+ "howling",
124
+ "gleaming",
125
+ "shattered",
126
+ "crumbling",
127
+ "haunted",
128
+ "dreaded",
129
+ "crimson",
130
+ "verdant",
131
+ "obsidian",
132
+ "ivory",
133
+ "scarlet",
134
+ "amber",
135
+ "violet",
136
+ "golden",
137
+ "silver",
138
+ "cobalt",
139
+ "onyx",
140
+ "sapphire",
141
+ "jade",
142
+ "pearl",
143
+ "copper",
144
+ // oracle / fate
145
+ "veiled",
146
+ "fated",
147
+ "omen",
148
+ "unseen",
149
+ "dreaming",
150
+ "waking",
151
+ "knowing",
152
+ "seeking",
153
+ "watching",
154
+ "wandering",
155
+ "waiting",
156
+ "silent",
157
+ "echoing",
158
+ ];
159
+ export const NOUNS = [
160
+ // places
161
+ "den",
162
+ "gate",
163
+ "ridge",
164
+ "peak",
165
+ "vale",
166
+ "isle",
167
+ "keep",
168
+ "bridge",
169
+ "cliff",
170
+ "grove",
171
+ "cairn",
172
+ "citadel",
173
+ "crypt",
174
+ "spire",
175
+ "tower",
176
+ "lair",
177
+ "hollow",
178
+ "nexus",
179
+ "path",
180
+ "rift",
181
+ "root",
182
+ "way",
183
+ "edge",
184
+ "fall",
185
+ "rise",
186
+ "mound",
187
+ "barrow",
188
+ "ford",
189
+ "pass",
190
+ "shore",
191
+ "strand",
192
+ "heath",
193
+ "moor",
194
+ "marsh",
195
+ "delta",
196
+ "crater",
197
+ "basin",
198
+ "canyon",
199
+ "ravine",
200
+ "gorge",
201
+ "chasm",
202
+ "inlet",
203
+ "haven",
204
+ "harbor",
205
+ "port",
206
+ "reef",
207
+ "shoal",
208
+ "bluff",
209
+ "mesa",
210
+ // objects / relics
211
+ "forge",
212
+ "crown",
213
+ "vault",
214
+ "rune",
215
+ "mark",
216
+ "seal",
217
+ "crest",
218
+ "ward",
219
+ "flame",
220
+ "glyph",
221
+ "lore",
222
+ "oath",
223
+ "relic",
224
+ "shard",
225
+ "altar",
226
+ "anvil",
227
+ "ark",
228
+ "axe",
229
+ "bell",
230
+ "blade",
231
+ "chain",
232
+ "cipher",
233
+ "coil",
234
+ "dirge",
235
+ "echo",
236
+ "effigy",
237
+ "exile",
238
+ "eye",
239
+ "fang",
240
+ "fate",
241
+ "foe",
242
+ "gaze",
243
+ "grave",
244
+ "grief",
245
+ "helm",
246
+ "herald",
247
+ "horn",
248
+ "hymn",
249
+ "idol",
250
+ "key",
251
+ "lantern",
252
+ "law",
253
+ "omen",
254
+ "oracle",
255
+ "pyre",
256
+ "quest",
257
+ "ruin",
258
+ "saga",
259
+ "scar",
260
+ "scribe",
261
+ "sigil",
262
+ "skull",
263
+ "soul",
264
+ "star",
265
+ "stone",
266
+ "storm",
267
+ "throne",
268
+ "tomb",
269
+ "torch",
270
+ "veil",
271
+ "vigil",
272
+ "vow",
273
+ "wrath",
274
+ "wisp",
275
+ "warden",
276
+ "wolf",
277
+ "iron",
278
+ "urn",
279
+ "mist",
280
+ "tide",
281
+ "nexus",
282
+ "shard",
283
+ "arrow",
284
+ "bow",
285
+ "coin",
286
+ "compass",
287
+ "crown",
288
+ "cup",
289
+ "dagger",
290
+ "drum",
291
+ "dust",
292
+ "feather",
293
+ "gem",
294
+ "hook",
295
+ "ink",
296
+ "lens",
297
+ "map",
298
+ "mask",
299
+ "mirror",
300
+ "needle",
301
+ "net",
302
+ "pillar",
303
+ "plume",
304
+ "ring",
305
+ "rod",
306
+ "rope",
307
+ "scroll",
308
+ "shield",
309
+ "spark",
310
+ "spear",
311
+ "staff",
312
+ "standard",
313
+ "stone",
314
+ "sword",
315
+ "talisman",
316
+ "thread",
317
+ "tooth",
318
+ "vial",
319
+ "wand",
320
+ "wheel",
321
+ "wing",
322
+ // mythic / abstract
323
+ "age",
324
+ "abyss",
325
+ "arc",
326
+ "ash",
327
+ "augur",
328
+ "bane",
329
+ "beacon",
330
+ "blood",
331
+ "call",
332
+ "chronicle",
333
+ "covenant",
334
+ "curse",
335
+ "dawn",
336
+ "decree",
337
+ "dominion",
338
+ "doom",
339
+ "dusk",
340
+ "dynasty",
341
+ "eclipse",
342
+ "epoch",
343
+ "edict",
344
+ "ember",
345
+ "end",
346
+ "fall",
347
+ "fire",
348
+ "fracture",
349
+ "fury",
350
+ "gale",
351
+ "glory",
352
+ "grace",
353
+ "herald",
354
+ "horizon",
355
+ "hunger",
356
+ "hymn",
357
+ "legacy",
358
+ "legend",
359
+ "light",
360
+ "lore",
361
+ "mantle",
362
+ "memory",
363
+ "mercy",
364
+ "moon",
365
+ "myth",
366
+ "night",
367
+ "oath",
368
+ "order",
369
+ "origin",
370
+ "pact",
371
+ "passage",
372
+ "peace",
373
+ "plague",
374
+ "pride",
375
+ "prophecy",
376
+ "realm",
377
+ "rebirth",
378
+ "requiem",
379
+ "rise",
380
+ "rite",
381
+ "sanctum",
382
+ "shadow",
383
+ "silence",
384
+ "sin",
385
+ "sky",
386
+ "song",
387
+ "sorrow",
388
+ "soul",
389
+ "sovereignty",
390
+ "sun",
391
+ "tempest",
392
+ "tide",
393
+ "truth",
394
+ "twilight",
395
+ "undoing",
396
+ "union",
397
+ "void",
398
+ "war",
399
+ "watch",
400
+ "wave",
401
+ "wisdom",
402
+ "world",
403
+ "wound",
404
+ "zenith",
405
+ "zeal",
406
+ // creatures
407
+ "asp",
408
+ "basilisk",
409
+ "bear",
410
+ "boar",
411
+ "bull",
412
+ "cobra",
413
+ "crane",
414
+ "crow",
415
+ "dragon",
416
+ "eagle",
417
+ "falcon",
418
+ "fox",
419
+ "hound",
420
+ "hydra",
421
+ "kraken",
422
+ "lion",
423
+ "lynx",
424
+ "manticore",
425
+ "moth",
426
+ "owl",
427
+ "phoenix",
428
+ "raven",
429
+ "serpent",
430
+ "sphinx",
431
+ "stag",
432
+ "swan",
433
+ "tiger",
434
+ "viper",
435
+ "vulture",
436
+ "whale",
437
+ "wyvern",
438
+ ];
@@ -0,0 +1,4 @@
1
+ /** Hex color: #RGB, #RGBA, #RRGGBB, #RRGGBBAA */
2
+ export declare const HEX_COLOR_RE: RegExp;
3
+ /** Matches all HTML tags, including unclosed ones */
4
+ export declare const HTML_TAGS_RE: RegExp;
@@ -0,0 +1,4 @@
1
+ /** Hex color: #RGB, #RGBA, #RRGGBB, #RRGGBBAA */
2
+ export const HEX_COLOR_RE = /^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
3
+ /** Matches all HTML tags, including unclosed ones */
4
+ export const HTML_TAGS_RE = /<[^>]*>|<[^\s>]*/g;
@@ -0,0 +1,24 @@
1
+ import type { SkyPhase, ThemeMode } from "../theme.ts";
2
+ export declare const THEME_COOKIE = "orakl-theme";
3
+ export declare const SYSTEM_PREF_COOKIE = "orakl-system-pref";
4
+ export declare const DEFAULT_THEME: ThemeMode;
5
+ export declare const SKY_SCHEDULE: Record<SkyPhase, [number, number]>;
6
+ export declare const LOGO_SCHEDULE: Record<SkyPhase, "dark" | "light">;
7
+ /** Per-phase background element configuration — single source of truth. */
8
+ export declare const PHASE_CONFIG: Record<SkyPhase, {
9
+ /** Canvas opacity for the stars layer (0 = hidden). */
10
+ starOpacity: number;
11
+ /** Number of fireflies (0 = none). Component halves this on mobile. */
12
+ fireflyCount: number;
13
+ /** Canvas opacity for the birds layer (0 = hidden). */
14
+ birdOpacity: number;
15
+ /** Whether to render the sky gradient (false = solid night). */
16
+ showSky: boolean;
17
+ }>;
18
+ export declare const SKY_PHASES: SkyPhase[];
19
+ /** Human-readable labels. */
20
+ export declare const THEME_LABELS: Record<ThemeMode, string>;
21
+ /** Time ranges for the UI. */
22
+ export declare const PHASE_TIMES: Record<SkyPhase, string>;
23
+ /** Representative gradient colours [top, bottom] for phase swatches. */
24
+ export declare const PHASE_COLORS: Record<SkyPhase, [string, string]>;
@@ -0,0 +1,69 @@
1
+ export const THEME_COOKIE = "orakl-theme";
2
+ export const SYSTEM_PREF_COOKIE = "orakl-system-pref";
3
+ export const DEFAULT_THEME = "dark";
4
+ // Configurable schedule: [startHour, endHour) in 24h local time.
5
+ // Night wraps around midnight: start > end means [start, 24) ∪ [0, end).
6
+ export const SKY_SCHEDULE = {
7
+ dawn: [5, 7],
8
+ morning: [7, 11],
9
+ noon: [11, 14],
10
+ evening: [14, 17],
11
+ sunset: [17, 19],
12
+ dusk: [19, 22],
13
+ night: [22, 5],
14
+ };
15
+ // Show dark or light logo variant depending on the phase, for better contrast.
16
+ export const LOGO_SCHEDULE = {
17
+ night: "light",
18
+ dawn: "light",
19
+ dusk: "light",
20
+ sunset: "dark",
21
+ morning: "dark",
22
+ noon: "dark",
23
+ evening: "dark",
24
+ };
25
+ /** Per-phase background element configuration — single source of truth. */
26
+ export const PHASE_CONFIG = {
27
+ night: { starOpacity: 1.0, fireflyCount: 0, birdOpacity: 0, showSky: false },
28
+ dawn: { starOpacity: 0.85, fireflyCount: 0, birdOpacity: 0, showSky: true },
29
+ morning: { starOpacity: 0, fireflyCount: 0, birdOpacity: 1, showSky: true },
30
+ noon: { starOpacity: 0, fireflyCount: 0, birdOpacity: 1, showSky: true },
31
+ evening: { starOpacity: 0, fireflyCount: 0, birdOpacity: 1, showSky: true },
32
+ sunset: { starOpacity: 0, fireflyCount: 0, birdOpacity: 0, showSky: true },
33
+ dusk: { starOpacity: 0.6, fireflyCount: 20, birdOpacity: 0, showSky: true },
34
+ };
35
+ export const SKY_PHASES = Object.keys(SKY_SCHEDULE);
36
+ /** Human-readable labels. */
37
+ export const THEME_LABELS = {
38
+ dark: "Dark",
39
+ light: "Light",
40
+ system: "System",
41
+ dynamic: "Dynamic",
42
+ night: "Night",
43
+ dawn: "Dawn",
44
+ morning: "Morning",
45
+ noon: "Noon",
46
+ evening: "Evening",
47
+ sunset: "Sunset",
48
+ dusk: "Dusk",
49
+ };
50
+ /** Time ranges for the UI. */
51
+ export const PHASE_TIMES = {
52
+ night: "10pm–5am",
53
+ dawn: "5am–7am",
54
+ morning: "7am–11am",
55
+ noon: "11am–2pm",
56
+ evening: "2pm–5pm",
57
+ sunset: "5pm–7pm",
58
+ dusk: "7pm–10pm",
59
+ };
60
+ /** Representative gradient colours [top, bottom] for phase swatches. */
61
+ export const PHASE_COLORS = {
62
+ night: ["#07080f", "#0E0D18"],
63
+ dawn: ["#1e2d4e", "#f4b393"],
64
+ morning: ["#c9d6e3", "#dde8f0"],
65
+ noon: ["#1a80c4", "#87ceeb"],
66
+ evening: ["#4a7fa5", "#f9c06a"],
67
+ sunset: ["#6b2d2d", "#f8dbd8"],
68
+ dusk: ["#1a2240", "#c9a0a0"],
69
+ };
package/dist/env.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ /** True when NODE_ENV is "production", read at call time (not memoised: some
2
+ * callers set the env var before this is first called). */
3
+ export declare function isProduction(): boolean;
package/dist/env.js ADDED
@@ -0,0 +1,5 @@
1
+ /** True when NODE_ENV is "production", read at call time (not memoised: some
2
+ * callers set the env var before this is first called). */
3
+ export function isProduction() {
4
+ return process.env.NODE_ENV === "production";
5
+ }
package/dist/font.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export { DEFAULT_FONT, FONT_COOKIE, FONT_DESCRIPTIONS, FONT_LABELS, FONT_PREFERENCES, } from "./constants/font.constants.ts";
2
+ /** Reader typeface preference. `dyslexic` swaps every family for OpenDyslexic. */
3
+ export type FontPreference = "default" | "dyslexic";
4
+ export declare function parseFont(value: string | undefined): FontPreference;
package/dist/font.js ADDED
@@ -0,0 +1,8 @@
1
+ import { DEFAULT_FONT, FONT_PREFERENCES } from "./constants/font.constants.js";
2
+ export { DEFAULT_FONT, FONT_COOKIE, FONT_DESCRIPTIONS, FONT_LABELS, FONT_PREFERENCES, } from "./constants/font.constants.js";
3
+ const VALID_FONTS = new Set(FONT_PREFERENCES);
4
+ export function parseFont(value) {
5
+ if (value && VALID_FONTS.has(value))
6
+ return value;
7
+ return DEFAULT_FONT;
8
+ }
@@ -0,0 +1,13 @@
1
+ export declare const HISTORY_RANGES: readonly ["all", "30d", "7d"];
2
+ export type HistoryRange = (typeof HISTORY_RANGES)[number];
3
+ /** `rangeParam` if it names a known range, else "all" (the default). */
4
+ export declare function parseHistoryRange(rangeParam: string | null): HistoryRange;
5
+ /**
6
+ * Date floor for `range`, in the shape each port's date column needs:
7
+ * `gamesSince` for game_sessions.started_at, `soloSince` for
8
+ * solo_sessions.completed_at. Both absent for "all" (no floor).
9
+ */
10
+ export declare function rangeFloor(range: HistoryRange, now: number): {
11
+ gamesSince?: string;
12
+ soloSince?: number;
13
+ };
@@ -0,0 +1,29 @@
1
+ export const HISTORY_RANGES = ["all", "30d", "7d"];
2
+ /** `rangeParam` if it names a known range, else "all" (the default). */
3
+ export function parseHistoryRange(rangeParam) {
4
+ return HISTORY_RANGES.includes(rangeParam ?? "")
5
+ ? rangeParam
6
+ : "all";
7
+ }
8
+ const DAY_MS = 24 * 60 * 60 * 1000;
9
+ /** Days back from `now` for each non-"all" range. */
10
+ const RANGE_DAYS = {
11
+ "30d": 30,
12
+ "7d": 7,
13
+ };
14
+ /** `now` (epoch ms) as a SQLite `datetime('now')`-shaped UTC string, matching
15
+ * game_sessions.started_at so the two can compare with `>=`. */
16
+ function toGamesSince(now) {
17
+ return new Date(now).toISOString().slice(0, 19).replace("T", " ");
18
+ }
19
+ /**
20
+ * Date floor for `range`, in the shape each port's date column needs:
21
+ * `gamesSince` for game_sessions.started_at, `soloSince` for
22
+ * solo_sessions.completed_at. Both absent for "all" (no floor).
23
+ */
24
+ export function rangeFloor(range, now) {
25
+ if (range === "all")
26
+ return {};
27
+ const floor = now - RANGE_DAYS[range] * DAY_MS;
28
+ return { gamesSince: toGamesSince(floor), soloSince: floor };
29
+ }
@@ -0,0 +1,23 @@
1
+ export * from "./analytics.ts";
2
+ export * from "./avatar-helpers.ts";
3
+ export * from "./avatars.ts";
4
+ export * from "./badges.ts";
5
+ export * from "./constants/feature-flags.constants.ts";
6
+ export * from "./constants/lobby.constants.ts";
7
+ export * from "./constants/patterns.constants.ts";
8
+ export * from "./env.ts";
9
+ export * from "./font.ts";
10
+ export * from "./history-range.ts";
11
+ export * from "./lobby.ts";
12
+ export * from "./manage-questions.ts";
13
+ export * from "./math.ts";
14
+ export { murmurhash } from "./murmurhash.ts";
15
+ export * from "./pricing.ts";
16
+ export * from "./profile-tabs.ts";
17
+ export * from "./quiz-routes.ts";
18
+ export * from "./sanitize.ts";
19
+ export * from "./schemas/question.schema.ts";
20
+ export * from "./solo-entitlements.ts";
21
+ export * from "./theme.ts";
22
+ export * from "./types/auth.ts";
23
+ export * from "./utils.ts";
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ export * from "./analytics.js";
2
+ export * from "./avatar-helpers.js";
3
+ export * from "./avatars.js";
4
+ export * from "./badges.js";
5
+ export * from "./constants/feature-flags.constants.js";
6
+ export * from "./constants/lobby.constants.js";
7
+ export * from "./constants/patterns.constants.js";
8
+ export * from "./env.js";
9
+ // font.ts re-exports every constants/font.constants.ts symbol.
10
+ export * from "./font.js";
11
+ export * from "./history-range.js";
12
+ export * from "./lobby.js";
13
+ export * from "./manage-questions.js";
14
+ export * from "./math.js";
15
+ export { murmurhash } from "./murmurhash.js";
16
+ export * from "./pricing.js";
17
+ export * from "./profile-tabs.js";
18
+ export * from "./quiz-routes.js";
19
+ export * from "./sanitize.js";
20
+ export * from "./schemas/question.schema.js";
21
+ export * from "./solo-entitlements.js";
22
+ // theme.ts re-exports every constants/theme.constants.ts symbol.
23
+ export * from "./theme.js";
24
+ // types/auth.ts re-exports every constants/auth.constants.ts symbol.
25
+ export * from "./types/auth.js";
26
+ export * from "./utils.js";
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Deterministic lobby code from quiz name + category IDs.
3
+ * Same name + same categories always produces the same adj-noun code.
4
+ */
5
+ export declare function generateLobbyCode(name: string, categoryIds: readonly string[]): string;
6
+ /**
7
+ * Finds the player with the given id in a player list.
8
+ * Returns the first match, or undefined when no player has that id.
9
+ */
10
+ export declare function findPlayer<T extends {
11
+ id: string;
12
+ }>(players: readonly T[], id: string | null): T | undefined;
13
+ /**
14
+ * Random lobby code for tests / fallback when no quiz meta is available.
15
+ */
16
+ export declare function generateRandomLobbyCode(existingCodes?: Set<string>): string;