@orakl/protocol 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 (50) hide show
  1. package/LICENSE +662 -0
  2. package/dist/badges.d.ts +19 -0
  3. package/dist/badges.js +1 -0
  4. package/dist/emotes.d.ts +5 -0
  5. package/dist/emotes.js +62 -0
  6. package/dist/error-codes.d.ts +1 -0
  7. package/dist/error-codes.js +1 -0
  8. package/dist/game-answer-record.d.ts +31 -0
  9. package/dist/game-answer-record.js +1 -0
  10. package/dist/game.d.ts +83 -0
  11. package/dist/game.js +1 -0
  12. package/dist/game.settings.d.ts +91 -0
  13. package/dist/game.settings.js +61 -0
  14. package/dist/index.d.ts +23 -0
  15. package/dist/index.js +13 -0
  16. package/dist/pages/app.schema.d.ts +544 -0
  17. package/dist/pages/app.schema.js +336 -0
  18. package/dist/pages/auth.schema.d.ts +25 -0
  19. package/dist/pages/auth.schema.js +23 -0
  20. package/dist/pages/common.schema.d.ts +27 -0
  21. package/dist/pages/common.schema.js +28 -0
  22. package/dist/pages/history.schema.d.ts +273 -0
  23. package/dist/pages/history.schema.js +210 -0
  24. package/dist/pages/quiz.schema.d.ts +150 -0
  25. package/dist/pages/quiz.schema.js +132 -0
  26. package/dist/player-safe-question.d.ts +13 -0
  27. package/dist/player-safe-question.js +1 -0
  28. package/dist/question.d.ts +6 -0
  29. package/dist/question.js +12 -0
  30. package/dist/question.schema.d.ts +494 -0
  31. package/dist/question.schema.js +132 -0
  32. package/dist/scoring.schema.d.ts +7 -0
  33. package/dist/scoring.schema.js +8 -0
  34. package/dist/solo-ws.d.ts +202 -0
  35. package/dist/solo-ws.js +4 -0
  36. package/dist/streak-flourish.d.ts +6 -0
  37. package/dist/streak-flourish.js +1 -0
  38. package/dist/wire/leaderboard.d.ts +6 -0
  39. package/dist/wire/leaderboard.js +1 -0
  40. package/dist/wire/question-bank.d.ts +23 -0
  41. package/dist/wire/question-bank.js +1 -0
  42. package/dist/wire/question-flags.d.ts +40 -0
  43. package/dist/wire/question-flags.js +1 -0
  44. package/dist/ws-game.schema.d.ts +75 -0
  45. package/dist/ws-game.schema.js +131 -0
  46. package/dist/ws-solo.schema.d.ts +31 -0
  47. package/dist/ws-solo.schema.js +57 -0
  48. package/dist/ws.d.ts +281 -0
  49. package/dist/ws.js +1 -0
  50. package/package.json +39 -0
@@ -0,0 +1,273 @@
1
+ import { Schema } from "effect";
2
+ /** Page-load response bodies for `src/api/routes/pages-history.ts and admin-feature-flags.ts`. */
3
+ /** Achievement badge id (mirrors `BadgeId` in `src/lib/badges.ts`). */
4
+ export declare const BadgeIdSchema: Schema.Literal<["victor", "flawless", "sharpshooter", "podium", "unstoppable", "on-a-roll", "survivor", "giant-slayer", "pantheon", "specialist", "polymath", "phoenix", "strong-finish", "master-of-none", "faster-than-most", "clutch", "quick-draw", "decisive", "sure-handed", "unbroken-focus", "devotee"]>;
5
+ /** Rarity tier a badge award reached (mirrors `Rarity` in `src/lib/badges.ts`). */
6
+ export declare const RaritySchema: Schema.Literal<["common", "rare", "legendary", "exotic"]>;
7
+ /** Per-badge counts + best rarity across a player's runs (mirrors `BadgeTally`). */
8
+ export declare const BadgeTallySchema: Schema.mutable<Schema.Record$<typeof Schema.String, Schema.Struct<{
9
+ count: typeof Schema.Number;
10
+ bestRarity: Schema.Literal<["common", "rare", "legendary", "exotic"]>;
11
+ }>>>;
12
+ /** Body of `GET /api/pages/admin/settings`. */
13
+ export declare const AdminSettingsPageSchema: Schema.Struct<{
14
+ freeHostGames: typeof Schema.Number;
15
+ }>;
16
+ declare const UserSourceSchema: Schema.Literal<["lifetime", "paid", "comp", "none"]>;
17
+ /** Where an account's curator+ standing comes from. */
18
+ export type UserSource = typeof UserSourceSchema.Type;
19
+ /** Body of `GET /api/pages/admin/users`. */
20
+ export declare const AdminUsersPageSchema: Schema.Struct<{
21
+ initial: Schema.Struct<{
22
+ users: Schema.mutable<Schema.Array$<Schema.Struct<{
23
+ id: typeof Schema.String;
24
+ email: typeof Schema.String;
25
+ role: Schema.Literal<["anonymous", "display", "member", "curator", "admin"]>;
26
+ nickname: Schema.NullOr<typeof Schema.String>;
27
+ avatar: Schema.NullOr<typeof Schema.String>;
28
+ powers: typeof Schema.String;
29
+ created_at: Schema.NullOr<typeof Schema.String>;
30
+ admin_note: Schema.NullOr<typeof Schema.String>;
31
+ leaderboard_excluded: typeof Schema.Number;
32
+ source: Schema.Literal<["lifetime", "paid", "comp", "none"]>;
33
+ }>>>;
34
+ total: typeof Schema.Number;
35
+ page: typeof Schema.Number;
36
+ limit: typeof Schema.Number;
37
+ totalPages: typeof Schema.Number;
38
+ }>;
39
+ roles: Schema.mutable<Schema.Array$<Schema.Literal<["anonymous", "display", "member", "curator", "admin"]>>>;
40
+ currentUserId: typeof Schema.String;
41
+ allPowers: Schema.mutable<Schema.Array$<Schema.Literal<["can-access-mimic", "can-send-feedback", "can-import-quizzes", "can-manage-features", "can-add-questions", "can-manage-categories", "can-moderate-questions", "can-publish-questions", "is-power-user", "can-manage-avatars", "can-apply-for-curation", "can-1v1"]>>>;
42
+ pendingRequests: Schema.mutable<Schema.Array$<Schema.Struct<{
43
+ id: typeof Schema.String;
44
+ user_id: typeof Schema.String;
45
+ status: typeof Schema.String;
46
+ created_at: typeof Schema.String;
47
+ email: typeof Schema.String;
48
+ nickname: Schema.NullOr<typeof Schema.String>;
49
+ }>>>;
50
+ }>;
51
+ /** Body of `GET /api/admin/feature-flags/dashboard`. */
52
+ export declare const FeatureFlagsDashboardSchema: Schema.Struct<{
53
+ flags: Schema.mutable<Schema.Array$<Schema.Struct<{
54
+ name: typeof Schema.String;
55
+ tier: Schema.Literal<["build", "db", "role"]>;
56
+ description: typeof Schema.String;
57
+ state: Schema.Literal<["on", "off", "rules"]>;
58
+ source: Schema.Literal<["env", "database", "code", "build"]>;
59
+ roles: Schema.NullOr<Schema.mutable<Schema.Array$<Schema.Literal<["anonymous", "display", "member", "curator", "admin"]>>>>;
60
+ power: Schema.NullOr<Schema.Literal<["can-access-mimic", "can-send-feedback", "can-import-quizzes", "can-manage-features", "can-add-questions", "can-manage-categories", "can-moderate-questions", "can-publish-questions", "is-power-user", "can-manage-avatars", "can-apply-for-curation", "can-1v1"]>>;
61
+ }>>>;
62
+ }>;
63
+ /** One dashboard row: what the flag is, and what it currently resolves to. */
64
+ export type FlagRow = (typeof FeatureFlagsDashboardSchema.Type)["flags"][number];
65
+ declare const SoloHistoryEntrySchema: Schema.Struct<{
66
+ id: typeof Schema.String;
67
+ total_score: typeof Schema.Number;
68
+ total_answered: typeof Schema.Number;
69
+ correct_count: typeof Schema.Number;
70
+ time_to_answer_avg_ms: typeof Schema.Number;
71
+ max_streak: typeof Schema.Number;
72
+ mode: typeof Schema.String;
73
+ difficulty: typeof Schema.String;
74
+ category_ids: typeof Schema.String;
75
+ completed_at: typeof Schema.Number;
76
+ }>;
77
+ export type SoloHistoryEntry = typeof SoloHistoryEntrySchema.Type;
78
+ declare const PlayerGameStatsSchema: Schema.Struct<{
79
+ games: typeof Schema.Number;
80
+ wins: typeof Schema.Number;
81
+ podiums: typeof Schema.Number;
82
+ best_rank: Schema.NullOr<typeof Schema.Number>;
83
+ }>;
84
+ export type PlayerGameStats = typeof PlayerGameStatsSchema.Type;
85
+ declare const PlayerGamePlacementSchema: Schema.Struct<{
86
+ id: typeof Schema.String;
87
+ quiz_name: typeof Schema.String;
88
+ started_at: typeof Schema.String;
89
+ final_score: typeof Schema.Number;
90
+ rank: typeof Schema.Number;
91
+ player_count: typeof Schema.Number;
92
+ badges: Schema.mutable<Schema.Array$<Schema.Literal<["victor", "flawless", "sharpshooter", "podium", "unstoppable", "on-a-roll", "survivor", "giant-slayer", "pantheon", "specialist", "polymath", "phoenix", "strong-finish", "master-of-none", "faster-than-most", "clutch", "quick-draw", "decisive", "sure-handed", "unbroken-focus", "devotee"]>>>;
93
+ }>;
94
+ export type PlayerGamePlacement = typeof PlayerGamePlacementSchema.Type;
95
+ /** Body of `GET /api/pages/history`. */
96
+ export declare const HistoryPageSchema: Schema.Struct<{
97
+ range: Schema.Literal<["all", "30d", "7d"]>;
98
+ runs: Schema.mutable<Schema.Array$<Schema.Struct<{
99
+ id: typeof Schema.String;
100
+ total_score: typeof Schema.Number;
101
+ total_answered: typeof Schema.Number;
102
+ correct_count: typeof Schema.Number;
103
+ time_to_answer_avg_ms: typeof Schema.Number;
104
+ max_streak: typeof Schema.Number;
105
+ mode: typeof Schema.String;
106
+ difficulty: typeof Schema.String;
107
+ category_ids: typeof Schema.String;
108
+ completed_at: typeof Schema.Number;
109
+ }>>>;
110
+ trendRuns: Schema.mutable<Schema.Array$<Schema.Struct<{
111
+ id: typeof Schema.String;
112
+ total_score: typeof Schema.Number;
113
+ total_answered: typeof Schema.Number;
114
+ correct_count: typeof Schema.Number;
115
+ time_to_answer_avg_ms: typeof Schema.Number;
116
+ max_streak: typeof Schema.Number;
117
+ mode: typeof Schema.String;
118
+ difficulty: typeof Schema.String;
119
+ category_ids: typeof Schema.String;
120
+ completed_at: typeof Schema.Number;
121
+ }>>>;
122
+ latestRunAt: Schema.NullOr<typeof Schema.Number>;
123
+ latestGameAt: Schema.NullOr<typeof Schema.String>;
124
+ stats: Schema.Struct<{
125
+ runs: typeof Schema.Number;
126
+ best_score: typeof Schema.Number;
127
+ best_streak: typeof Schema.Number;
128
+ total_answered: typeof Schema.Number;
129
+ total_correct: typeof Schema.Number;
130
+ }>;
131
+ badgeTally: Schema.mutable<Schema.Record$<typeof Schema.String, Schema.Struct<{
132
+ count: typeof Schema.Number;
133
+ bestRarity: Schema.Literal<["common", "rare", "legendary", "exotic"]>;
134
+ }>>>;
135
+ categoryName: Schema.mutable<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
136
+ attemptStats: Schema.Struct<{
137
+ attempts: typeof Schema.Number;
138
+ focusRate: typeof Schema.Number;
139
+ fastestCorrectMs: Schema.NullOr<typeof Schema.Number>;
140
+ }>;
141
+ dayStreak: typeof Schema.Number;
142
+ mastery: Schema.Struct<{
143
+ strongest: Schema.NullOr<Schema.Struct<{
144
+ categoryId: typeof Schema.String;
145
+ correct: typeof Schema.Number;
146
+ total: typeof Schema.Number;
147
+ }>>;
148
+ weakest: Schema.NullOr<Schema.Struct<{
149
+ categoryId: typeof Schema.String;
150
+ correct: typeof Schema.Number;
151
+ total: typeof Schema.Number;
152
+ }>>;
153
+ }>;
154
+ gameStats: Schema.Struct<{
155
+ games: typeof Schema.Number;
156
+ wins: typeof Schema.Number;
157
+ podiums: typeof Schema.Number;
158
+ best_rank: Schema.NullOr<typeof Schema.Number>;
159
+ }>;
160
+ games: Schema.mutable<Schema.Array$<Schema.Struct<{
161
+ id: typeof Schema.String;
162
+ quiz_name: typeof Schema.String;
163
+ started_at: typeof Schema.String;
164
+ final_score: typeof Schema.Number;
165
+ rank: typeof Schema.Number;
166
+ player_count: typeof Schema.Number;
167
+ badges: Schema.mutable<Schema.Array$<Schema.Literal<["victor", "flawless", "sharpshooter", "podium", "unstoppable", "on-a-roll", "survivor", "giant-slayer", "pantheon", "specialist", "polymath", "phoenix", "strong-finish", "master-of-none", "faster-than-most", "clutch", "quick-draw", "decisive", "sure-handed", "unbroken-focus", "devotee"]>>>;
168
+ }>>>;
169
+ runsNextCursor: Schema.NullOr<typeof Schema.String>;
170
+ gamesNextCursor: Schema.NullOr<typeof Schema.String>;
171
+ }>;
172
+ /** Body of `GET /api/pages/history/game/:id`. */
173
+ export declare const GameReviewPageSchema: Schema.Struct<{
174
+ game: Schema.Struct<{
175
+ id: typeof Schema.String;
176
+ quizName: typeof Schema.String;
177
+ startedAt: typeof Schema.String;
178
+ finalScore: typeof Schema.Number;
179
+ rank: typeof Schema.Number;
180
+ playerCount: typeof Schema.Number;
181
+ }>;
182
+ standings: Schema.mutable<Schema.Array$<Schema.Struct<{
183
+ id: typeof Schema.String;
184
+ nickname: typeof Schema.String;
185
+ score: typeof Schema.Number;
186
+ rank: typeof Schema.Number;
187
+ isViewer: typeof Schema.Boolean;
188
+ avatarId: Schema.NullOr<typeof Schema.String>;
189
+ role: Schema.NullOr<Schema.Literal<["player", "observer"]>>;
190
+ avatarSrc: typeof Schema.String;
191
+ }>>>;
192
+ badges: Schema.mutable<Schema.Array$<Schema.Struct<{
193
+ id: Schema.Literal<["victor", "flawless", "sharpshooter", "podium", "unstoppable", "on-a-roll", "survivor", "giant-slayer", "pantheon", "specialist", "polymath", "phoenix", "strong-finish", "master-of-none", "faster-than-most", "clutch", "quick-draw", "decisive", "sure-handed", "unbroken-focus", "devotee"]>;
194
+ rarity: Schema.Literal<["common", "rare", "legendary", "exotic"]>;
195
+ }>>>;
196
+ breakdown: Schema.NullOr<Schema.mutable<Schema.Array$<Schema.Struct<{
197
+ questionIndex: typeof Schema.Number;
198
+ categoryId: typeof Schema.String;
199
+ difficulty: Schema.optional<Schema.Literal<["easy", "medium", "hard"]>>;
200
+ isCorrect: typeof Schema.Boolean;
201
+ timeToAnswerMs: typeof Schema.Number;
202
+ questionId: Schema.optional<typeof Schema.String>;
203
+ questionText: Schema.optional<typeof Schema.String>;
204
+ selectedAnswerId: Schema.optional<typeof Schema.String>;
205
+ selectedAnswerText: Schema.optional<typeof Schema.String>;
206
+ correctAnswerId: Schema.optional<typeof Schema.String>;
207
+ correctAnswerText: Schema.optional<typeof Schema.String>;
208
+ mediaUrl: Schema.optional<typeof Schema.String>;
209
+ mediaType: Schema.optional<Schema.Literal<["image", "audio", "video"]>>;
210
+ source: Schema.optional<Schema.Struct<{
211
+ url: Schema.filter<Schema.filter<typeof Schema.String>>;
212
+ label: Schema.optional<Schema.filter<typeof Schema.String>>;
213
+ }>>;
214
+ postAnswerNote: Schema.optional<typeof Schema.String>;
215
+ }>>>>;
216
+ categoryName: Schema.mutable<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
217
+ stats: Schema.Struct<{
218
+ answered: typeof Schema.Number;
219
+ correct: typeof Schema.Number;
220
+ accuracy: Schema.NullOr<typeof Schema.Number>;
221
+ avgTimeMs: Schema.NullOr<typeof Schema.Number>;
222
+ }>;
223
+ alreadyFlaggedIds: Schema.mutable<Schema.Array$<typeof Schema.String>>;
224
+ }>;
225
+ /** Body of `GET /api/pages/history/solo/:id`. */
226
+ export declare const SoloReviewPageSchema: Schema.Struct<{
227
+ run: Schema.Struct<{
228
+ id: typeof Schema.String;
229
+ totalScore: typeof Schema.Number;
230
+ totalAnswered: typeof Schema.Number;
231
+ correctCount: typeof Schema.Number;
232
+ timeToAnswerAvgMs: typeof Schema.Number;
233
+ maxStreak: typeof Schema.Number;
234
+ mode: typeof Schema.String;
235
+ difficulty: typeof Schema.String;
236
+ completedAt: typeof Schema.Number;
237
+ categories: Schema.mutable<Schema.Array$<typeof Schema.String>>;
238
+ }>;
239
+ badges: Schema.mutable<Schema.Array$<Schema.Struct<{
240
+ id: Schema.Literal<["victor", "flawless", "sharpshooter", "podium", "unstoppable", "on-a-roll", "survivor", "giant-slayer", "pantheon", "specialist", "polymath", "phoenix", "strong-finish", "master-of-none", "faster-than-most", "clutch", "quick-draw", "decisive", "sure-handed", "unbroken-focus", "devotee"]>;
241
+ rarity: Schema.Literal<["common", "rare", "legendary", "exotic"]>;
242
+ }>>>;
243
+ categoryStats: Schema.mutable<Schema.Array$<Schema.Struct<{
244
+ categoryId: typeof Schema.String;
245
+ name: typeof Schema.String;
246
+ correct: typeof Schema.Number;
247
+ total: typeof Schema.Number;
248
+ }>>>;
249
+ review: Schema.mutable<Schema.Array$<Schema.Struct<{
250
+ questionPosition: typeof Schema.Number;
251
+ isCorrect: typeof Schema.Boolean;
252
+ timeToAnswerMs: typeof Schema.Number;
253
+ categoryId: Schema.NullOr<typeof Schema.String>;
254
+ questionText: Schema.NullOr<typeof Schema.String>;
255
+ difficulty: Schema.NullOr<typeof Schema.String>;
256
+ selectedAnswerText: Schema.NullOr<typeof Schema.String>;
257
+ correctAnswerText: Schema.NullOr<typeof Schema.String>;
258
+ questionId: Schema.NullOr<typeof Schema.String>;
259
+ mediaUrl: Schema.NullOr<typeof Schema.String>;
260
+ mediaType: Schema.NullOr<Schema.Literal<["image", "audio", "video"]>>;
261
+ source: Schema.NullOr<Schema.Struct<{
262
+ url: Schema.filter<Schema.filter<typeof Schema.String>>;
263
+ label: Schema.optional<Schema.filter<typeof Schema.String>>;
264
+ }>>;
265
+ postAnswerNote: Schema.NullOr<typeof Schema.String>;
266
+ }>>>;
267
+ alreadyFlaggedIds: Schema.mutable<Schema.Array$<typeof Schema.String>>;
268
+ }>;
269
+ /** Body of `GET /api/pages/display`. */
270
+ export declare const DisplayPageSchema: Schema.Struct<{
271
+ displayToken: typeof Schema.String;
272
+ }>;
273
+ export {};
@@ -0,0 +1,210 @@
1
+ import { Schema } from "effect";
2
+ import { MediaTypeSchema, QuestionSourceSchema } from "../question.schema.js";
3
+ import { GameAnswerRecordSchema, PlayerRoleSchema, UserPowerSchema, UserRoleSchema, } from "./common.schema.js";
4
+ /** Page-load response bodies for `src/api/routes/pages-history.ts and admin-feature-flags.ts`. */
5
+ /** Achievement badge id (mirrors `BadgeId` in `src/lib/badges.ts`). */
6
+ export const BadgeIdSchema = Schema.Literal("victor", "flawless", "sharpshooter", "podium", "unstoppable", "on-a-roll", "survivor", "giant-slayer", "pantheon", "specialist", "polymath", "phoenix", "strong-finish", "master-of-none", "faster-than-most", "clutch", "quick-draw", "decisive", "sure-handed", "unbroken-focus", "devotee");
7
+ /** Rarity tier a badge award reached (mirrors `Rarity` in `src/lib/badges.ts`). */
8
+ export const RaritySchema = Schema.Literal("common", "rare", "legendary", "exotic");
9
+ /** Per-badge counts + best rarity across a player's runs (mirrors `BadgeTally`). */
10
+ export const BadgeTallySchema = Schema.mutable(Schema.Record({
11
+ key: Schema.String,
12
+ value: Schema.Struct({ count: Schema.Number, bestRarity: RaritySchema }),
13
+ }));
14
+ // ─── Admin ──────────────────────────────────────────────────────────────────
15
+ /** Body of `GET /api/pages/admin/settings`. */
16
+ export const AdminSettingsPageSchema = Schema.Struct({
17
+ freeHostGames: Schema.Number,
18
+ });
19
+ const UserSourceSchema = Schema.Literal("lifetime", "paid", "comp", "none");
20
+ const UserListItemSchema = Schema.Struct({
21
+ id: Schema.String,
22
+ email: Schema.String,
23
+ role: UserRoleSchema,
24
+ nickname: Schema.NullOr(Schema.String),
25
+ avatar: Schema.NullOr(Schema.String),
26
+ powers: Schema.String,
27
+ created_at: Schema.NullOr(Schema.String),
28
+ admin_note: Schema.NullOr(Schema.String),
29
+ leaderboard_excluded: Schema.Number,
30
+ source: UserSourceSchema,
31
+ });
32
+ const CurationRequestWithUserSchema = Schema.Struct({
33
+ id: Schema.String,
34
+ user_id: Schema.String,
35
+ status: Schema.String,
36
+ created_at: Schema.String,
37
+ email: Schema.String,
38
+ nickname: Schema.NullOr(Schema.String),
39
+ });
40
+ /** Body of `GET /api/pages/admin/users`. */
41
+ export const AdminUsersPageSchema = Schema.Struct({
42
+ initial: Schema.Struct({
43
+ users: Schema.mutable(Schema.Array(UserListItemSchema)),
44
+ total: Schema.Number,
45
+ page: Schema.Number,
46
+ limit: Schema.Number,
47
+ totalPages: Schema.Number,
48
+ }),
49
+ roles: Schema.mutable(Schema.Array(UserRoleSchema)),
50
+ currentUserId: Schema.String,
51
+ allPowers: Schema.mutable(Schema.Array(UserPowerSchema)),
52
+ pendingRequests: Schema.mutable(Schema.Array(CurationRequestWithUserSchema)),
53
+ });
54
+ /** Body of `GET /api/admin/feature-flags/dashboard`. */
55
+ export const FeatureFlagsDashboardSchema = Schema.Struct({
56
+ flags: Schema.mutable(Schema.Array(Schema.Struct({
57
+ name: Schema.String,
58
+ tier: Schema.Literal("build", "db", "role"),
59
+ description: Schema.String,
60
+ state: Schema.Literal("on", "off", "rules"),
61
+ source: Schema.Literal("env", "database", "code", "build"),
62
+ roles: Schema.NullOr(Schema.mutable(Schema.Array(UserRoleSchema))),
63
+ power: Schema.NullOr(UserPowerSchema),
64
+ }))),
65
+ });
66
+ // ─── History ────────────────────────────────────────────────────────────────
67
+ const HistoryRangeSchema = Schema.Literal("all", "30d", "7d");
68
+ const SoloHistoryEntrySchema = Schema.Struct({
69
+ id: Schema.String,
70
+ total_score: Schema.Number,
71
+ total_answered: Schema.Number,
72
+ correct_count: Schema.Number,
73
+ time_to_answer_avg_ms: Schema.Number,
74
+ max_streak: Schema.Number,
75
+ mode: Schema.String,
76
+ difficulty: Schema.String,
77
+ category_ids: Schema.String,
78
+ completed_at: Schema.Number,
79
+ });
80
+ const SoloStatsSchema = Schema.Struct({
81
+ runs: Schema.Number,
82
+ best_score: Schema.Number,
83
+ best_streak: Schema.Number,
84
+ total_answered: Schema.Number,
85
+ total_correct: Schema.Number,
86
+ });
87
+ const SoloAttemptStatsSchema = Schema.Struct({
88
+ attempts: Schema.Number,
89
+ focusRate: Schema.Number,
90
+ fastestCorrectMs: Schema.NullOr(Schema.Number),
91
+ });
92
+ const SoloCategoryMasterySchema = Schema.Struct({
93
+ categoryId: Schema.String,
94
+ correct: Schema.Number,
95
+ total: Schema.Number,
96
+ });
97
+ const PlayerGameStatsSchema = Schema.Struct({
98
+ games: Schema.Number,
99
+ wins: Schema.Number,
100
+ podiums: Schema.Number,
101
+ best_rank: Schema.NullOr(Schema.Number),
102
+ });
103
+ const PlayerGamePlacementSchema = Schema.Struct({
104
+ id: Schema.String,
105
+ quiz_name: Schema.String,
106
+ started_at: Schema.String,
107
+ final_score: Schema.Number,
108
+ rank: Schema.Number,
109
+ player_count: Schema.Number,
110
+ badges: Schema.mutable(Schema.Array(BadgeIdSchema)),
111
+ });
112
+ /** Body of `GET /api/pages/history`. */
113
+ export const HistoryPageSchema = Schema.Struct({
114
+ range: HistoryRangeSchema,
115
+ runs: Schema.mutable(Schema.Array(SoloHistoryEntrySchema)),
116
+ trendRuns: Schema.mutable(Schema.Array(SoloHistoryEntrySchema)),
117
+ latestRunAt: Schema.NullOr(Schema.Number),
118
+ latestGameAt: Schema.NullOr(Schema.String),
119
+ stats: SoloStatsSchema,
120
+ badgeTally: BadgeTallySchema,
121
+ categoryName: Schema.mutable(Schema.Record({ key: Schema.String, value: Schema.String })),
122
+ attemptStats: SoloAttemptStatsSchema,
123
+ dayStreak: Schema.Number,
124
+ mastery: Schema.Struct({
125
+ strongest: Schema.NullOr(SoloCategoryMasterySchema),
126
+ weakest: Schema.NullOr(SoloCategoryMasterySchema),
127
+ }),
128
+ gameStats: PlayerGameStatsSchema,
129
+ games: Schema.mutable(Schema.Array(PlayerGamePlacementSchema)),
130
+ runsNextCursor: Schema.NullOr(Schema.String),
131
+ gamesNextCursor: Schema.NullOr(Schema.String),
132
+ });
133
+ // ─── Game review ────────────────────────────────────────────────────────────
134
+ const GameStandingEntrySchema = Schema.Struct({
135
+ id: Schema.String,
136
+ nickname: Schema.String,
137
+ score: Schema.Number,
138
+ rank: Schema.Number,
139
+ isViewer: Schema.Boolean,
140
+ avatarId: Schema.NullOr(Schema.String),
141
+ role: Schema.NullOr(PlayerRoleSchema),
142
+ avatarSrc: Schema.String,
143
+ });
144
+ /** Body of `GET /api/pages/history/game/:id`. */
145
+ export const GameReviewPageSchema = Schema.Struct({
146
+ game: Schema.Struct({
147
+ id: Schema.String,
148
+ quizName: Schema.String,
149
+ startedAt: Schema.String,
150
+ finalScore: Schema.Number,
151
+ rank: Schema.Number,
152
+ playerCount: Schema.Number,
153
+ }),
154
+ standings: Schema.mutable(Schema.Array(GameStandingEntrySchema)),
155
+ badges: Schema.mutable(Schema.Array(Schema.Struct({ id: BadgeIdSchema, rarity: RaritySchema }))),
156
+ breakdown: Schema.NullOr(Schema.mutable(Schema.Array(GameAnswerRecordSchema))),
157
+ categoryName: Schema.mutable(Schema.Record({ key: Schema.String, value: Schema.String })),
158
+ stats: Schema.Struct({
159
+ answered: Schema.Number,
160
+ correct: Schema.Number,
161
+ accuracy: Schema.NullOr(Schema.Number),
162
+ avgTimeMs: Schema.NullOr(Schema.Number),
163
+ }),
164
+ alreadyFlaggedIds: Schema.mutable(Schema.Array(Schema.String)),
165
+ });
166
+ // ─── Solo review ────────────────────────────────────────────────────────────
167
+ const SoloRunReviewEntrySchema = Schema.Struct({
168
+ questionPosition: Schema.Number,
169
+ isCorrect: Schema.Boolean,
170
+ timeToAnswerMs: Schema.Number,
171
+ categoryId: Schema.NullOr(Schema.String),
172
+ questionText: Schema.NullOr(Schema.String),
173
+ difficulty: Schema.NullOr(Schema.String),
174
+ selectedAnswerText: Schema.NullOr(Schema.String),
175
+ correctAnswerText: Schema.NullOr(Schema.String),
176
+ questionId: Schema.NullOr(Schema.String),
177
+ mediaUrl: Schema.NullOr(Schema.String),
178
+ mediaType: Schema.NullOr(MediaTypeSchema),
179
+ source: Schema.NullOr(QuestionSourceSchema),
180
+ postAnswerNote: Schema.NullOr(Schema.String),
181
+ });
182
+ /** Body of `GET /api/pages/history/solo/:id`. */
183
+ export const SoloReviewPageSchema = Schema.Struct({
184
+ run: Schema.Struct({
185
+ id: Schema.String,
186
+ totalScore: Schema.Number,
187
+ totalAnswered: Schema.Number,
188
+ correctCount: Schema.Number,
189
+ timeToAnswerAvgMs: Schema.Number,
190
+ maxStreak: Schema.Number,
191
+ mode: Schema.String,
192
+ difficulty: Schema.String,
193
+ completedAt: Schema.Number,
194
+ categories: Schema.mutable(Schema.Array(Schema.String)),
195
+ }),
196
+ badges: Schema.mutable(Schema.Array(Schema.Struct({ id: BadgeIdSchema, rarity: RaritySchema }))),
197
+ categoryStats: Schema.mutable(Schema.Array(Schema.Struct({
198
+ categoryId: Schema.String,
199
+ name: Schema.String,
200
+ correct: Schema.Number,
201
+ total: Schema.Number,
202
+ }))),
203
+ review: Schema.mutable(Schema.Array(SoloRunReviewEntrySchema)),
204
+ alreadyFlaggedIds: Schema.mutable(Schema.Array(Schema.String)),
205
+ });
206
+ // ─── Display ────────────────────────────────────────────────────────────────
207
+ /** Body of `GET /api/pages/display`. */
208
+ export const DisplayPageSchema = Schema.Struct({
209
+ displayToken: Schema.String,
210
+ });
@@ -0,0 +1,150 @@
1
+ import { Schema } from "effect";
2
+ /** Body of `GET /api/layout`. */
3
+ export declare const LayoutPageSchema: Schema.Struct<{
4
+ user: Schema.Struct<{
5
+ id: typeof Schema.String;
6
+ nickname: Schema.NullOr<typeof Schema.String>;
7
+ avatar: Schema.NullOr<typeof Schema.String>;
8
+ role: Schema.Literal<["anonymous", "display", "member", "curator", "admin"]>;
9
+ powers: Schema.mutable<Schema.Array$<Schema.Literal<["can-access-mimic", "can-send-feedback", "can-import-quizzes", "can-manage-features", "can-add-questions", "can-manage-categories", "can-moderate-questions", "can-publish-questions", "is-power-user", "can-manage-avatars", "can-apply-for-curation", "can-1v1"]>>>;
10
+ lobbyCode: Schema.NullOr<typeof Schema.String>;
11
+ lobbyRole: Schema.optional<Schema.Literal<["curator"]>>;
12
+ accountRole: Schema.optional<Schema.Literal<["anonymous", "display", "member", "curator", "admin"]>>;
13
+ emailVerified: typeof Schema.Boolean;
14
+ accountUserId: Schema.optional<typeof Schema.String>;
15
+ }>;
16
+ theme: Schema.Struct<{
17
+ mode: Schema.Union<[Schema.Literal<["dark", "light", "system", "dynamic"]>, Schema.Literal<["night", "dawn", "morning", "noon", "evening", "sunset", "dusk"]>]>;
18
+ effective: Schema.Literal<["dark", "light"]>;
19
+ phase: Schema.Literal<["night", "dawn", "morning", "noon", "evening", "sunset", "dusk"]>;
20
+ showStars: typeof Schema.Boolean;
21
+ showSky: typeof Schema.Boolean;
22
+ showBirds: typeof Schema.Boolean;
23
+ skyTimeOfDay: Schema.Literal<["dawn", "morning", "noon", "evening", "sunset", "dusk"]>;
24
+ renderBoth: typeof Schema.Boolean;
25
+ }>;
26
+ analytics: Schema.Struct<{
27
+ enabled: typeof Schema.Boolean;
28
+ browserSignal: typeof Schema.Boolean;
29
+ }>;
30
+ feedbackWidgetEnabled: typeof Schema.Boolean;
31
+ uiFlags: Schema.SchemaClass<{
32
+ readonly FEEDBACK_WIDGET?: boolean | undefined;
33
+ readonly ENABLE_IMPORTS?: boolean | undefined;
34
+ readonly PLAYER_HISTORY?: boolean | undefined;
35
+ readonly CURATOR_HISTORY?: boolean | undefined;
36
+ readonly SOLO_LEADERBOARDS?: boolean | undefined;
37
+ readonly QUIZ_SCORING_MODES?: boolean | undefined;
38
+ readonly QUIZ_ACCESS_MODES?: boolean | undefined;
39
+ readonly QUIZ_MAX_PLAYERS?: boolean | undefined;
40
+ readonly QUIZ_PRESETS?: boolean | undefined;
41
+ readonly IMAGE_QUIZ_CATEGORY?: boolean | undefined;
42
+ readonly BADGE_DISPLAY?: boolean | undefined;
43
+ readonly ROLE_SELECTION?: boolean | undefined;
44
+ }, {
45
+ readonly FEEDBACK_WIDGET?: boolean | undefined;
46
+ readonly ENABLE_IMPORTS?: boolean | undefined;
47
+ readonly PLAYER_HISTORY?: boolean | undefined;
48
+ readonly CURATOR_HISTORY?: boolean | undefined;
49
+ readonly SOLO_LEADERBOARDS?: boolean | undefined;
50
+ readonly QUIZ_SCORING_MODES?: boolean | undefined;
51
+ readonly QUIZ_ACCESS_MODES?: boolean | undefined;
52
+ readonly QUIZ_MAX_PLAYERS?: boolean | undefined;
53
+ readonly QUIZ_PRESETS?: boolean | undefined;
54
+ readonly IMAGE_QUIZ_CATEGORY?: boolean | undefined;
55
+ readonly BADGE_DISPLAY?: boolean | undefined;
56
+ readonly ROLE_SELECTION?: boolean | undefined;
57
+ }, never>;
58
+ }>;
59
+ declare const PlayerJourneySchema: Schema.Struct<{
60
+ membership: Schema.Literal<["none", "pending", "active"]>;
61
+ phase: Schema.NullOr<Schema.Literal<["lobby", "playing", "round_results", "final_scores", "role_selection", "intermission"]>>;
62
+ state: Schema.Literal<["code-entry", "setup", "pending", "lobby", "playing", "role_selection", "final_scores"]>;
63
+ route: typeof Schema.String;
64
+ }>;
65
+ /** Where a player belongs right now, and the canonical route for that state. */
66
+ export type PlayerJourney = typeof PlayerJourneySchema.Type;
67
+ /** Body of `GET /api/quiz/journey`: a `PlayerJourney` plus the registry-miss diagnosis. */
68
+ export declare const QuizJourneyPageSchema: Schema.Struct<{
69
+ miss: Schema.NullOr<Schema.Literal<["lobby_lost"]>>;
70
+ membership: Schema.Literal<["none", "pending", "active"]>;
71
+ phase: Schema.NullOr<Schema.Literal<["lobby", "playing", "round_results", "final_scores", "role_selection", "intermission"]>>;
72
+ state: Schema.Literal<["code-entry", "setup", "pending", "lobby", "playing", "role_selection", "final_scores"]>;
73
+ route: typeof Schema.String;
74
+ }>;
75
+ /** Body of `GET /api/quiz/context`. */
76
+ export declare const QuizContextPageSchema: Schema.Struct<{
77
+ membership: Schema.Literal<["none", "pending", "active"]>;
78
+ phase: Schema.NullOr<Schema.Literal<["lobby", "playing", "round_results", "final_scores", "role_selection", "intermission"]>>;
79
+ playerId: Schema.NullOr<typeof Schema.String>;
80
+ isCurator: typeof Schema.Boolean;
81
+ curatorNickname: typeof Schema.String;
82
+ curatorAvatarId: typeof Schema.String;
83
+ isLoggedIn: typeof Schema.Boolean;
84
+ profileAvatarId: typeof Schema.String;
85
+ avatars: Schema.mutable<Schema.Array$<Schema.Struct<{
86
+ id: typeof Schema.String;
87
+ title: typeof Schema.String;
88
+ description: typeof Schema.String;
89
+ category: typeof Schema.String;
90
+ src: typeof Schema.String;
91
+ }>>>;
92
+ emotesEnabled: typeof Schema.Boolean;
93
+ lobby: Schema.NullOr<Schema.Struct<{
94
+ quizName: typeof Schema.String;
95
+ description: typeof Schema.String;
96
+ categories: Schema.mutable<Schema.Array$<typeof Schema.String>>;
97
+ difficulty: Schema.NullOr<Schema.Literal<["all", "easy", "medium", "hard"]>>;
98
+ accessMode: Schema.Literal<["open", "invite-only"]>;
99
+ maxPlayers: Schema.NullOr<typeof Schema.Number>;
100
+ players: Schema.mutable<Schema.Array$<Schema.Struct<{
101
+ id: typeof Schema.String;
102
+ nickname: typeof Schema.String;
103
+ avatar: typeof Schema.String;
104
+ score: typeof Schema.Number;
105
+ status: Schema.Literal<["pending", "active", "disconnected"]>;
106
+ role: Schema.Literal<["player", "observer"]>;
107
+ }>>>;
108
+ }>>;
109
+ stateMessages: Schema.mutable<Schema.Array$<typeof Schema.Unknown>>;
110
+ journey: Schema.Struct<{
111
+ membership: Schema.Literal<["none", "pending", "active"]>;
112
+ phase: Schema.NullOr<Schema.Literal<["lobby", "playing", "round_results", "final_scores", "role_selection", "intermission"]>>;
113
+ state: Schema.Literal<["code-entry", "setup", "pending", "lobby", "playing", "role_selection", "final_scores"]>;
114
+ route: typeof Schema.String;
115
+ }>;
116
+ }>;
117
+ /** Body of `GET /api/quiz/results`. */
118
+ export declare const QuizResultsPageSchema: Schema.Struct<{
119
+ isAnonymousPlayer: typeof Schema.Boolean;
120
+ claimed: typeof Schema.Boolean;
121
+ breakdown: Schema.NullOr<Schema.mutable<Schema.Array$<Schema.Struct<{
122
+ questionIndex: typeof Schema.Number;
123
+ categoryId: typeof Schema.String;
124
+ difficulty: Schema.optional<Schema.Literal<["easy", "medium", "hard"]>>;
125
+ isCorrect: typeof Schema.Boolean;
126
+ timeToAnswerMs: typeof Schema.Number;
127
+ questionId: Schema.optional<typeof Schema.String>;
128
+ questionText: Schema.optional<typeof Schema.String>;
129
+ selectedAnswerId: Schema.optional<typeof Schema.String>;
130
+ selectedAnswerText: Schema.optional<typeof Schema.String>;
131
+ correctAnswerId: Schema.optional<typeof Schema.String>;
132
+ correctAnswerText: Schema.optional<typeof Schema.String>;
133
+ mediaUrl: Schema.optional<typeof Schema.String>;
134
+ mediaType: Schema.optional<Schema.Literal<["image", "audio", "video"]>>;
135
+ source: Schema.optional<Schema.Struct<{
136
+ url: Schema.filter<Schema.filter<typeof Schema.String>>;
137
+ label: Schema.optional<Schema.filter<typeof Schema.String>>;
138
+ }>>;
139
+ postAnswerNote: Schema.optional<typeof Schema.String>;
140
+ }>>>>;
141
+ canFlag: typeof Schema.Boolean;
142
+ alreadyFlaggedIds: Schema.mutable<Schema.Array$<typeof Schema.String>>;
143
+ hostAllowance: Schema.NullOr<Schema.Struct<{
144
+ counted: typeof Schema.Boolean;
145
+ used: typeof Schema.Number;
146
+ limit: typeof Schema.Number;
147
+ left: typeof Schema.Number;
148
+ }>>;
149
+ }>;
150
+ export {};