@orakl/protocol 0.1.1 → 0.3.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.
package/dist/badges.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type BadgeId = "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";
1
+ export type BadgeId = "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" | "herculean" | "undaunted" | "measured" | "strong-start" | "new-heights" | "far-horizons" | "cassandra" | "lone-torch" | "ascendant" | "undisputed";
2
2
  /** Modes a badge can be awarded in. */
3
3
  export type BadgeMode = "solo" | "multiplayer";
4
4
  export interface BadgeAward {
package/dist/index.d.ts CHANGED
@@ -12,12 +12,13 @@ export * from "./pages/quiz.schema.ts";
12
12
  export type { PlayerSafeQuestion } from "./player-safe-question.ts";
13
13
  export { DifficultySchema, type ImageChoiceQuestion, type ImageMatchingQuestion, isHttpsUrl, type Media, MediaSchema, type MediaType, MediaTypeSchema, PostAnswerNoteSchema, type Question, QuestionSchema, type QuestionSource, QuestionSourceSchema, type QuestionType, QuestionTypeSchema, type Source, SourceSchema, type TextChoiceQuestion, type TrueFalseQuestion, } from "./question.schema.ts";
14
14
  export { hasMedia, isImageMatching, isTextChoice, isTrueFalse, } from "./question.ts";
15
+ export type { QuestionRating } from "./question-rating.ts";
15
16
  export { OptionalScoringModeSchema, ScoringModeSchema, } from "./scoring.schema.ts";
16
- export { type SoloAnswerChangeMessage, type SoloAnswerMessage, type SoloAuthMessage, type SoloClientMessage, type SoloErrorMessage, type SoloFinalMessage, type SoloGuestLimitMessage, type SoloLifeSpentMessage, type SoloNextMessage, type SoloPingMessage, type SoloPongMessage, type SoloQuestionMessage, type SoloReadyMessage, type SoloResumeMessage, type SoloRoundResultMessage, type SoloServerMessage, type SoloStartMessage, type SoloStreakBestMessage, type SoloStreakLostMessage, type SoloStreakMessage, type SoloStreakNearMissMessage, type SoloTabBlurMessage, type SoloTabFocusMessage, type SoloTickMessage, soloError, } from "./solo-ws.ts";
17
+ export { type SoloAnswerChangeMessage, type SoloAnswerMessage, type SoloAuthMessage, type SoloClientMessage, type SoloErrorMessage, type SoloFinalMessage, type SoloGuestLimitMessage, type SoloLifeSpentMessage, type SoloNextMessage, type SoloPingMessage, type SoloPongMessage, type SoloQuestionMessage, type SoloRateAckMessage, type SoloRateMessage, type SoloReadyMessage, type SoloResumeMessage, type SoloRoundResultMessage, type SoloServerMessage, type SoloStartMessage, type SoloStreakBestMessage, type SoloStreakLostMessage, type SoloStreakMessage, type SoloStreakNearMissMessage, type SoloTabBlurMessage, type SoloTabFocusMessage, type SoloTickMessage, soloError, } from "./solo-ws.ts";
17
18
  export type { StreakFlourish } from "./streak-flourish.ts";
18
19
  export type { LeaderboardBoard, LeaderboardDifficulty, LeaderboardScope, } from "./wire/leaderboard.ts";
19
20
  export type { OperatorQuestionRevision, PublishManyResult, QuestionRevision, } from "./wire/question-bank.ts";
20
21
  export type { FlagDetail, FlagReporter, FlagStatus, QuestionFlagAnswerSnapshot, QuestionSnapshot, } from "./wire/question-flags.ts";
21
- export type { ClientMessage, CuratorAdvanceMessage, CuratorIntermissionMessage, CuratorPlayerActionMessage, CuratorResetMessage, CuratorStartMessage, CuratorStartRoleSelectionMessage, CuratorStopMessage, GameErrorMessage, GameFinalScoresMessage, GameIntermissionMessage, GamePingMessage, GameQuestionMessage, GameResultsReadyMessage, GameResumeMessage, GameRoundResultMessage, GameStartMessage, GameTickMessage, JoinAcceptedMessage, JoinRejectedMessage, LobbyEndedMessage, LobbyResetMessage, LobbyUpdateMessage, PlayerAnsweredMessage, PlayerAnswerMessage, PlayerEmoteBroadcastMessage, PlayerEmoteMessage, PlayerLeaveMessage, PlayerNicknameChangedMessage, PlayerQuestionAnswer, PlayerRemovedMessage, PlayerRoleMessage, RoleSelectionLockedMessage, RoleSelectionStartMessage, RoleSelectionUpdateMessage, ServerMessage, WsAuthMessage, WsPongMessage, } from "./ws.ts";
22
+ export type { ClientMessage, CuratorAdvanceMessage, CuratorIntermissionMessage, CuratorPlayerActionMessage, CuratorResetMessage, CuratorStartMessage, CuratorStartRoleSelectionMessage, CuratorStopMessage, GameErrorMessage, GameFinalScoresMessage, GameIntermissionMessage, GamePingMessage, GameQuestionMessage, GameResultsReadyMessage, GameResumeMessage, GameRoundResultMessage, GameStartMessage, GameTickMessage, JoinAcceptedMessage, JoinRejectedMessage, LobbyEndedMessage, LobbyResetMessage, LobbyUpdateMessage, PlayerAnsweredMessage, PlayerAnswerMessage, PlayerEmoteBroadcastMessage, PlayerEmoteMessage, PlayerLeaveMessage, PlayerNicknameChangedMessage, PlayerQuestionAnswer, PlayerRateAckMessage, PlayerRateMessage, PlayerRemovedMessage, PlayerRoleMessage, RoleSelectionLockedMessage, RoleSelectionStartMessage, RoleSelectionUpdateMessage, ServerMessage, WsAuthMessage, WsPongMessage, } from "./ws.ts";
22
23
  export { ClientMessageSchema } from "./ws-game.schema.ts";
23
24
  export { SoloClientMessageSchema } from "./ws-solo.schema.ts";
@@ -171,6 +171,48 @@ export declare const ManageFlaggedQuestionsPageSchema: Schema.Struct<{
171
171
  statusFilter: Schema.Literal<["open", "resolved", "all"]>;
172
172
  page: typeof Schema.Number;
173
173
  }>;
174
+ declare const QuestionRatingRowSchema: Schema.Struct<{
175
+ id: typeof Schema.String;
176
+ excerpt: typeof Schema.String;
177
+ source: Schema.Literal<["built-in", "promoted"]>;
178
+ category: typeof Schema.String;
179
+ down: typeof Schema.Number;
180
+ up: typeof Schema.Number;
181
+ downAllTime: typeof Schema.Number;
182
+ upAllTime: typeof Schema.Number;
183
+ edited: typeof Schema.Boolean;
184
+ openFlags: typeof Schema.Number;
185
+ }>;
186
+ /** One rated question on the ratings page: counts since the last edit and all-time, no rater identity. */
187
+ export type QuestionRatingRow = typeof QuestionRatingRowSchema.Type;
188
+ /** Body of `GET /api/pages/manage/question-ratings`. */
189
+ export declare const ManageQuestionRatingsPageSchema: Schema.Struct<{
190
+ initial: Schema.mutable<Schema.Array$<Schema.Schema<{
191
+ readonly source: "built-in" | "promoted";
192
+ readonly id: string;
193
+ readonly up: number;
194
+ readonly category: string;
195
+ readonly excerpt: string;
196
+ readonly down: number;
197
+ readonly downAllTime: number;
198
+ readonly upAllTime: number;
199
+ readonly edited: boolean;
200
+ readonly openFlags: number;
201
+ }, {
202
+ readonly source: "built-in" | "promoted";
203
+ readonly id: string;
204
+ readonly up: number;
205
+ readonly category: string;
206
+ readonly excerpt: string;
207
+ readonly down: number;
208
+ readonly downAllTime: number;
209
+ readonly upAllTime: number;
210
+ readonly edited: boolean;
211
+ readonly openFlags: number;
212
+ }, never>>>;
213
+ initialHasMore: typeof Schema.Boolean;
214
+ page: typeof Schema.Number;
215
+ }>;
174
216
  declare const AuthoredQuestionRowSchema: Schema.Struct<{
175
217
  id: typeof Schema.String;
176
218
  category: typeof Schema.String;
@@ -469,11 +511,23 @@ export declare const CuratorQuestionsPageSchema: Schema.Struct<{
469
511
  readonly label: string;
470
512
  readonly category: string;
471
513
  readonly created_at: string;
514
+ readonly ratings?: {
515
+ readonly up: number;
516
+ readonly down: number;
517
+ readonly downAllTime: number;
518
+ readonly upAllTime: number;
519
+ } | undefined;
472
520
  }, {
473
521
  readonly id: string;
474
522
  readonly label: string;
475
523
  readonly category: string;
476
524
  readonly created_at: string;
525
+ readonly ratings?: {
526
+ readonly up: number;
527
+ readonly down: number;
528
+ readonly downAllTime: number;
529
+ readonly upAllTime: number;
530
+ } | undefined;
477
531
  }, never>>>;
478
532
  questionsCursor: Schema.NullOr<typeof Schema.String>;
479
533
  }>;
@@ -137,6 +137,24 @@ export const ManageFlaggedQuestionsPageSchema = Schema.Struct({
137
137
  statusFilter: Schema.Literal("open", "resolved", "all"),
138
138
  page: Schema.Number,
139
139
  });
140
+ const QuestionRatingRowSchema = Schema.Struct({
141
+ id: Schema.String,
142
+ excerpt: Schema.String,
143
+ source: Schema.Literal("built-in", "promoted"),
144
+ category: Schema.String,
145
+ down: Schema.Number,
146
+ up: Schema.Number,
147
+ downAllTime: Schema.Number,
148
+ upAllTime: Schema.Number,
149
+ edited: Schema.Boolean,
150
+ openFlags: Schema.Number,
151
+ });
152
+ /** Body of `GET /api/pages/manage/question-ratings`. */
153
+ export const ManageQuestionRatingsPageSchema = Schema.Struct({
154
+ initial: Arr(QuestionRatingRowSchema),
155
+ initialHasMore: Schema.Boolean,
156
+ page: Schema.Number,
157
+ });
140
158
  const AuthoredQuestionRowSchema = Schema.Struct({
141
159
  id: Schema.String,
142
160
  category: Schema.String,
@@ -293,6 +311,13 @@ const OwnQuestionSchema = Schema.Struct({
293
311
  category: Schema.String,
294
312
  label: Schema.String,
295
313
  created_at: Schema.String,
314
+ /** Thumbs counts since the last edit and all-time; absent with the rating flag off. */
315
+ ratings: Schema.optional(Schema.Struct({
316
+ up: Schema.Number,
317
+ down: Schema.Number,
318
+ upAllTime: Schema.Number,
319
+ downAllTime: Schema.Number,
320
+ })),
296
321
  });
297
322
  /** Body of `GET /api/pages/curator/questions`. */
298
323
  export const CuratorQuestionsPageSchema = Schema.Struct({
@@ -1,7 +1,7 @@
1
1
  import { Schema } from "effect";
2
2
  /** Page-load response bodies for `src/api/routes/pages-history.ts and admin-feature-flags.ts`. */
3
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"]>;
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", "herculean", "undaunted", "measured", "strong-start", "new-heights", "far-horizons", "cassandra", "lone-torch", "ascendant", "undisputed"]>;
5
5
  /** Rarity tier a badge award reached (mirrors `Rarity` in `src/lib/badges.ts`). */
6
6
  export declare const RaritySchema: Schema.Literal<["common", "rare", "legendary", "exotic"]>;
7
7
  /** Per-badge counts + best rarity across a player's runs (mirrors `BadgeTally`). */
@@ -89,7 +89,7 @@ declare const PlayerGamePlacementSchema: Schema.Struct<{
89
89
  final_score: typeof Schema.Number;
90
90
  rank: typeof Schema.Number;
91
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"]>>>;
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", "herculean", "undaunted", "measured", "strong-start", "new-heights", "far-horizons", "cassandra", "lone-torch", "ascendant", "undisputed"]>>>;
93
93
  }>;
94
94
  export type PlayerGamePlacement = typeof PlayerGamePlacementSchema.Type;
95
95
  /** Body of `GET /api/pages/history`. */
@@ -164,7 +164,7 @@ export declare const HistoryPageSchema: Schema.Struct<{
164
164
  final_score: typeof Schema.Number;
165
165
  rank: typeof Schema.Number;
166
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"]>>>;
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", "herculean", "undaunted", "measured", "strong-start", "new-heights", "far-horizons", "cassandra", "lone-torch", "ascendant", "undisputed"]>>>;
168
168
  }>>>;
169
169
  runsNextCursor: Schema.NullOr<typeof Schema.String>;
170
170
  gamesNextCursor: Schema.NullOr<typeof Schema.String>;
@@ -190,7 +190,7 @@ export declare const GameReviewPageSchema: Schema.Struct<{
190
190
  avatarSrc: typeof Schema.String;
191
191
  }>>>;
192
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"]>;
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", "herculean", "undaunted", "measured", "strong-start", "new-heights", "far-horizons", "cassandra", "lone-torch", "ascendant", "undisputed"]>;
194
194
  rarity: Schema.Literal<["common", "rare", "legendary", "exotic"]>;
195
195
  }>>>;
196
196
  breakdown: Schema.NullOr<Schema.mutable<Schema.Array$<Schema.Struct<{
@@ -240,7 +240,7 @@ export declare const SoloReviewPageSchema: Schema.Struct<{
240
240
  categories: Schema.mutable<Schema.Array$<typeof Schema.String>>;
241
241
  }>;
242
242
  badges: Schema.mutable<Schema.Array$<Schema.Struct<{
243
- 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"]>;
243
+ 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", "herculean", "undaunted", "measured", "strong-start", "new-heights", "far-horizons", "cassandra", "lone-torch", "ascendant", "undisputed"]>;
244
244
  rarity: Schema.Literal<["common", "rare", "legendary", "exotic"]>;
245
245
  }>>>;
246
246
  categoryStats: Schema.mutable<Schema.Array$<Schema.Struct<{
@@ -3,7 +3,7 @@ import { MediaTypeSchema, StoredQuestionSourceSchema, } from "../question.schema
3
3
  import { GameAnswerRecordSchema, PlayerRoleSchema, UserPowerSchema, UserRoleSchema, } from "./common.schema.js";
4
4
  /** Page-load response bodies for `src/api/routes/pages-history.ts and admin-feature-flags.ts`. */
5
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");
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", "herculean", "undaunted", "measured", "strong-start", "new-heights", "far-horizons", "cassandra", "lone-torch", "ascendant", "undisputed");
7
7
  /** Rarity tier a badge award reached (mirrors `Rarity` in `src/lib/badges.ts`). */
8
8
  export const RaritySchema = Schema.Literal("common", "rare", "legendary", "exotic");
9
9
  /** Per-badge counts + best rarity across a player's runs (mirrors `BadgeTally`). */
@@ -41,6 +41,7 @@ export declare const LayoutPageSchema: Schema.Struct<{
41
41
  readonly IMAGE_QUIZ_CATEGORY?: boolean | undefined;
42
42
  readonly BADGE_DISPLAY?: boolean | undefined;
43
43
  readonly ROLE_SELECTION?: boolean | undefined;
44
+ readonly QUESTION_RATING?: boolean | undefined;
44
45
  }, {
45
46
  readonly FEEDBACK_WIDGET?: boolean | undefined;
46
47
  readonly ENABLE_IMPORTS?: boolean | undefined;
@@ -54,6 +55,7 @@ export declare const LayoutPageSchema: Schema.Struct<{
54
55
  readonly IMAGE_QUIZ_CATEGORY?: boolean | undefined;
55
56
  readonly BADGE_DISPLAY?: boolean | undefined;
56
57
  readonly ROLE_SELECTION?: boolean | undefined;
58
+ readonly QUESTION_RATING?: boolean | undefined;
57
59
  }, never>;
58
60
  }>;
59
61
  declare const PlayerJourneySchema: Schema.Struct<{
@@ -45,6 +45,7 @@ const UiFlagsSchema = Schema.partial(Schema.Struct({
45
45
  IMAGE_QUIZ_CATEGORY: Schema.Boolean,
46
46
  BADGE_DISPLAY: Schema.Boolean,
47
47
  ROLE_SELECTION: Schema.Boolean,
48
+ QUESTION_RATING: Schema.Boolean,
48
49
  }));
49
50
  /** Body of `GET /api/layout`. */
50
51
  export const LayoutPageSchema = Schema.Struct({
@@ -0,0 +1,2 @@
1
+ /** A Question rating's thumb: `"up"` is "Good question", `"down"` is "Bad question". */
2
+ export type QuestionRating = "up" | "down";
@@ -0,0 +1 @@
1
+ export {};
package/dist/solo-ws.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { BadgeAward } from "./badges.ts";
2
2
  import type { PlayerSafeQuestion } from "./player-safe-question.ts";
3
3
  import type { MediaType, QuestionSource } from "./question.ts";
4
+ import type { QuestionRating } from "./question-rating.ts";
4
5
  export type SoloAuthMessage = {
5
6
  type: "auth";
6
7
  token: string;
@@ -47,7 +48,15 @@ export type SoloResumeMessage = {
47
48
  /** Secret issued in solo:ready; required to resume a guest session (anti-hijack). */
48
49
  resumeToken?: string;
49
50
  };
50
- export type SoloClientMessage = SoloAuthMessage | SoloStartMessage | SoloAnswerMessage | SoloAnswerChangeMessage | SoloNextMessage | SoloTabBlurMessage | SoloTabFocusMessage | SoloPongMessage | SoloResumeMessage;
51
+ /** Rate a question revealed in this run (signed-in runs only). The server
52
+ * answers with `solo:rate-ack` echoing `questionId`. */
53
+ export type SoloRateMessage = {
54
+ type: "solo:rate";
55
+ /** Bank question id, as on `solo:question`. */
56
+ questionId: string;
57
+ rating: QuestionRating;
58
+ };
59
+ export type SoloClientMessage = SoloAuthMessage | SoloStartMessage | SoloAnswerMessage | SoloAnswerChangeMessage | SoloNextMessage | SoloTabBlurMessage | SoloTabFocusMessage | SoloPongMessage | SoloResumeMessage | SoloRateMessage;
51
60
  export type SoloReadyMessage = {
52
61
  type: "solo:ready";
53
62
  isGuest: boolean;
@@ -199,4 +208,11 @@ export type SoloGuestLimitMessage = {
199
208
  reason: string;
200
209
  upgradeHint: string;
201
210
  };
202
- export type SoloServerMessage = SoloReadyMessage | SoloQuestionMessage | SoloTickMessage | SoloRoundResultMessage | SoloStreakMessage | SoloStreakLostMessage | SoloStreakNearMissMessage | SoloStreakBestMessage | SoloLifeSpentMessage | SoloFinalMessage | SoloPingMessage | SoloErrorMessage | SoloGuestLimitMessage;
211
+ /** Outcome of one `solo:rate`: `ok` is false when the rating was refused or
212
+ * not stored. Failures ride here, never on `solo:error`. */
213
+ export type SoloRateAckMessage = {
214
+ type: "solo:rate-ack";
215
+ questionId: string;
216
+ ok: boolean;
217
+ };
218
+ export type SoloServerMessage = SoloReadyMessage | SoloQuestionMessage | SoloTickMessage | SoloRoundResultMessage | SoloStreakMessage | SoloStreakLostMessage | SoloStreakNearMissMessage | SoloStreakBestMessage | SoloLifeSpentMessage | SoloFinalMessage | SoloPingMessage | SoloErrorMessage | SoloGuestLimitMessage | SoloRateAckMessage;
@@ -16,6 +16,10 @@ export declare const ClientMessageSchema: Schema.Union<[Schema.Struct<{
16
16
  role: Schema.Literal<["player", "observer"]>;
17
17
  }>, Schema.Struct<{
18
18
  type: Schema.Literal<["player:leave"]>;
19
+ }>, Schema.Struct<{
20
+ type: Schema.Literal<["player:rate"]>;
21
+ questionId: Schema.filter<typeof Schema.NonEmptyString>;
22
+ rating: Schema.Literal<["up", "down"]>;
19
23
  }>, Schema.Struct<{
20
24
  type: Schema.Literal<["curator:start"]>;
21
25
  categoryIds: Schema.optional<Schema.filter<Schema.Array$<typeof Schema.NonEmptyString>>>;
@@ -45,6 +45,11 @@ const PlayerRoleMessageSchema = Schema.Struct({
45
45
  const PlayerLeaveMessageSchema = Schema.Struct({
46
46
  type: Schema.Literal("player:leave"),
47
47
  });
48
+ const PlayerRateMessageSchema = Schema.Struct({
49
+ type: Schema.Literal("player:rate"),
50
+ questionId: BoundedIdSchema,
51
+ rating: Schema.Literal("up", "down"),
52
+ });
48
53
  // ─── curator:* ──────────────────────────────────────────────────────────────
49
54
  // QuestionType minus "image_matching" (mirrors StandardQuizQuestion).
50
55
  const StandardQuizQuestionTypeSchema = Schema.Literal("text_choice", "image_choice", "true_false", "finish_line", "audio_identify", "sequence_order", "estimate_range", "fill_blank", "matching_pairs", "progressive_reveal");
@@ -127,5 +132,5 @@ const WsPongMessageSchema = Schema.Struct({
127
132
  });
128
133
  // Discriminant: Effect Schema detects the shared `type: Schema.Literal(...)`
129
134
  // field and short-circuits matching — every member needs a unique `type`.
130
- export const ClientMessageSchema = Schema.Union(WsAuthMessageSchema, PlayerAnswerMessageSchema, PlayerEmoteMessageSchema, PlayerRoleMessageSchema, PlayerLeaveMessageSchema, CuratorStartMessageSchema, CuratorAdvanceMessageSchema, CuratorStartRoleSelectionMessageSchema, CuratorIntermissionMessageSchema, CuratorPlayerActionMessageSchema, CuratorStopMessageSchema, CuratorResetMessageSchema, WsPongMessageSchema);
135
+ export const ClientMessageSchema = Schema.Union(WsAuthMessageSchema, PlayerAnswerMessageSchema, PlayerEmoteMessageSchema, PlayerRoleMessageSchema, PlayerLeaveMessageSchema, PlayerRateMessageSchema, CuratorStartMessageSchema, CuratorAdvanceMessageSchema, CuratorStartRoleSelectionMessageSchema, CuratorIntermissionMessageSchema, CuratorPlayerActionMessageSchema, CuratorStopMessageSchema, CuratorResetMessageSchema, WsPongMessageSchema);
131
136
  const _assertNoClientMessageDrift = null;
@@ -28,4 +28,8 @@ export declare const SoloClientMessageSchema: Schema.Union<[Schema.Struct<{
28
28
  type: Schema.Literal<["solo:resume"]>;
29
29
  sessionId: Schema.filter<typeof Schema.NonEmptyString>;
30
30
  resumeToken: Schema.optional<Schema.filter<typeof Schema.NonEmptyString>>;
31
+ }>, Schema.Struct<{
32
+ type: Schema.Literal<["solo:rate"]>;
33
+ questionId: Schema.filter<typeof Schema.NonEmptyString>;
34
+ rating: Schema.Literal<["up", "down"]>;
31
35
  }>]>;
@@ -51,7 +51,12 @@ const SoloResumeMessageSchema = Schema.Struct({
51
51
  sessionId: BoundedIdSchema,
52
52
  resumeToken: Schema.optional(BoundedIdSchema),
53
53
  });
54
+ const SoloRateMessageSchema = Schema.Struct({
55
+ type: Schema.Literal("solo:rate"),
56
+ questionId: BoundedIdSchema,
57
+ rating: Schema.Literal("up", "down"),
58
+ });
54
59
  // Discriminant: Effect Schema detects the shared `type: Schema.Literal(...)`
55
60
  // field and short-circuits matching — every member needs a unique `type`.
56
- export const SoloClientMessageSchema = Schema.Union(SoloAuthMessageSchema, SoloStartMessageSchema, SoloAnswerMessageSchema, SoloAnswerChangeMessageSchema, SoloNextMessageSchema, SoloTabBlurMessageSchema, SoloTabFocusMessageSchema, SoloPongMessageSchema, SoloResumeMessageSchema);
61
+ export const SoloClientMessageSchema = Schema.Union(SoloAuthMessageSchema, SoloStartMessageSchema, SoloAnswerMessageSchema, SoloAnswerChangeMessageSchema, SoloNextMessageSchema, SoloTabBlurMessageSchema, SoloTabFocusMessageSchema, SoloPongMessageSchema, SoloResumeMessageSchema, SoloRateMessageSchema);
57
62
  const _assertNoSoloClientMessageDrift = null;
package/dist/ws.d.ts CHANGED
@@ -4,8 +4,9 @@ import type { AdvanceMode, Difficulty, DifficultyFilter, ScoringMode, TimerDurat
4
4
  import type { Player, PlayerRole, QuizQuestion } from "./game.ts";
5
5
  import type { GameAnswerRecord } from "./game-answer-record.ts";
6
6
  import type { MediaType, QuestionType } from "./question.schema.ts";
7
+ import type { QuestionRating } from "./question-rating.ts";
7
8
  import type { StreakFlourish } from "./streak-flourish.ts";
8
- export type ClientMessage = WsAuthMessage | PlayerAnswerMessage | PlayerEmoteMessage | PlayerRoleMessage | PlayerLeaveMessage | CuratorStartMessage | CuratorAdvanceMessage | CuratorStartRoleSelectionMessage | CuratorIntermissionMessage | CuratorPlayerActionMessage | CuratorStopMessage | CuratorResetMessage | WsPongMessage;
9
+ export type ClientMessage = WsAuthMessage | PlayerAnswerMessage | PlayerEmoteMessage | PlayerRoleMessage | PlayerLeaveMessage | PlayerRateMessage | CuratorStartMessage | CuratorAdvanceMessage | CuratorStartRoleSelectionMessage | CuratorIntermissionMessage | CuratorPlayerActionMessage | CuratorStopMessage | CuratorResetMessage | WsPongMessage;
9
10
  /** First frame for native/display (cross-origin, no cookie): authenticates the
10
11
  * socket with the bearer game token (ADR 0014). Web rides the cookie instead. */
11
12
  export interface WsAuthMessage {
@@ -34,6 +35,15 @@ export interface PlayerRoleMessage {
34
35
  export interface PlayerLeaveMessage {
35
36
  type: "player:leave";
36
37
  }
38
+ /** Rate a question revealed in this game — from a signed-in player who played
39
+ * its round, or the curator. The server answers with `player:rate-ack`
40
+ * echoing `questionId`. */
41
+ export interface PlayerRateMessage {
42
+ type: "player:rate";
43
+ /** Bank question id, as on `game:question`. */
44
+ questionId: string;
45
+ rating: QuestionRating;
46
+ }
37
47
  /** Curator starts the game. Questions are drawn server-side from categories,
38
48
  * or taken from a curator-side import (preloadedQuestions). */
39
49
  export interface CuratorStartMessage {
@@ -76,7 +86,7 @@ export interface CuratorPlayerActionMessage {
76
86
  export interface WsPongMessage {
77
87
  type: "pong";
78
88
  }
79
- export type ServerMessage = JoinAcceptedMessage | JoinRejectedMessage | LobbyUpdateMessage | LobbyEndedMessage | LobbyResetMessage | PlayerNicknameChangedMessage | GameStartMessage | GameQuestionMessage | GameTickMessage | PlayerAnsweredMessage | GameRoundResultMessage | GameFinalScoresMessage | GameResultsReadyMessage | RoleSelectionStartMessage | RoleSelectionUpdateMessage | RoleSelectionLockedMessage | PlayerRemovedMessage | GameIntermissionMessage | GameResumeMessage | PlayerEmoteBroadcastMessage | GameErrorMessage | GamePingMessage;
89
+ export type ServerMessage = JoinAcceptedMessage | JoinRejectedMessage | LobbyUpdateMessage | LobbyEndedMessage | LobbyResetMessage | PlayerNicknameChangedMessage | GameStartMessage | GameQuestionMessage | GameTickMessage | PlayerAnsweredMessage | GameRoundResultMessage | GameFinalScoresMessage | GameResultsReadyMessage | RoleSelectionStartMessage | RoleSelectionUpdateMessage | RoleSelectionLockedMessage | PlayerRemovedMessage | GameIntermissionMessage | GameResumeMessage | PlayerEmoteBroadcastMessage | GameErrorMessage | GamePingMessage | PlayerRateAckMessage;
80
90
  export interface JoinAcceptedMessage {
81
91
  type: "join:accepted";
82
92
  playerId: string;
@@ -279,3 +289,11 @@ export interface GameErrorMessage {
279
289
  /** Human-readable fallback when the UI has no copy for `code`. */
280
290
  message: string;
281
291
  }
292
+ /** Outcome of one `player:rate`, to the rater only: `ok` is false when the
293
+ * rating was refused or not stored. Failures ride here, never on
294
+ * `game:error`, which carries no request id. */
295
+ export interface PlayerRateAckMessage {
296
+ type: "player:rate-ack";
297
+ questionId: string;
298
+ ok: boolean;
299
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orakl/protocol",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Orakl wire contract: WebSocket frames and API response schemas.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {