@orakl/protocol 0.10.0 → 0.12.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/emotes.d.ts CHANGED
@@ -1,5 +1,73 @@
1
- export declare const EMOTE_SPRITES: Record<string, {
2
- x: number;
3
- y: number;
1
+ import { Schema } from "effect";
2
+ /** Most emotes a Player's set holds. */
3
+ export declare const MAX_EMOTE_SET = 5;
4
+ /** An emote id on the wire: a seeded name (e.g. `heart`) or a generated id. */
5
+ export declare const EmoteIdSchema: Schema.filter<typeof Schema.String>;
6
+ /** A Player's chosen emotes, in their order. */
7
+ export declare const EmoteSetSchema: Schema.mutable<Schema.filter<Schema.Array$<Schema.filter<typeof Schema.String>>>>;
8
+ /** One live emote in the public gallery. */
9
+ export declare const EmoteSchema: Schema.Struct<{
10
+ id: typeof Schema.String;
11
+ title: typeof Schema.String;
12
+ description: typeof Schema.String;
13
+ /** Public, content-hashed image path; may be animated. */
14
+ src: typeof Schema.String;
15
+ /** First frame, shown when the viewer asks for reduced motion. */
16
+ stillSrc: typeof Schema.String;
17
+ }>;
18
+ export type Emote = typeof EmoteSchema.Type;
19
+ /** One pack in the public gallery: its live emotes in the Admin's order. */
20
+ export declare const EmotePackSchema: Schema.Struct<{
21
+ id: typeof Schema.String;
22
+ title: typeof Schema.String;
23
+ description: typeof Schema.String;
24
+ /** The pack whose first emotes a Player who chose nothing gets. */
25
+ isDefault: typeof Schema.Boolean;
26
+ emotes: Schema.mutable<Schema.Array$<Schema.Struct<{
27
+ id: typeof Schema.String;
28
+ title: typeof Schema.String;
29
+ description: typeof Schema.String;
30
+ /** Public, content-hashed image path; may be animated. */
31
+ src: typeof Schema.String;
32
+ /** First frame, shown when the viewer asks for reduced motion. */
33
+ stillSrc: typeof Schema.String;
34
+ }>>>;
35
+ }>;
36
+ export type EmotePack = typeof EmotePackSchema.Type;
37
+ /** Body of `GET /api/emotes`: every pack with live emotes, in pack order. */
38
+ export declare const EmoteGallerySchema: Schema.mutable<Schema.Array$<Schema.Struct<{
39
+ id: typeof Schema.String;
40
+ title: typeof Schema.String;
41
+ description: typeof Schema.String;
42
+ /** The pack whose first emotes a Player who chose nothing gets. */
43
+ isDefault: typeof Schema.Boolean;
44
+ emotes: Schema.mutable<Schema.Array$<Schema.Struct<{
45
+ id: typeof Schema.String;
46
+ title: typeof Schema.String;
47
+ description: typeof Schema.String;
48
+ /** Public, content-hashed image path; may be animated. */
49
+ src: typeof Schema.String;
50
+ /** First frame, shown when the viewer asks for reduced motion. */
51
+ stillSrc: typeof Schema.String;
52
+ }>>>;
53
+ }>>>;
54
+ /** Body of `GET /api/pages/admin/emotes`: every pack and emote, retired ones included. */
55
+ export declare const ManageEmotesPageSchema: Schema.Struct<{
56
+ packs: Schema.mutable<Schema.Array$<Schema.Struct<{
57
+ id: typeof Schema.String;
58
+ title: typeof Schema.String;
59
+ description: typeof Schema.String;
60
+ sortOrder: typeof Schema.Number;
61
+ isDefault: typeof Schema.Boolean;
62
+ emotes: Schema.mutable<Schema.Array$<Schema.Struct<{
63
+ sortOrder: typeof Schema.Number;
64
+ /** Hidden from the gallery and pickers; a Game in progress keeps showing it. */
65
+ retired: typeof Schema.Boolean;
66
+ id: typeof Schema.String;
67
+ title: typeof Schema.String;
68
+ description: typeof Schema.String;
69
+ src: typeof Schema.String;
70
+ stillSrc: typeof Schema.String;
71
+ }>>>;
72
+ }>>>;
4
73
  }>;
5
- export declare const SELECTABLE_EMOTE_IDS: readonly ["alert", "anger", "bars", "cash", "circle", "cloud", "cross", "dots1", "dots2", "dots3", "drop", "drops", "exclamation", "exclamations", "faceAngry", "faceHappy", "faceSad", "heart", "heartBroken", "hearts", "idea", "laugh", "music", "question", "sleep", "sleeps", "star", "stars", "swirl"];
package/dist/emotes.js CHANGED
@@ -1,62 +1,45 @@
1
- export const EMOTE_SPRITES = {
2
- alert: { x: 64, y: 64 },
3
- anger: { x: 64, y: 48 },
4
- bars: { x: 64, y: 32 },
5
- cash: { x: 64, y: 16 },
6
- circle: { x: 64, y: 0 },
7
- cloud: { x: 48, y: 80 },
8
- cross: { x: 48, y: 64 },
9
- dots1: { x: 48, y: 48 },
10
- dots2: { x: 48, y: 32 },
11
- dots3: { x: 48, y: 16 },
12
- drop: { x: 48, y: 0 },
13
- drops: { x: 32, y: 80 },
14
- exclamation: { x: 32, y: 64 },
15
- exclamations: { x: 32, y: 48 },
16
- faceAngry: { x: 64, y: 80 },
17
- faceHappy: { x: 32, y: 16 },
18
- faceSad: { x: 32, y: 0 },
19
- heart: { x: 16, y: 80 },
20
- heartBroken: { x: 16, y: 64 },
21
- hearts: { x: 16, y: 48 },
22
- idea: { x: 16, y: 32 },
23
- laugh: { x: 16, y: 16 },
24
- music: { x: 16, y: 0 },
25
- question: { x: 0, y: 80 },
26
- sleep: { x: 0, y: 64 },
27
- sleeps: { x: 0, y: 48 },
28
- star: { x: 0, y: 32 },
29
- stars: { x: 0, y: 16 },
30
- swirl: { x: 0, y: 0 },
31
- };
32
- export const SELECTABLE_EMOTE_IDS = [
33
- "alert",
34
- "anger",
35
- "bars",
36
- "cash",
37
- "circle",
38
- "cloud",
39
- "cross",
40
- "dots1",
41
- "dots2",
42
- "dots3",
43
- "drop",
44
- "drops",
45
- "exclamation",
46
- "exclamations",
47
- "faceAngry",
48
- "faceHappy",
49
- "faceSad",
50
- "heart",
51
- "heartBroken",
52
- "hearts",
53
- "idea",
54
- "laugh",
55
- "music",
56
- "question",
57
- "sleep",
58
- "sleeps",
59
- "star",
60
- "stars",
61
- "swirl",
62
- ];
1
+ import { Schema } from "effect";
2
+ /** Most emotes a Player's set holds. */
3
+ export const MAX_EMOTE_SET = 5;
4
+ /** An emote id on the wire: a seeded name (e.g. `heart`) or a generated id. */
5
+ export const EmoteIdSchema = Schema.String.pipe(Schema.pattern(/^[A-Za-z0-9_-]{1,64}$/));
6
+ /** A Player's chosen emotes, in their order. */
7
+ export const EmoteSetSchema = Schema.mutable(Schema.Array(EmoteIdSchema).pipe(Schema.maxItems(MAX_EMOTE_SET)));
8
+ /** One live emote in the public gallery. */
9
+ export const EmoteSchema = Schema.Struct({
10
+ id: Schema.String,
11
+ title: Schema.String,
12
+ description: Schema.String,
13
+ /** Public, content-hashed image path; may be animated. */
14
+ src: Schema.String,
15
+ /** First frame, shown when the viewer asks for reduced motion. */
16
+ stillSrc: Schema.String,
17
+ });
18
+ /** One pack in the public gallery: its live emotes in the Admin's order. */
19
+ export const EmotePackSchema = Schema.Struct({
20
+ id: Schema.String,
21
+ title: Schema.String,
22
+ description: Schema.String,
23
+ /** The pack whose first emotes a Player who chose nothing gets. */
24
+ isDefault: Schema.Boolean,
25
+ emotes: Schema.mutable(Schema.Array(EmoteSchema)),
26
+ });
27
+ /** Body of `GET /api/emotes`: every pack with live emotes, in pack order. */
28
+ export const EmoteGallerySchema = Schema.mutable(Schema.Array(EmotePackSchema));
29
+ const ManagedEmoteSchema = Schema.Struct({
30
+ ...EmoteSchema.fields,
31
+ sortOrder: Schema.Number,
32
+ /** Hidden from the gallery and pickers; a Game in progress keeps showing it. */
33
+ retired: Schema.Boolean,
34
+ });
35
+ /** Body of `GET /api/pages/admin/emotes`: every pack and emote, retired ones included. */
36
+ export const ManageEmotesPageSchema = Schema.Struct({
37
+ packs: Schema.mutable(Schema.Array(Schema.Struct({
38
+ id: Schema.String,
39
+ title: Schema.String,
40
+ description: Schema.String,
41
+ sortOrder: Schema.Number,
42
+ isDefault: Schema.Boolean,
43
+ emotes: Schema.mutable(Schema.Array(ManagedEmoteSchema)),
44
+ }))),
45
+ });
@@ -1 +1 @@
1
- export type ErrorCode = "no_active_lobby" | "no_active_game" | "device_blocked" | "nickname_taken" | "device_in_lobby" | "player_not_found" | "player_not_pending" | "intermission_invalid_phase" | "not_in_intermission" | "category_name_exists" | "category_not_found" | "category_has_questions" | "tag_name_exists" | "tag_not_found" | "tag_has_questions" | "tag_in_season" | "category_in_season" | "season_name_exists" | "season_not_found" | "user_not_found" | "curation_request_pending" | "curator_self_join" | "already_flagged" | "question_not_found" | "invalid_answer" | "game_in_progress" | "already_answered" | "observer_forbidden" | "no_questions" | "season_out_of_season" | "no_categories" | "too_few_players" | "hosting_closed" | "not_answered" | "flag_not_toggleable" | "solo_invalid_phase" | "solo_invalid_answer" | "solo_nonce_mismatch" | "solo_answer_expired" | "solo_guest_limit" | "solo_no_questions" | "solo_season_out_of_season" | "solo_resume_denied" | "solo_auth_failed";
1
+ export type ErrorCode = "no_active_lobby" | "no_active_game" | "device_blocked" | "nickname_taken" | "nickname_locked" | "device_in_lobby" | "player_not_found" | "player_not_pending" | "intermission_invalid_phase" | "not_in_intermission" | "category_name_exists" | "category_not_found" | "category_has_questions" | "tag_name_exists" | "tag_not_found" | "tag_has_questions" | "tag_in_season" | "category_in_season" | "season_name_exists" | "season_not_found" | "user_not_found" | "curation_request_pending" | "curator_self_join" | "already_flagged" | "question_not_found" | "invalid_answer" | "game_in_progress" | "already_answered" | "observer_forbidden" | "no_questions" | "season_out_of_season" | "no_categories" | "too_few_players" | "hosting_closed" | "not_answered" | "emote_not_in_set" | "flag_not_toggleable" | "solo_invalid_phase" | "solo_invalid_answer" | "solo_nonce_mismatch" | "solo_answer_expired" | "solo_guest_limit" | "solo_no_questions" | "solo_season_out_of_season" | "solo_resume_denied" | "solo_auth_failed";
package/dist/game.d.ts CHANGED
@@ -19,6 +19,8 @@ export interface Player {
19
19
  id: string;
20
20
  nickname: string;
21
21
  avatar: string;
22
+ /** The Player's resolved emote set, in their order; the only ids they may send. */
23
+ emotes: string[];
22
24
  score: number;
23
25
  ready: boolean;
24
26
  status: PlayerStatus;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type { BadgeAward, BadgeId, BadgeMode, BadgeRunParams, } from "./badges.ts";
2
- export { EMOTE_SPRITES, SELECTABLE_EMOTE_IDS } from "./emotes.ts";
2
+ export { type Emote, EmoteGallerySchema, EmoteIdSchema, type EmotePack, EmotePackSchema, EmoteSchema, EmoteSetSchema, MAX_EMOTE_SET, ManageEmotesPageSchema, } from "./emotes.ts";
3
3
  export type { ErrorCode } from "./error-codes.ts";
4
4
  export { type AdvanceMode, type Difficulty, type DifficultyFilter, GAME, type QuestionsPerRound, type ScoringMode, type TimerDuration, } from "./game.settings.ts";
5
5
  export type { AccessMode, ActiveGamePhase, GamePhase, GameState, ImageMatchingQuizQuestion, Player, PlayerRole, PlayerStatus, QuizAnswer, QuizConfig, QuizQuestion, StandardQuizQuestion, } from "./game.ts";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { EMOTE_SPRITES, SELECTABLE_EMOTE_IDS } from "./emotes.js";
1
+ export { EmoteGallerySchema, EmoteIdSchema, EmotePackSchema, EmoteSchema, EmoteSetSchema, MAX_EMOTE_SET, ManageEmotesPageSchema, } from "./emotes.js";
2
2
  export { GAME, } from "./game.settings.js";
3
3
  export * from "./pages/app.schema.js";
4
4
  export * from "./pages/auth.schema.js";
@@ -19,6 +19,8 @@ export declare const ProfilePageSchema: Schema.Struct<{
19
19
  role: Schema.Literal<["anonymous", "display", "member", "curator", "admin"]>;
20
20
  powers: Schema.mutable<Schema.Array$<Schema.Schema<"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", "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", never>>>;
21
21
  avatar: typeof Schema.String;
22
+ /** Saved emote set, in order. */
23
+ emoteIds: Schema.optional<Schema.mutable<Schema.filter<Schema.Array$<Schema.filter<typeof Schema.String>>>>>;
22
24
  emailVerified: typeof Schema.Boolean;
23
25
  }>;
24
26
  theme: Schema.Struct<{
@@ -1,4 +1,5 @@
1
1
  import { Schema } from "effect";
2
+ import { EmoteSetSchema } from "../emotes.js";
2
3
  import { MediaCreditSchema, MediaTypeSchema, StoredQuestionSourceSchema, } from "../question.schema.js";
3
4
  import { ThemeModeSchema, UserPowerSchema, UserRoleSchema, } from "./common.schema.js";
4
5
  /** Page-load response bodies for `src/api/routes/pages.ts`. */
@@ -55,6 +56,8 @@ export const ProfilePageSchema = Schema.Struct({
55
56
  role: UserRoleSchema,
56
57
  powers: Arr(UserPowerSchema),
57
58
  avatar: Schema.String,
59
+ /** Saved emote set, in order. */
60
+ emoteIds: Schema.optional(EmoteSetSchema),
58
61
  emailVerified: Schema.Boolean,
59
62
  }),
60
63
  theme: Schema.Struct({ mode: ThemeModeSchema }),
@@ -63,7 +63,11 @@ export declare const AdminLobbiesPageSchema: Schema.Struct<{
63
63
  /** Lobby age in whole seconds at read time. */
64
64
  ageSeconds: typeof Schema.Number;
65
65
  roster: Schema.mutable<Schema.Array$<Schema.Struct<{
66
+ /** The Lobby's player id, the target for Admin actions. */
67
+ playerId: typeof Schema.String;
66
68
  nickname: typeof Schema.String;
69
+ /** Avatar id the row chose; "" when none. */
70
+ avatarId: typeof Schema.String;
67
71
  role: Schema.Literal<["player", "observer"]>;
68
72
  status: Schema.Literal<["pending", "active", "disconnected"]>;
69
73
  /** The row is the hosting Curator's own. */
@@ -66,7 +66,11 @@ export const AdminLobbiesPageSchema = Schema.Struct({
66
66
  /** Lobby age in whole seconds at read time. */
67
67
  ageSeconds: Schema.Number,
68
68
  roster: Schema.mutable(Schema.Array(Schema.Struct({
69
+ /** The Lobby's player id, the target for Admin actions. */
70
+ playerId: Schema.String,
69
71
  nickname: Schema.String,
72
+ /** Avatar id the row chose; "" when none. */
73
+ avatarId: Schema.String,
70
74
  role: PlayerRoleSchema,
71
75
  status: Schema.Literal("pending", "active", "disconnected"),
72
76
  /** The row is the hosting Curator's own. */
@@ -92,6 +92,22 @@ export declare const QuizContextPageSchema: Schema.Struct<{
92
92
  src: typeof Schema.String;
93
93
  }>>>;
94
94
  emotesEnabled: typeof Schema.Boolean;
95
+ /** The emote gallery the setup picker offers and the play page draws from. */
96
+ emotePacks: Schema.mutable<Schema.Array$<Schema.Struct<{
97
+ id: typeof Schema.String;
98
+ title: typeof Schema.String;
99
+ description: typeof Schema.String;
100
+ isDefault: typeof Schema.Boolean;
101
+ emotes: Schema.mutable<Schema.Array$<Schema.Struct<{
102
+ id: typeof Schema.String;
103
+ title: typeof Schema.String;
104
+ description: typeof Schema.String;
105
+ src: typeof Schema.String;
106
+ stillSrc: typeof Schema.String;
107
+ }>>>;
108
+ }>>>;
109
+ /** The signed-in Player's saved emote set; absent for a guest. */
110
+ profileEmoteIds: Schema.optional<Schema.mutable<Schema.filter<Schema.Array$<Schema.filter<typeof Schema.String>>>>>;
95
111
  lobby: Schema.NullOr<Schema.Struct<{
96
112
  quizName: typeof Schema.String;
97
113
  description: typeof Schema.String;
@@ -104,6 +120,7 @@ export declare const QuizContextPageSchema: Schema.Struct<{
104
120
  id: typeof Schema.String;
105
121
  nickname: typeof Schema.String;
106
122
  avatar: typeof Schema.String;
123
+ emotes: Schema.mutable<Schema.Array$<typeof Schema.String>>;
107
124
  score: typeof Schema.Number;
108
125
  status: Schema.Literal<["pending", "active", "disconnected"]>;
109
126
  role: Schema.Literal<["player", "observer"]>;
@@ -1,4 +1,5 @@
1
1
  import { Schema } from "effect";
2
+ import { EmotePackSchema, EmoteSetSchema } from "../emotes.js";
2
3
  import { GAME } from "../game.settings.js";
3
4
  import { GameAnswerRecordSchema, PlayerRoleSchema, SkyPhaseSchema, ThemeModeSchema, UserPowerSchema, UserRoleSchema, } from "./common.schema.js";
4
5
  /** Page-load response bodies for `src/api/routes/layout.ts and quiz.ts`. */
@@ -93,6 +94,7 @@ const LobbySchema = Schema.Struct({
93
94
  id: Schema.String,
94
95
  nickname: Schema.String,
95
96
  avatar: Schema.String,
97
+ emotes: Schema.mutable(Schema.Array(Schema.String)),
96
98
  score: Schema.Number,
97
99
  status: PlayerStatusSchema,
98
100
  role: PlayerRoleSchema,
@@ -110,6 +112,10 @@ export const QuizContextPageSchema = Schema.Struct({
110
112
  profileAvatarId: Schema.String,
111
113
  avatars: Schema.mutable(Schema.Array(AvatarSchema)),
112
114
  emotesEnabled: Schema.Boolean,
115
+ /** The emote gallery the setup picker offers and the play page draws from. */
116
+ emotePacks: Schema.mutable(Schema.Array(EmotePackSchema)),
117
+ /** The signed-in Player's saved emote set; absent for a guest. */
118
+ profileEmoteIds: Schema.optional(EmoteSetSchema),
113
119
  lobby: Schema.NullOr(LobbySchema),
114
120
  // Replayed game WS frames, opaque here — applyStateMessages reads their
115
121
  // fields by message `type` on the client, so decoding preserves every key
@@ -8,7 +8,7 @@ export declare const ClientMessageSchema: Schema.Union<[Schema.Struct<{
8
8
  playerId: Schema.optional<Schema.filter<typeof Schema.NonEmptyString>>;
9
9
  }>, Schema.Struct<{
10
10
  type: Schema.Literal<["player:emote"]>;
11
- emoteId: Schema.Literal<["alert", "anger", "bars", "cash", "circle", "cloud", "cross", "dots1", "dots2", "dots3", "drop", "drops", "exclamation", "exclamations", "faceAngry", "faceHappy", "faceSad", "heart", "heartBroken", "hearts", "idea", "laugh", "music", "question", "sleep", "sleeps", "star", "stars", "swirl"]>;
11
+ emoteId: Schema.filter<typeof Schema.String>;
12
12
  offsetX: Schema.filter<Schema.filter<typeof Schema.Number>>;
13
13
  offsetY: Schema.filter<Schema.filter<typeof Schema.Number>>;
14
14
  }>, Schema.Struct<{
@@ -1,5 +1,5 @@
1
1
  import { Schema } from "effect";
2
- import { SELECTABLE_EMOTE_IDS } from "./emotes.js";
2
+ import { EmoteIdSchema } from "./emotes.js";
3
3
  import { GAME } from "./game.settings.js";
4
4
  import { DifficultySchema, MediaCreditSchema, MediaTypeSchema, } from "./question.schema.js";
5
5
  import { OptionalScoringModeSchema } from "./scoring.schema.js";
@@ -31,7 +31,8 @@ const PlayerAnswerMessageSchema = Schema.Struct({
31
31
  });
32
32
  const PlayerEmoteMessageSchema = Schema.Struct({
33
33
  type: Schema.Literal("player:emote"),
34
- emoteId: Schema.Literal(...SELECTABLE_EMOTE_IDS),
34
+ // Any well-formed id; the server refuses one outside the sender's set.
35
+ emoteId: EmoteIdSchema,
35
36
  // Broadcast to every player and used directly as CSS left%/top% (0-1) —
36
37
  // bounded, not just finite, or an attacker-controlled value corrupts the
37
38
  // shared emote overlay for the whole lobby.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orakl/protocol",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Orakl wire contract: WebSocket frames and API response schemas.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {