@hadoku/watchparty-ui 0.45.9 → 0.45.11

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 (27) hide show
  1. package/dist/chunks/{AdminPanel-BAux2Z40.js → AdminPanel-NqY9bqdB.js} +14 -14
  2. package/dist/chunks/{AdminPanel-BAux2Z40.js.map → AdminPanel-NqY9bqdB.js.map} +1 -1
  3. package/dist/chunks/MediaDrawer-DnJ2bjL7.js +710 -0
  4. package/dist/chunks/MediaDrawer-DnJ2bjL7.js.map +1 -0
  5. package/dist/chunks/{PlaylistPanel-BoleB5vk.js → PlaylistPanel-DKjA4zxR.js} +32 -32
  6. package/dist/chunks/{PlaylistPanel-BoleB5vk.js.map → PlaylistPanel-DKjA4zxR.js.map} +1 -1
  7. package/dist/chunks/{Room-Bnjk24LE.js → Room-H5597D2i.js} +303 -304
  8. package/dist/chunks/Room-H5597D2i.js.map +1 -0
  9. package/dist/chunks/{index-d21ofwW2.js → index-BLeEknCO.js} +3138 -3301
  10. package/dist/chunks/index-BLeEknCO.js.map +1 -0
  11. package/dist/chunks/{submissionsApi-BdWmV6DO.js → submissionsApi-CL9vNf_o.js} +28 -28
  12. package/dist/chunks/{submissionsApi-BdWmV6DO.js.map → submissionsApi-CL9vNf_o.js.map} +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/room-chrome.js +1003 -1093
  15. package/dist/room-chrome.js.map +1 -1
  16. package/dist/watchparty-ui.css +1 -1
  17. package/package.json +3 -3
  18. package/dist/chunks/GameModule-CPrQCsQN.js +0 -1512
  19. package/dist/chunks/GameModule-CPrQCsQN.js.map +0 -1
  20. package/dist/chunks/MapEditor-DfGyp-bV.js +0 -733
  21. package/dist/chunks/MapEditor-DfGyp-bV.js.map +0 -1
  22. package/dist/chunks/MediaDrawer-Dx5XhHiF.js +0 -711
  23. package/dist/chunks/MediaDrawer-Dx5XhHiF.js.map +0 -1
  24. package/dist/chunks/Room-Bnjk24LE.js.map +0 -1
  25. package/dist/chunks/cover-AUIrlUMF.js +0 -5
  26. package/dist/chunks/cover-AUIrlUMF.js.map +0 -1
  27. package/dist/chunks/index-d21ofwW2.js.map +0 -1
@@ -1,30 +1,30 @@
1
1
  import { jsx as c, jsxs as _, Fragment as le } from "react/jsx-runtime";
2
- import Ht, { useState as R, useRef as z, useMemo as Q, useCallback as E, useEffect as D, createContext as $t, useContext as En, useId as Pn, useEffectEvent as Bt } from "react";
3
- import { themePrefs as ie, Icon as Nn, THEMES as Rn, useHadokuThemeOptional as Dn } from "@wolffm/themes";
4
- import { z as r } from "zod";
5
- import { createCdnClient as On, kindOfType as Mn, MAX_BYTES as Ln, measureImage as jn, filesFromClipboard as Un, filesFromDrop as Fn, CdnError as qe } from "@wolffm/cdn-client";
6
- import { create as Hn } from "zustand";
7
- import { createPrefsClient as $n, getDeviceId as Bn, DEVICE_ID_KEY as Gn } from "@wolffm/prefs-client";
8
- import { io as Kn } from "socket.io-client";
9
- import { createAvatarClient as Wn, AvatarError as ht } from "@wolffm/prefs-client/avatar";
10
- import { resolveIdentityReassert as qn } from "@wolffm/rooms-protocol";
11
- import { createPortal as Vn } from "react-dom";
12
- import { useCatalogueSearch as Yn } from "@wolffm/cdn-client/react";
13
- const Gt = "https://cdn.hadoku.me", Kt = /^[0-9a-f]{64}\.(?:png|jpe?g|gif|webp|avif)$/;
2
+ import Ft, { useState as R, useRef as z, useMemo as Q, useCallback as E, useEffect as D, createContext as Ht, useContext as kn, useId as En, useEffectEvent as $t } from "react";
3
+ import { themePrefs as ae, Icon as Pn, THEMES as Nn, useHadokuThemeOptional as Rn } from "@wolffm/themes";
4
+ import { z as o } from "zod";
5
+ import { createCdnClient as Dn, kindOfType as On, MAX_BYTES as Mn, measureImage as Ln, filesFromClipboard as jn, filesFromDrop as Un, CdnError as Ke } from "@wolffm/cdn-client";
6
+ import { create as Fn } from "zustand";
7
+ import { createPrefsClient as Hn, getDeviceId as $n, DEVICE_ID_KEY as Bn } from "@wolffm/prefs-client";
8
+ import { io as Gn } from "socket.io-client";
9
+ import { createAvatarClient as qn, AvatarError as ht } from "@wolffm/prefs-client/avatar";
10
+ import { resolveIdentityReassert as Vn } from "@wolffm/rooms-protocol";
11
+ import { createPortal as Kn } from "react-dom";
12
+ import { useCatalogueSearch as Wn } from "@wolffm/cdn-client/react";
13
+ const Bt = "https://cdn.hadoku.me", Gt = /^[0-9a-f]{64}\.(?:png|jpe?g|gif|webp|avif)$/;
14
14
  function Je(e) {
15
- return typeof e == "string" && Kt.test(e);
16
- }
17
- const Qe = 8080, Wt = 5173, zn = "/watchparty/ws", qt = 500, Xn = 1e3, V = 4, Vt = typeof process < "u" && process.env ? process.env : {};
18
- Vt.PRODUCTION_UI_URL;
19
- Vt.PRODUCTION_SERVER_URL;
20
- const xe = r.enum(["S", "A", "B", "C", "D", "F"]), gt = 2e4, Jn = 300;
21
- r.object({
22
- name: r.string().min(1).max(32).optional(),
23
- sprite: r.string().min(1).max(32).optional(),
15
+ return typeof e == "string" && Gt.test(e);
16
+ }
17
+ const Qe = 8080, qt = 5173, Yn = "/watchparty/ws", Vt = 500, zn = 1e3, W = 4, Kt = typeof process < "u" && process.env ? process.env : {};
18
+ Kt.PRODUCTION_UI_URL;
19
+ Kt.PRODUCTION_SERVER_URL;
20
+ const xe = o.enum(["S", "A", "B", "C", "D", "F"]), gt = 2e4, Xn = 300;
21
+ o.object({
22
+ name: o.string().min(1).max(32).optional(),
23
+ sprite: o.string().min(1).max(32).optional(),
24
24
  /** "My avatar settings just changed — re-read my picture" (the fleet
25
25
  * settings popout's `hadoku:avatar` event). Carries no picture: the server
26
26
  * resolves it from prefs-api by registry userId, never from the client. */
27
- avatar: r.literal(!0).optional()
27
+ avatar: o.literal(!0).optional()
28
28
  });
29
29
  const w = {
30
30
  JOIN: "join",
@@ -44,20 +44,20 @@ const w = {
44
44
  // 'ready_state' here = playback-readiness gate (distinct from READY_EVENTS.STATE = "ready check" UX feature)
45
45
  READY_STATE: "ready_state",
46
46
  ERROR: "error"
47
- }, Qn = r.enum(["play", "pause", "seek", "load", "home"]), Zn = r.object({
48
- framed: r.boolean(),
49
- depth: r.number().int().nonnegative().max(10)
47
+ }, Jn = o.enum(["play", "pause", "seek", "load", "home"]), Qn = o.object({
48
+ framed: o.boolean(),
49
+ depth: o.number().int().nonnegative().max(10)
50
50
  });
51
- r.object({
52
- room_key: r.string(),
53
- name: r.string().min(1).max(32).optional(),
54
- sprite: r.string().min(1).max(32).optional(),
55
- embed: Zn.optional(),
51
+ o.object({
52
+ room_key: o.string(),
53
+ name: o.string().min(1).max(32).optional(),
54
+ sprite: o.string().min(1).max(32).optional(),
55
+ embed: Qn.optional(),
56
56
  /** Which media-delivery path this client resolved to ('range' | 'fragment').
57
57
  * Optional so older clients still validate. Reported so a party's logs can be split by
58
58
  * arm — without it an A/B rollout is unmeasurable, exactly as entry path was before
59
59
  * `embed` existed. */
60
- delivery_arm: r.enum(["range", "fragment"]).optional(),
60
+ delivery_arm: o.enum(["range", "fragment"]).optional(),
61
61
  /** Browser-persisted device id (`hadoku_device_id`, owned by
62
62
  * @wolffm/prefs-client). Lets the server derive a `dev:`-tier
63
63
  * ParticipantId for a client with no friend key, so an anonymous viewer
@@ -69,44 +69,44 @@ r.object({
69
69
  *
70
70
  * CLIENT-ASSERTED — nothing proves it, so it must never gate a capability.
71
71
  * See `isAuthenticatedTier` in @wolffm/rooms-protocol. */
72
- device_id: r.string().min(1).max(128).optional(),
72
+ device_id: o.string().min(1).max(128).optional(),
73
73
  /** Random per PAGE LOAD, carried on every rejoin from that page. A join whose
74
74
  * tab id matches a live connection of the same participant is that tab
75
75
  * reconnecting, so the server retires the old connection at once instead of
76
76
  * showing it as a second row until the heartbeat reaps it (mistral-bluff
77
77
  * 2026-10-20). Never broadcast: it is what lets a rejoin evict a connection.
78
78
  * CLIENT-ASSERTED, so it never gates a capability. */
79
- tab_id: r.string().min(8).max(64).optional(),
79
+ tab_id: o.string().min(8).max(64).optional(),
80
80
  /** Present on a rejoin only: why this page's previous connection ended, as the
81
81
  * BROWSER saw it, and for how long it was gone. The server cannot know either
82
82
  * — a connection cut upstream never reaches it as a close. */
83
- reconnect: r.object({
84
- count: r.number().int().nonnegative(),
85
- reason: r.string().max(64),
86
- offline_ms: r.number().int().nonnegative()
83
+ reconnect: o.object({
84
+ count: o.number().int().nonnegative(),
85
+ reason: o.string().max(64),
86
+ offline_ms: o.number().int().nonnegative()
87
87
  }).optional()
88
88
  });
89
- r.object({
89
+ o.object({
90
90
  // The room's id — the same for every participant, unlike the key each one
91
91
  // joined with (a leader key is a credential). What a game bundle is told
92
92
  // its room is (GameBundleSlot).
93
- room_id: r.string(),
94
- play_state: r.enum(["idle", "playing", "paused", "ended"]),
95
- playhead_ms: r.number().int().nonnegative(),
96
- leader_id: r.string().nullable(),
97
- media_id: r.string().nullable(),
98
- server_seq: r.number().int().nonnegative(),
99
- server_ts: r.number().int().nonnegative()
93
+ room_id: o.string(),
94
+ play_state: o.enum(["idle", "playing", "paused", "ended"]),
95
+ playhead_ms: o.number().int().nonnegative(),
96
+ leader_id: o.string().nullable(),
97
+ media_id: o.string().nullable(),
98
+ server_seq: o.number().int().nonnegative(),
99
+ server_ts: o.number().int().nonnegative()
100
100
  });
101
- r.object({
102
- client_seq: r.number().int().positive(),
103
- kind: Qn,
104
- to_ms: r.number().int().nonnegative().optional(),
105
- media_id: r.string().optional()
101
+ o.object({
102
+ client_seq: o.number().int().positive(),
103
+ kind: Jn,
104
+ to_ms: o.number().int().nonnegative().optional(),
105
+ media_id: o.string().optional()
106
106
  // leader_id removed - not needed since set_leader control was removed
107
107
  });
108
- const Yt = r.object({
109
- key: r.string().regex(Kt, "not a CDN image key"),
108
+ const Wt = o.object({
109
+ key: o.string().regex(Gt, "not a CDN image key"),
110
110
  /**
111
111
  * Intrinsic pixels, or **0 meaning "unknown"**.
112
112
  *
@@ -119,8 +119,8 @@ const Yt = r.object({
119
119
  * text went with it, with nothing said. Widening is backward compatible —
120
120
  * every message already in history carries positive dimensions.
121
121
  */
122
- w: r.number().int().nonnegative().max(gt),
123
- h: r.number().int().nonnegative().max(gt),
122
+ w: o.number().int().nonnegative().max(gt),
123
+ h: o.number().int().nonnegative().max(gt),
124
124
  /**
125
125
  * Human-readable description, rendered as the `alt` text.
126
126
  *
@@ -134,317 +134,235 @@ const Yt = r.object({
134
134
  * value only, never as markup. Bounded so one message cannot carry a
135
135
  * paragraph; the library's own titles run well under this.
136
136
  */
137
- title: r.string().max(Jn).optional()
137
+ title: o.string().max(Xn).optional()
138
138
  });
139
- r.object({
140
- text: r.string().max(qt),
141
- style: r.string().max(64).optional(),
142
- images: r.array(Yt).max(V).optional()
139
+ o.object({
140
+ text: o.string().max(Vt),
141
+ style: o.string().max(64).optional(),
142
+ images: o.array(Wt).max(W).optional()
143
143
  }).refine((e) => e.text.length > 0 || (e.images?.length ?? 0) > 0, { message: "message must carry text or at least one image" });
144
- const er = r.enum(["join", "leave", "media_change", "identity_change", "recap"]);
145
- r.object({
146
- id: r.string(),
147
- client_id: r.string(),
144
+ const Zn = o.enum(["join", "leave", "media_change", "identity_change", "recap"]);
145
+ o.object({
146
+ id: o.string(),
147
+ client_id: o.string(),
148
148
  // The sender's participant handle — stable across their reconnects, unlike
149
149
  // `client_id`. Optional: system messages and pre-existing history have none.
150
- author: r.string().optional(),
151
- name: r.string(),
152
- sprite: r.string().nullable(),
153
- text: r.string(),
154
- ts: r.number(),
150
+ author: o.string().optional(),
151
+ name: o.string(),
152
+ sprite: o.string().nullable(),
153
+ text: o.string(),
154
+ ts: o.number(),
155
155
  // Optional so a client on an older bundle still validates a message that
156
156
  // has none, and so system messages (which never carry images) stay unchanged.
157
- images: r.array(Yt).max(V).optional(),
158
- isSystem: r.boolean().optional(),
159
- systemType: er.optional()
157
+ images: o.array(Wt).max(W).optional(),
158
+ isSystem: o.boolean().optional(),
159
+ systemType: Zn.optional()
160
160
  });
161
- const tr = r.object({
162
- avg_download_rate_bps: r.number().nonnegative(),
163
- buffered_ahead_ms: r.number().nonnegative(),
164
- rtt_ms: r.number().nonnegative(),
165
- playhead_ms: r.number().nonnegative(),
166
- is_buffering: r.boolean(),
167
- fragments_loaded: r.number().int().nonnegative(),
168
- fragments_pending: r.number().int().nonnegative(),
169
- fragments_error: r.number().int().nonnegative(),
170
- video_ready_state: r.number().int().optional(),
161
+ const er = o.object({
162
+ avg_download_rate_bps: o.number().nonnegative(),
163
+ buffered_ahead_ms: o.number().nonnegative(),
164
+ rtt_ms: o.number().nonnegative(),
165
+ playhead_ms: o.number().nonnegative(),
166
+ is_buffering: o.boolean(),
167
+ fragments_loaded: o.number().int().nonnegative(),
168
+ fragments_pending: o.number().int().nonnegative(),
169
+ fragments_error: o.number().int().nonnegative(),
170
+ video_ready_state: o.number().int().optional(),
171
171
  /** Buffered-ahead of the WORST AUDIO track, ms. `buffered_ahead_ms` above is
172
172
  * already the min across video and audio; this is reported separately so the
173
173
  * health card (and any later analysis) can say WHICH track is starving.
174
174
  * -1 means "no audio FragmentManager" (media still loading, or audio not yet
175
175
  * attached) and must never be treated as a zero-length buffer. Defaults to
176
176
  * -1 so older clients, which never send it, are read as "unknown". */
177
- audio_buffered_ahead_ms: r.number().default(-1),
177
+ audio_buffered_ahead_ms: o.number().default(-1),
178
178
  // Nominal media duration (ms) = last fragment's end. Lets the leader's health
179
179
  // card distinguish "near end-of-stream, little buffer ahead is expected" from
180
180
  // a real low-buffer stall. Defaults to 0 so older clients still validate.
181
- duration_ms: r.number().nonnegative().default(0),
181
+ duration_ms: o.number().nonnegative().default(0),
182
182
  /** Media delivery path this client is actually using. Reported HERE and not only at
183
183
  * join because the join-time value is provisional — /api/flags lands after the socket
184
184
  * connects, so the arm is not final until FragmentManager first reads it. Optional so
185
185
  * older clients still validate. */
186
- delivery_arm: r.enum(["range", "fragment"]).optional(),
186
+ delivery_arm: o.enum(["range", "fragment"]).optional(),
187
187
  /** Page state, so a stall can be read against what the viewer could see.
188
188
  * Without it "he says he saw nothing" and "his player froze for 55s" could
189
189
  * not be reconciled (mistral-bluff 2026-10-20). All optional: older
190
190
  * clients omit them, and `net_*` exist only where the browser exposes
191
191
  * navigator.connection (Chromium). */
192
- page_visible: r.boolean().optional(),
193
- page_focused: r.boolean().optional(),
194
- muted: r.boolean().optional(),
195
- online: r.boolean().optional(),
196
- net_type: r.string().max(16).optional(),
197
- net_rtt_ms: r.number().nonnegative().optional(),
198
- net_downlink_mbps: r.number().nonnegative().optional(),
192
+ page_visible: o.boolean().optional(),
193
+ page_focused: o.boolean().optional(),
194
+ muted: o.boolean().optional(),
195
+ online: o.boolean().optional(),
196
+ net_type: o.string().max(16).optional(),
197
+ net_rtt_ms: o.number().nonnegative().optional(),
198
+ net_downlink_mbps: o.number().nonnegative().optional(),
199
199
  /** ms since this connection last received a time_pong — a half-open
200
200
  * socket shows here as a growing number while everything else looks fine. */
201
- pong_age_ms: r.number().int().nonnegative().optional(),
202
- reported_at: r.number().int().nonnegative()
203
- }), nr = tr.extend({
204
- client_id: r.string(),
205
- name: r.string(),
206
- sprite_id: r.string().nullable(),
201
+ pong_age_ms: o.number().int().nonnegative().optional(),
202
+ reported_at: o.number().int().nonnegative()
203
+ }), tr = er.extend({
204
+ client_id: o.string(),
205
+ name: o.string(),
206
+ sprite_id: o.string().nullable(),
207
207
  /** Set when this connected client's last report is older than the freshness
208
208
  * window: how old it is, ms. The card then shows the client as silent
209
209
  * rather than dropping it — a viewer whose reports cannot get through is the
210
210
  * one the leader most needs to see. */
211
- stale_ms: r.number().int().nonnegative().optional()
211
+ stale_ms: o.number().int().nonnegative().optional()
212
212
  });
213
- r.object({
214
- clients: r.array(nr),
215
- server_ts: r.number().int().nonnegative()
213
+ o.object({
214
+ clients: o.array(tr),
215
+ server_ts: o.number().int().nonnegative()
216
216
  });
217
- const rr = r.object({
218
- client_id: r.string(),
219
- sprite_id: r.string().nullable(),
220
- name: r.string(),
221
- buffered_ahead_ms: r.number().nonnegative(),
217
+ const nr = o.object({
218
+ client_id: o.string(),
219
+ sprite_id: o.string().nullable(),
220
+ name: o.string(),
221
+ buffered_ahead_ms: o.number().nonnegative(),
222
222
  // playhead + duration let the viewer buffer ring apply the same near-end
223
223
  // exemption the leader's health card uses: near end-of-stream there is
224
224
  // legitimately little buffer ahead, so a low buffered_ahead_ms there must NOT
225
225
  // render "critical" red. Default 0 so older clients still validate.
226
- playhead_ms: r.number().nonnegative().default(0),
227
- duration_ms: r.number().nonnegative().default(0),
226
+ playhead_ms: o.number().nonnegative().default(0),
227
+ duration_ms: o.number().nonnegative().default(0),
228
228
  /** The video element's readyState, forwarded so the viewer buffer ring can
229
229
  * apply the same "plenty buffered but the element cannot advance" rule the
230
230
  * leader's card uses (see components/bufferHealth.ts). -1 = unknown/older
231
231
  * client, which must never trip the rule. */
232
- video_ready_state: r.number().int().default(-1)
232
+ video_ready_state: o.number().int().default(-1)
233
233
  });
234
- r.object({
235
- clients: r.array(rr),
236
- server_ts: r.number().int().nonnegative()
234
+ o.object({
235
+ clients: o.array(nr),
236
+ server_ts: o.number().int().nonnegative()
237
237
  });
238
- r.object({
239
- media_id: r.string()
238
+ o.object({
239
+ media_id: o.string()
240
240
  });
241
- const Ze = r.enum(["super_upvote", "upvote", "mid", "downvote"]), or = r.object({
242
- mediaId: r.string(),
243
- displayName: r.string(),
241
+ const Ze = o.enum(["super_upvote", "upvote", "mid", "downvote"]), rr = o.object({
242
+ mediaId: o.string(),
243
+ displayName: o.string(),
244
244
  // Enrichment fields — present for flat-playlist ingest output, absent for
245
245
  // subfolder-layout playlist clips. All optional so old playlist.json stays valid.
246
- description: r.string().optional(),
247
- thumbnail: r.string().optional(),
246
+ description: o.string().optional(),
247
+ thumbnail: o.string().optional(),
248
248
  // media-relative path, e.g. output/fmp4/.../poster.jpg
249
- durationMs: r.number().optional(),
250
- uploadDate: r.string().optional()
249
+ durationMs: o.number().optional(),
250
+ uploadDate: o.string().optional()
251
251
  // YouTube upload date 'YYYY-MM-DD'; drives playlist order
252
- }), ir = r.enum(["basic", "vote"]), zt = r.object({
253
- id: r.string(),
254
- name: r.string(),
255
- type: ir.default("vote"),
256
- videos: r.array(or),
257
- cover: r.string().optional()
252
+ }), or = o.enum(["basic", "vote"]), Yt = o.object({
253
+ id: o.string(),
254
+ name: o.string(),
255
+ type: or.default("vote"),
256
+ videos: o.array(rr),
257
+ cover: o.string().optional()
258
258
  // media-relative path to the playlist cover image
259
259
  });
260
- r.object({ playlistId: r.string() });
261
- r.object({ index: r.number().int().min(0) });
262
- r.object({
263
- playlistId: r.string(),
264
- mediaId: r.string(),
260
+ o.object({ playlistId: o.string() });
261
+ o.object({ index: o.number().int().min(0) });
262
+ o.object({
263
+ playlistId: o.string(),
264
+ mediaId: o.string(),
265
265
  vote: Ze
266
266
  });
267
- r.object({ voterKey: r.string().min(1).max(128) });
268
- r.object({ playlistId: r.string(), mediaIds: r.array(r.string()) });
269
- r.object({
270
- playlist: zt.nullable(),
271
- activeIndex: r.number().int().nullable(),
272
- myVotes: r.record(r.string(), Ze)
267
+ o.object({ voterKey: o.string().min(1).max(128) });
268
+ o.object({ playlistId: o.string(), mediaIds: o.array(o.string()) });
269
+ o.object({
270
+ playlist: Yt.nullable(),
271
+ activeIndex: o.number().int().nullable(),
272
+ myVotes: o.record(o.string(), Ze)
273
273
  // mediaId -> VoteValue
274
274
  });
275
- const ar = r.object({
276
- clientId: r.string(),
277
- name: r.string(),
278
- votedCount: r.number().int().nonnegative(),
279
- totalVideos: r.number().int().nonnegative()
275
+ const ar = o.object({
276
+ clientId: o.string(),
277
+ name: o.string(),
278
+ votedCount: o.number().int().nonnegative(),
279
+ totalVideos: o.number().int().nonnegative()
280
280
  });
281
- r.object({
282
- progress: r.array(ar)
281
+ o.object({
282
+ progress: o.array(ar)
283
283
  });
284
- r.object({
285
- playlist: zt,
286
- votes: r.record(r.string(), r.record(r.string(), Ze)),
284
+ o.object({
285
+ playlist: Yt,
286
+ votes: o.record(o.string(), o.record(o.string(), Ze)),
287
287
  // votes[clientId][mediaId]
288
- names: r.record(r.string(), r.string()),
288
+ names: o.record(o.string(), o.string()),
289
289
  // clientId -> display name
290
290
  /** clientId -> sprite id, frozen at reveal, so a voter who has since LEFT
291
291
  * (and so is gone from the live roster) still renders. Optional: older
292
292
  * servers omit it and clients fall back to the roster. */
293
- sprites: r.record(r.string(), r.string()).optional(),
293
+ sprites: o.record(o.string(), o.string()).optional(),
294
294
  /** True when this re-sends results after a voter was removed. A client whose
295
295
  * reveal is closed ignores it, rather than having the popup reappear. */
296
- update: r.boolean().optional()
296
+ update: o.boolean().optional()
297
297
  });
298
- const be = {
298
+ const ye = {
299
299
  STATE: "playlist_state",
300
300
  VOTE_PROGRESS: "playlist_vote_progress",
301
301
  RESULTS: "playlist_results",
302
302
  /** Server -> the removed voter: forget the ballot you hold in localStorage. */
303
303
  VOTES_CLEARED: "playlist_votes_cleared"
304
- }, Xt = r.object({
305
- id: r.string(),
306
- displayName: r.string(),
307
- thumbnail: r.string().optional()
304
+ }, zt = o.object({
305
+ id: o.string(),
306
+ displayName: o.string(),
307
+ thumbnail: o.string().optional()
308
308
  });
309
- r.object({
310
- items: r.array(Xt)
309
+ o.object({
310
+ items: o.array(zt)
311
311
  });
312
- const Jt = r.partialRecord(xe, r.array(r.string()));
313
- r.object({ board: Jt });
314
- const sr = r.object({
315
- mediaId: r.string(),
312
+ const Xt = o.partialRecord(xe, o.array(o.string()));
313
+ o.object({ board: Xt });
314
+ const ir = o.object({
315
+ mediaId: o.string(),
316
316
  tier: xe,
317
317
  absoluteTier: xe,
318
318
  /** Tier level + within-row position. Integer part is the tier. */
319
- score: r.number(),
319
+ score: o.number(),
320
320
  /** The consensus mean that decided the tier. Never the displayed number. */
321
- placementScore: r.number(),
322
- subRankOffset: r.number(),
323
- votes: r.record(r.string(), xe)
321
+ placementScore: o.number(),
322
+ subRankOffset: o.number(),
323
+ votes: o.record(o.string(), xe)
324
324
  // opaque voterId -> the letter they gave
325
325
  });
326
- r.object({
327
- items: r.array(Xt),
328
- placed: r.array(sr),
329
- unrated: r.array(r.string()),
330
- spread: r.number(),
331
- nudged: r.boolean(),
332
- names: r.record(r.string(), r.string()),
333
- sprites: r.record(r.string(), r.string()),
334
- voterCount: r.number().int().nonnegative(),
335
- myBoard: Jt
326
+ o.object({
327
+ items: o.array(zt),
328
+ placed: o.array(ir),
329
+ unrated: o.array(o.string()),
330
+ spread: o.number(),
331
+ nudged: o.boolean(),
332
+ names: o.record(o.string(), o.string()),
333
+ sprites: o.record(o.string(), o.string()),
334
+ voterCount: o.number().int().nonnegative(),
335
+ myBoard: Xt
336
336
  });
337
- const lr = {
337
+ const sr = {
338
338
  /** Broadcast to EVERY connected socket when anyone saves. Carries no board —
339
339
  * it is a "re-fetch" ping, because the shared result is identical for all
340
340
  * viewers but `myBoard` is not, and one payload cannot serve both. */
341
341
  UPDATED: "tierlist_updated"
342
342
  };
343
- r.object({});
344
- r.object({ ready: r.boolean() });
345
- r.object({
346
- active: r.boolean(),
347
- ready: r.array(r.string())
343
+ o.object({});
344
+ o.object({ ready: o.boolean() });
345
+ o.object({
346
+ active: o.boolean(),
347
+ ready: o.array(o.string())
348
348
  // clientIds who have flagged ready
349
349
  });
350
- const cr = {
350
+ const lr = {
351
351
  STATE: "ready_check_state"
352
352
  // distinct from buffer-readiness 'ready_state'
353
- }, Qt = {
353
+ }, Jt = {
354
354
  ACTIVE: "game_active",
355
- // server -> room (room-wide active game id; null = none)
355
+ // server -> room (the open game id; null = none)
356
356
  SYNC: "game_sync"
357
+ // client -> server (which game is open? on mount/reconnect)
357
358
  };
358
- r.object({
359
- gameId: r.string().min(1).max(32).nullable()
360
- });
361
- r.object({
362
- count: r.number().int().min(0).max(9)
363
- });
364
- r.object({
365
- gameId: r.string().nullable(),
366
- // Present only while a game is active (ws/game.ts builds this from
367
- // room.gameActivePreview + the live tallies). Optional so the cleared
368
- // payload — a bare { gameId: null } — still validates.
369
- hostClientId: r.string().nullable().optional(),
370
- seed: r.number().optional(),
371
- players: r.array(r.unknown()).optional(),
372
- /** clientId -> wins this session. */
373
- sessionWins: r.record(r.string(), r.number()).optional(),
374
- botCount: r.number().optional()
375
- });
376
- r.object({
377
- gameId: r.string().min(1).max(32)
378
- });
379
- const dr = r.object({
380
- clientId: r.string(),
381
- playerId: r.number().int().min(0),
382
- name: r.string(),
383
- // Selected character sprite id (sage/herald/cleric/knight/mage/brawler/
384
- // wanderer/rogue). Optional — clients fall back to a colored square when
385
- // missing. Drives both avatar rendering AND per-character bomb tinting in
386
- // the Bevy game.
387
- sprite: r.string().optional()
359
+ o.object({
360
+ gameId: o.string().min(1).max(32).nullable()
388
361
  });
389
- r.object({
390
- gameId: r.string(),
391
- hostClientId: r.string().nullable(),
392
- seed: r.number().int(),
393
- players: r.array(dr)
362
+ o.object({
363
+ gameId: o.string().nullable()
394
364
  });
395
- r.object({ d: r.unknown() });
396
- r.object({ d: r.unknown() });
397
- r.object({ fromClientId: r.string(), d: r.unknown() });
398
- const ur = r.object({
399
- playerId: r.number().int().min(0),
400
- clientId: r.string().nullable(),
401
- name: r.string(),
402
- sprite: r.string().nullable(),
403
- survived: r.boolean(),
404
- roundScore: r.number().int().min(0).optional(),
405
- sessionScore: r.number().int().min(0).optional(),
406
- /** End-of-round upgrade snapshot — bombMax = max concurrent bombs the
407
- * player could place; blastLen = blast radius in tiles, one direction.
408
- * Optional so older client builds keep validating. */
409
- bombMax: r.number().int().min(0).optional(),
410
- blastLen: r.number().int().min(0).optional(),
411
- // Per-pid match counters — all optional so older client builds keep
412
- // validating against the schema. Server treats missing fields as 0.
413
- kills: r.number().int().min(0),
414
- selfKills: r.number().int().min(0).optional(),
415
- firstBloods: r.number().int().min(0).optional(),
416
- soulPickups: r.number().int().min(0).optional(),
417
- powerupsCollected: r.number().int().min(0).optional(),
418
- bombsPlaced: r.number().int().min(0).optional(),
419
- blocksDestroyed: r.number().int().min(0).optional(),
420
- kicks: r.number().int().min(0).optional(),
421
- killsByKick: r.number().int().min(0).optional(),
422
- killsByChain: r.number().int().min(0).optional(),
423
- trapkills: r.number().int().min(0).optional(),
424
- // Per-cluster multi-kill counters (operator spec: separate columns for
425
- // double through deca-kill, where deca is the "10+" catch-all).
426
- doubleKills: r.number().int().min(0).optional(),
427
- tripleKills: r.number().int().min(0).optional(),
428
- quadKills: r.number().int().min(0).optional(),
429
- pentaKills: r.number().int().min(0).optional(),
430
- hexaKills: r.number().int().min(0).optional(),
431
- heptaKills: r.number().int().min(0).optional(),
432
- octaKills: r.number().int().min(0).optional(),
433
- nonaKills: r.number().int().min(0).optional(),
434
- decaKills: r.number().int().min(0).optional()
435
- });
436
- r.object({
437
- winnerPlayerId: r.number().int().min(0).nullable(),
438
- draw: r.boolean(),
439
- players: r.array(ur),
440
- // Optional session metadata + round-level extras (Phase C).
441
- sessionOver: r.boolean().optional(),
442
- roundNo: r.number().int().min(0).optional(),
443
- sessionScores: r.record(r.string(), r.number().int().min(0)).optional(),
444
- maxMultiKill: r.number().int().min(0).optional(),
445
- maxChainKill: r.number().int().min(0).optional()
446
- });
447
- const mr = [
365
+ const cr = [
448
366
  {
449
367
  id: "fantasy",
450
368
  characters: [
@@ -488,37 +406,37 @@ const mr = [
488
406
  { id: "mentor", color: "#e1e0dc" }
489
407
  ]
490
408
  }
491
- ], et = mr.flatMap((e) => e.characters), Me = et.map((e) => e.id), fr = Object.fromEntries(et.map((e) => [e.id, e.color])), pr = Object.fromEntries(et.map((e) => [e.id, "rev" in e ? e.rev : 1]));
492
- function hr(e) {
493
- const t = pr[e];
409
+ ], et = cr.flatMap((e) => e.characters), Me = et.map((e) => e.id), dr = Object.fromEntries(et.map((e) => [e.id, e.color])), ur = Object.fromEntries(et.map((e) => [e.id, "rev" in e ? e.rev : 1]));
410
+ function mr(e) {
411
+ const t = ur[e];
494
412
  return `/media/sprites/square_${e}.png${t > 1 ? `?v=${t}` : ""}`;
495
413
  }
496
414
  function tt(e) {
497
415
  return !!e && Me.includes(e);
498
416
  }
499
- const gr = 5e3, Zt = { mode: "off", percent: 0 }, br = ["off", "on", "ab"];
500
- function yr(e) {
501
- return typeof e == "string" && br.includes(e);
417
+ const fr = 5e3, Qt = { mode: "off", percent: 0 }, pr = ["off", "on", "ab"];
418
+ function hr(e) {
419
+ return typeof e == "string" && pr.includes(e);
502
420
  }
503
- function vr(e) {
504
- const t = e && typeof e == "object" ? e : {}, n = yr(t.mode) ? t.mode : Zt.mode, o = Number(t.percent), i = Number.isFinite(o) ? Math.min(100, Math.max(0, Math.round(o))) : 0;
505
- return { mode: n, percent: i };
421
+ function gr(e) {
422
+ const t = e && typeof e == "object" ? e : {}, n = hr(t.mode) ? t.mode : Qt.mode, r = Number(t.percent), a = Number.isFinite(r) ? Math.min(100, Math.max(0, Math.round(r))) : 0;
423
+ return { mode: n, percent: a };
506
424
  }
507
- function Sr(e) {
425
+ function yr(e) {
508
426
  let t = 2166136261;
509
427
  for (let n = 0; n < e.length; n++)
510
428
  t ^= e.charCodeAt(n), t = Math.imul(t, 16777619) >>> 0;
511
429
  return t >>> 0;
512
430
  }
513
- function _r(e, t, n) {
431
+ function br(e, t, n) {
514
432
  if (n === !0)
515
433
  return "fragment";
516
434
  if (n === !1)
517
435
  return "range";
518
- const o = vr(e);
519
- return o.mode === "on" ? "fragment" : o.mode === "off" || o.percent <= 0 ? "range" : o.percent >= 100 || t && Sr(t) % 100 < o.percent ? "fragment" : "range";
436
+ const r = gr(e);
437
+ return r.mode === "on" ? "fragment" : r.mode === "off" || r.percent <= 0 ? "range" : r.percent >= 100 || t && yr(t) % 100 < r.percent ? "fragment" : "range";
520
438
  }
521
- const en = r.enum(["url", "magnet", "upload"]), wr = r.enum([
439
+ const Zt = o.enum(["url", "magnet", "upload"]), vr = o.enum([
522
440
  "pending",
523
441
  "approved",
524
442
  "fetching",
@@ -526,7 +444,7 @@ const en = r.enum(["url", "magnet", "upload"]), wr = r.enum([
526
444
  "ready",
527
445
  "rejected",
528
446
  "failed"
529
- ]), bt = {
447
+ ]), yt = {
530
448
  pending: ["approved", "rejected"],
531
449
  approved: ["fetching", "rejected", "failed"],
532
450
  fetching: ["ingesting", "failed"],
@@ -535,15 +453,15 @@ const en = r.enum(["url", "magnet", "upload"]), wr = r.enum([
535
453
  rejected: [],
536
454
  failed: ["approved"]
537
455
  };
538
- Object.keys(bt).filter((e) => bt[e].length === 0);
539
- const xr = r.object({
540
- id: r.string().min(1),
456
+ Object.keys(yt).filter((e) => yt[e].length === 0);
457
+ const Sr = o.object({
458
+ id: o.string().min(1),
541
459
  /** Stable userId from whoami. Never the raw `X-User-Key`. */
542
- ownerUserId: r.string().min(1),
543
- kind: en,
460
+ ownerUserId: o.string().min(1),
461
+ kind: Zt,
544
462
  /** The magnet URI, the https URL, or the filetransfer binding id. */
545
- source: r.string().min(1),
546
- title: r.string().optional(),
463
+ source: o.string().min(1),
464
+ title: o.string().optional(),
547
465
  /**
548
466
  * The anime series folder (PascalCase, e.g. `SparksOfTomorrow`) a `magnet`
549
467
  * submission belongs to — wave 4 (2026-10-01: "magnets are in scope, and
@@ -554,115 +472,112 @@ const xr = r.object({
554
472
  * disagreed with the scraper's own folder-name assumption would silently
555
473
  * misroute the copy.
556
474
  */
557
- series: r.string().optional(),
558
- state: wr,
559
- createdAt: r.number().int().nonnegative(),
560
- updatedAt: r.number().int().nonnegative(),
475
+ series: o.string().optional(),
476
+ state: vr,
477
+ createdAt: o.number().int().nonnegative(),
478
+ updatedAt: o.number().int().nonnegative(),
561
479
  /** Why it failed, or why an operator rejected it. */
562
- error: r.string().optional(),
480
+ error: o.string().optional(),
563
481
  /** Size once known. 0 means "known to be empty"; absent means "not yet known" —
564
482
  * the same distinction `chatImages` draws for image dimensions. */
565
- bytes: r.number().int().nonnegative().optional()
566
- }), Ir = 4096, tn = 300, Cr = 100;
567
- r.object({
568
- kind: en,
569
- source: r.string().min(1).max(Ir),
570
- title: r.string().min(1).max(tn).optional(),
483
+ bytes: o.number().int().nonnegative().optional()
484
+ }), _r = 4096, en = 300, wr = 100;
485
+ o.object({
486
+ kind: Zt,
487
+ source: o.string().min(1).max(_r),
488
+ title: o.string().min(1).max(en).optional(),
571
489
  /** Required for `kind: 'magnet'` by `checkSource`; ignored for `url`/`upload`. */
572
- series: r.string().min(1).max(Cr).optional()
490
+ series: o.string().min(1).max(wr).optional()
573
491
  });
574
- r.object({
575
- reason: r.string().min(1).max(tn).optional()
492
+ o.object({
493
+ reason: o.string().min(1).max(en).optional()
576
494
  });
577
- r.object({
578
- submissions: r.array(xr)
495
+ o.object({
496
+ submissions: o.array(Sr)
579
497
  });
580
- r.object({
581
- error: r.literal("submissions/quota_exceeded"),
498
+ o.object({
499
+ error: o.literal("submissions/quota_exceeded"),
582
500
  /** The caller's measured bytes in non-terminal submissions, right now. */
583
- pendingBytes: r.number().int().nonnegative(),
501
+ pendingBytes: o.number().int().nonnegative(),
584
502
  /** The cap that was applied, from the server's config. */
585
- capBytes: r.number().int().nonnegative()
503
+ capBytes: o.number().int().nonnegative()
586
504
  });
587
- const Tr = /^[a-z0-9][a-z0-9-]{0,31}$/, yt = "https://game-catalog.invalid";
588
- function kr(e) {
505
+ const xr = /^[a-z0-9][a-z0-9-]{0,31}$/, bt = "https://game-catalog.invalid";
506
+ function Ir(e) {
589
507
  if (!e.startsWith("/") || e.startsWith("//") || /[\\\s]/.test(e) || [...e].some((t) => t.charCodeAt(0) < 32 || t.charCodeAt(0) === 127))
590
508
  return !1;
591
509
  try {
592
- return new URL(e, yt).origin === yt;
510
+ return new URL(e, bt).origin === bt;
593
511
  } catch {
594
512
  return !1;
595
513
  }
596
514
  }
597
- const nn = r.string().min(2).max(512).refine(kr, {
515
+ const tn = o.string().min(2).max(512).refine(Ir, {
598
516
  message: "must be a root-relative path on the page origin (e.g. /cardtable/embed/x.js)"
599
- }), vt = {
600
- id: r.string().regex(Tr),
601
- name: r.string().min(1).max(64),
602
- cover: nn.optional()
603
- }, Ar = r.discriminatedUnion("kind", [
604
- r.object({ ...vt, kind: r.literal("iframe") }).strict(),
605
- r.object({ ...vt, kind: r.literal("module"), url: nn }).strict()
606
- ]);
607
- r.array(Ar).max(32).refine((e) => new Set(e.map((t) => t.id)).size === e.length, { message: "game ids must be unique" });
608
- const nt = r.enum(["anilist", "tmdb"]), Er = r.object({
517
+ }), Cr = {
518
+ id: o.string().regex(xr),
519
+ name: o.string().min(1).max(64),
520
+ cover: tn.optional()
521
+ }, Tr = o.object({ ...Cr, kind: o.literal("module"), url: tn }).strict();
522
+ o.array(Tr).max(32).refine((e) => new Set(e.map((t) => t.id)).size === e.length, { message: "game ids must be unique" });
523
+ const nt = o.enum(["anilist", "tmdb"]), Ar = o.object({
609
524
  source: nt,
610
525
  /** The provider's own id, as a string (AniList and TMDB both use integers). */
611
- id: r.string(),
612
- title: r.string(),
613
- year: r.number().int().nullable(),
526
+ id: o.string(),
527
+ title: o.string(),
528
+ year: o.number().int().nullable(),
614
529
  /** AniList `format` (TV, ONA, MOVIE…) or `TV` for TMDB. */
615
- format: r.string().nullable(),
616
- episodes: r.number().int().nullable(),
530
+ format: o.string().nullable(),
531
+ episodes: o.number().int().nullable(),
617
532
  /** Same-origin proxied poster (`/api/search/thumb?u=…`), or null. */
618
- poster: r.string().nullable(),
533
+ poster: o.string().nullable(),
619
534
  /** The folder this show would land in — `SousouNoFrieren`. */
620
- series: r.string(),
535
+ series: o.string(),
621
536
  /** On the scraper's watch list already (by series). */
622
- onWatchlist: r.boolean(),
537
+ onWatchlist: o.boolean(),
623
538
  /**
624
539
  * Not addable: a movie, or a title with no usable Latin-script name. The
625
540
  * scraper matches releases by `SxxExx`, so a film can never arrive through it.
626
541
  */
627
- addable: r.boolean()
542
+ addable: o.boolean()
628
543
  });
629
- r.object({
630
- results: r.array(Er),
544
+ o.object({
545
+ results: o.array(Ar),
631
546
  /** Providers that answered. TMDB is absent when no token is configured. */
632
- sources: r.array(nt)
547
+ sources: o.array(nt)
633
548
  });
634
- const Pr = r.object({
635
- id: r.string(),
636
- url: r.string(),
637
- title: r.string(),
638
- channel: r.string().nullable(),
639
- durationS: r.number().nullable(),
640
- thumb: r.string().nullable()
549
+ const kr = o.object({
550
+ id: o.string(),
551
+ url: o.string(),
552
+ title: o.string(),
553
+ channel: o.string().nullable(),
554
+ durationS: o.number().nullable(),
555
+ thumb: o.string().nullable()
641
556
  });
642
- r.object({ results: r.array(Pr) });
643
- r.object({
557
+ o.object({ results: o.array(kr) });
558
+ o.object({
644
559
  source: nt,
645
- id: r.string().regex(/^\d{1,12}$/)
560
+ id: o.string().regex(/^\d{1,12}$/)
646
561
  });
647
- r.object({ series: r.string(), title: r.string() });
648
- let ye = null, rn = Gt;
649
- function Nr(e) {
650
- e.cdnBase && (rn = e.cdnBase);
562
+ o.object({ series: o.string(), title: o.string() });
563
+ let be = null, nn = Bt;
564
+ function Er(e) {
565
+ e.cdnBase && (nn = e.cdnBase);
651
566
  }
652
- function on() {
653
- return rn.replace(/\/+$/, "");
567
+ function rn() {
568
+ return nn.replace(/\/+$/, "");
654
569
  }
655
570
  function Le() {
656
- const e = on();
657
- return (!ye || ye.base !== e) && (ye = { base: e, client: On({ cdnBase: e }) }), ye.client;
571
+ const e = rn();
572
+ return (!be || be.base !== e) && (be = { base: e, client: Dn({ cdnBase: e }) }), be.client;
658
573
  }
659
574
  function Pe(e) {
660
- return !Je(e) || !on() ? null : Le().urlFor(e);
575
+ return !Je(e) || !rn() ? null : Le().urlFor(e);
661
576
  }
662
- function Rr(e) {
577
+ function Pr(e) {
663
578
  return e.kind === "file";
664
579
  }
665
- class an extends Error {
580
+ class on extends Error {
666
581
  constructor(t) {
667
582
  super(t), this.name = "ChatImageUploadError";
668
583
  }
@@ -687,82 +602,82 @@ function Ie(e) {
687
602
  return "Image upload failed";
688
603
  }
689
604
  }
690
- function Dr(e) {
691
- return e instanceof qe ? Ie(e.reason) : e instanceof an ? e.message : "Image upload failed";
605
+ function Nr(e) {
606
+ return e instanceof Ke ? Ie(e.reason) : e instanceof on ? e.message : "Image upload failed";
692
607
  }
693
- function Or(e) {
608
+ function Rr(e) {
694
609
  const t = e.type.toLowerCase().split(";")[0].trim();
695
- return t && Mn(t) !== "image" ? Ie("unsupported-type") : e.size > Ln.image ? Ie("too-large") : e.size === 0 ? Ie("invalid") : null;
610
+ return t && On(t) !== "image" ? Ie("unsupported-type") : e.size > Mn.image ? Ie("too-large") : e.size === 0 ? Ie("invalid") : null;
696
611
  }
697
- function Mr(e) {
698
- return Un(e);
612
+ function Dr(e) {
613
+ return jn(e);
699
614
  }
700
- function Lr(e) {
701
- return Fn(e);
615
+ function Or(e) {
616
+ return Un(e);
702
617
  }
703
- async function jr(e) {
704
- const t = await jn(e);
618
+ async function Mr(e) {
619
+ const t = await Ln(e);
705
620
  return { w: t?.width ?? 0, h: t?.height ?? 0 };
706
621
  }
707
- async function Ur(e, t = {}) {
622
+ async function Lr(e, t = {}) {
708
623
  const n = await Le().upload(e, { signal: t.signal });
709
624
  if (!Je(n.key))
710
- throw new an("Image upload returned an unusable key");
625
+ throw new on("Image upload returned an unusable key");
711
626
  return { key: n.key, deduplicated: n.deduplicated === !0 };
712
627
  }
713
- async function Fr(e, t = {}) {
628
+ async function jr(e, t = {}) {
714
629
  const n = [];
715
- for (const o of e) {
716
- if (o.kind === "remote") {
717
- n.push({ key: o.key, w: o.w, h: o.h, ...o.title ? { title: o.title } : {} });
630
+ for (const r of e) {
631
+ if (r.kind === "remote") {
632
+ n.push({ key: r.key, w: r.w, h: r.h, ...r.title ? { title: r.title } : {} });
718
633
  continue;
719
634
  }
720
- const { key: i } = await Ur(o.file, t);
721
- n.push({ key: i, w: o.w, h: o.h });
635
+ const { key: a } = await Lr(r.file, t);
636
+ n.push({ key: a, w: r.w, h: r.h });
722
637
  }
723
638
  return n;
724
639
  }
725
- function Hr(e) {
640
+ function Ur(e) {
726
641
  return {
727
642
  error: e instanceof Error ? e.message : String(e),
728
643
  name: e instanceof Error ? e.name : typeof e,
729
- reason: e instanceof qe ? e.reason : void 0,
730
- status: e instanceof qe ? e.status : void 0
644
+ reason: e instanceof Ke ? e.reason : void 0,
645
+ status: e instanceof Ke ? e.status : void 0
731
646
  };
732
647
  }
733
- const Ve = 240, X = 8, $r = 28, sn = 240;
734
- function Br(e, t, n) {
735
- let o = t.left - Ve - X;
736
- o < X && (o = t.right + X), o = Math.min(o, n.width - Ve - X), o = Math.max(X, o);
737
- const i = sn + $r;
738
- let a = e.top + e.height / 2 - i / 2;
739
- return a = Math.min(a, n.height - i - X), a = Math.max(X, a), { left: o, top: a };
740
- }
741
- const ln = "/dataplatform/api/memes", Gr = 120;
742
- function Kr({ onClose: e, onPick: t, onUnavailable: n }) {
743
- const [o, i] = R(""), a = z(null), s = z(null), l = Le(), { items: p, loading: h, error: f, hasMore: L, loadMore: O } = Yn(
648
+ const We = 240, X = 8, Fr = 28, an = 240;
649
+ function Hr(e, t, n) {
650
+ let r = t.left - We - X;
651
+ r < X && (r = t.right + X), r = Math.min(r, n.width - We - X), r = Math.max(X, r);
652
+ const a = an + Fr;
653
+ let i = e.top + e.height / 2 - a / 2;
654
+ return i = Math.min(i, n.height - a - X), i = Math.max(X, i), { left: r, top: i };
655
+ }
656
+ const sn = "/dataplatform/api/memes", $r = 120;
657
+ function Br({ onClose: e, onPick: t, onUnavailable: n }) {
658
+ const [r, a] = R(""), i = z(null), s = z(null), l = Le(), { items: p, loading: h, error: f, hasMore: L, loadMore: O } = Wn(
744
659
  l,
745
- ln,
746
- o.trim()
660
+ sn,
661
+ r.trim()
747
662
  ), M = f?.reason ?? null, C = Q(() => {
748
663
  const x = /* @__PURE__ */ new Set();
749
664
  return p.filter((P) => x.has(P.key) ? !1 : (x.add(P.key), !0));
750
- }, [p]), [m, v] = R(null), y = z(null), I = E(() => {
751
- y.current !== null && (window.clearTimeout(y.current), y.current = null);
665
+ }, [p]), [m, v] = R(null), b = z(null), I = E(() => {
666
+ b.current !== null && (window.clearTimeout(b.current), b.current = null);
752
667
  }, []), g = E(() => {
753
668
  I(), v(null);
754
- }, [I]), A = typeof window < "u" && typeof window.matchMedia == "function" && window.matchMedia("(hover: hover)").matches, N = E(
669
+ }, [I]), k = typeof window < "u" && typeof window.matchMedia == "function" && window.matchMedia("(hover: hover)").matches, N = E(
755
670
  (x, P, T = !1) => {
756
- const pe = a.current;
671
+ const pe = i.current;
757
672
  if (!pe) return;
758
673
  const he = () => v({
759
674
  item: x,
760
- ...Br(P.getBoundingClientRect(), pe.getBoundingClientRect(), {
675
+ ...Hr(P.getBoundingClientRect(), pe.getBoundingClientRect(), {
761
676
  width: window.innerWidth,
762
677
  height: window.innerHeight
763
678
  })
764
679
  });
765
- I(), T ? he() : y.current = window.setTimeout(he, Gr);
680
+ I(), T ? he() : b.current = window.setTimeout(he, $r);
766
681
  },
767
682
  [I]
768
683
  );
@@ -774,7 +689,7 @@ function Kr({ onClose: e, onPick: t, onUnavailable: n }) {
774
689
  const x = (T) => {
775
690
  T.key === "Escape" && (T.stopPropagation(), e());
776
691
  }, P = (T) => {
777
- a.current && !a.current.contains(T.target) && e();
692
+ i.current && !i.current.contains(T.target) && e();
778
693
  };
779
694
  return document.addEventListener("keydown", x), document.addEventListener("mousedown", P), () => {
780
695
  document.removeEventListener("keydown", x), document.removeEventListener("mousedown", P);
@@ -786,7 +701,7 @@ function Kr({ onClose: e, onPick: t, onUnavailable: n }) {
786
701
  return /* @__PURE__ */ _(
787
702
  "div",
788
703
  {
789
- ref: a,
704
+ ref: i,
790
705
  role: "dialog",
791
706
  "aria-label": "Meme library",
792
707
  "data-testid": "meme-picker",
@@ -797,8 +712,8 @@ function Kr({ onClose: e, onPick: t, onUnavailable: n }) {
797
712
  {
798
713
  ref: s,
799
714
  type: "text",
800
- value: o,
801
- onChange: (x) => i(x.target.value),
715
+ value: r,
716
+ onChange: (x) => a(x.target.value),
802
717
  placeholder: "Search memes...",
803
718
  "aria-label": "Search memes",
804
719
  "data-testid": "meme-search",
@@ -821,7 +736,7 @@ function Kr({ onClose: e, onPick: t, onUnavailable: n }) {
821
736
  children: M === "unauthenticated" ? "Sign in to browse memes" : M === "forbidden" ? "Your account can't browse the meme library" : "Meme library is unavailable"
822
737
  }
823
738
  ),
824
- F && /* @__PURE__ */ c("p", { className: "p-4 text-center text-sm text-text-secondary", children: o.trim() ? `No memes match "${o.trim()}"` : "The meme library is empty" }),
739
+ F && /* @__PURE__ */ c("p", { className: "p-4 text-center text-sm text-text-secondary", children: r.trim() ? `No memes match "${r.trim()}"` : "The meme library is empty" }),
825
740
  C.length > 0 && /* @__PURE__ */ c("div", { className: "grid grid-cols-3 gap-1.5 sm:grid-cols-4", children: C.map((x) => {
826
741
  const P = Pe(x.key);
827
742
  return P ? /* @__PURE__ */ c(
@@ -832,7 +747,7 @@ function Kr({ onClose: e, onPick: t, onUnavailable: n }) {
832
747
  title: x.title,
833
748
  "data-testid": "meme-result",
834
749
  onMouseEnter: (T) => {
835
- A && N(x, T.currentTarget);
750
+ k && N(x, T.currentTarget);
836
751
  },
837
752
  onMouseLeave: g,
838
753
  onFocus: (T) => N(x, T.currentTarget, !0),
@@ -874,7 +789,7 @@ function Kr({ onClose: e, onPick: t, onUnavailable: n }) {
874
789
  style: {
875
790
  left: m.left,
876
791
  top: m.top,
877
- width: Ve,
792
+ width: We,
878
793
  /* The placement maths reserves exactly PREVIEW_PX of width.
879
794
  Without border-box the padding and border sit OUTSIDE that
880
795
  number and the box laps over the panel it is meant to sit
@@ -891,7 +806,7 @@ function Kr({ onClose: e, onPick: t, onUnavailable: n }) {
891
806
  src: Pe(m.item.key) ?? void 0,
892
807
  alt: "",
893
808
  className: "block w-full rounded bg-bg object-contain",
894
- style: { height: "auto", maxHeight: sn }
809
+ style: { height: "auto", maxHeight: an }
895
810
  }
896
811
  ),
897
812
  m.item.title && /* One line. A long title must not change the box height, because
@@ -904,34 +819,34 @@ function Kr({ onClose: e, onPick: t, onUnavailable: n }) {
904
819
  }
905
820
  );
906
821
  }
907
- function Wr({ open: e, ...t }) {
908
- return e ? /* @__PURE__ */ c(Kr, { ...t }) : null;
822
+ function Gr({ open: e, ...t }) {
823
+ return e ? /* @__PURE__ */ c(Br, { ...t }) : null;
909
824
  }
910
825
  const rt = {
911
826
  serverOrigin: `http://localhost:${Qe}`,
912
827
  defaultRoomKey: "dev-room",
913
- cdnBase: Gt
828
+ cdnBase: Bt
914
829
  };
915
830
  let Ce = { ...rt };
916
831
  function qr(e) {
917
832
  const t = Object.fromEntries(
918
- Object.entries(e).filter(([n, o]) => o !== void 0)
833
+ Object.entries(e).filter(([n, r]) => r !== void 0)
919
834
  );
920
- Ce = { ...Ce, ...t }, Nr({ cdnBase: Ce.cdnBase });
835
+ Ce = { ...Ce, ...t }, Er({ cdnBase: Ce.cdnBase });
921
836
  }
922
837
  function me() {
923
838
  return Ce;
924
839
  }
925
- const Vr = $t(rt);
926
- function Yr(e) {
840
+ const Vr = Ht(rt);
841
+ function Kr(e) {
927
842
  return e.serverOrigin?.replace(/\/$/, "") || "";
928
843
  }
929
- function cn() {
930
- return Yr(me());
844
+ function ln() {
845
+ return Kr(me());
931
846
  }
932
- const dn = $t(null);
933
- function zr() {
934
- return En(dn);
847
+ const cn = Ht(null);
848
+ function Wr() {
849
+ return kn(cn);
935
850
  }
936
851
  const te = {
937
852
  ANON_KEY: "watchparty_preferences",
@@ -961,14 +876,14 @@ function ot(e, t) {
961
876
  return !1;
962
877
  }
963
878
  }
964
- function Xr() {
879
+ function Yr() {
965
880
  try {
966
881
  const e = je();
967
882
  if (!e) return [];
968
883
  const t = [];
969
884
  for (let n = 0; n < e.length; n++) {
970
- const o = e.key(n);
971
- o !== null && t.push(o);
885
+ const r = e.key(n);
886
+ r !== null && t.push(r);
972
887
  }
973
888
  return t;
974
889
  } catch {
@@ -981,45 +896,45 @@ function Ne(e) {
981
896
  } catch {
982
897
  }
983
898
  }
984
- function Jr(e) {
899
+ function zr(e) {
985
900
  const t = B(e);
986
901
  return t === null ? null : t === "true" ? !0 : t === "false" ? !1 : null;
987
902
  }
988
- const un = /* @__PURE__ */ new Map();
989
- let mn = !1;
903
+ const dn = /* @__PURE__ */ new Map();
904
+ let un = !1;
990
905
  function Ue(e, t) {
991
- un.set(e, t), mn && fn(e, t);
906
+ dn.set(e, t), un && mn(e, t);
992
907
  }
993
- function Qr() {
994
- mn = !0;
995
- for (const [e, t] of un) fn(e, t);
908
+ function Xr() {
909
+ un = !0;
910
+ for (const [e, t] of dn) mn(e, t);
996
911
  }
997
- function fn(e, t) {
912
+ function mn(e, t) {
998
913
  typeof window > "u" || (window[e] = t);
999
914
  }
1000
- const ae = [], Zr = 500;
915
+ const ie = [], Jr = 500;
1001
916
  let Te = [], Ye = null;
1002
- const eo = 1e3, to = 200;
917
+ const Qr = 1e3, Zr = 200;
1003
918
  let ze = null;
1004
- function pn(e) {
919
+ function fn(e) {
1005
920
  ze = e;
1006
921
  }
1007
- function hn() {
922
+ function pn() {
1008
923
  return B(te.REPORT_LOGS_FLAG) === "true";
1009
924
  }
1010
- function no() {
925
+ function eo() {
1011
926
  if (typeof window > "u") return !1;
1012
927
  if (window.__WP_DEBUG__ || new URLSearchParams(window.location.search).get("debug") === "true") return !0;
1013
928
  const t = B(te.DEBUG_FLAG);
1014
929
  return t !== null && t !== "false";
1015
930
  }
1016
- function ro() {
931
+ function to() {
1017
932
  const e = B(te.DEBUG_FLAG);
1018
933
  if (!e || e === "true") return null;
1019
934
  const t = e.split(",").map((n) => n.trim().toLowerCase()).filter(Boolean);
1020
935
  return t.length > 0 ? new Set(t) : null;
1021
936
  }
1022
- function oo() {
937
+ function no() {
1023
938
  return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
1024
939
  hour12: !1,
1025
940
  hour: "2-digit",
@@ -1028,8 +943,8 @@ function oo() {
1028
943
  fractionalSecondDigits: 3
1029
944
  });
1030
945
  }
1031
- function io(e) {
1032
- ae.push(e), ae.length > Zr && ae.shift();
946
+ function ro(e) {
947
+ ie.push(e), ie.length > Jr && ie.shift();
1033
948
  }
1034
949
  const Fe = {
1035
950
  debug: "color: #64748b; font-weight: normal;",
@@ -1038,67 +953,67 @@ const Fe = {
1038
953
  category: "color: #3b82f6; font-weight: bold;",
1039
954
  time: "color: #6b7280; font-weight: normal;"
1040
955
  };
1041
- function ao(e) {
956
+ function oo(e) {
1042
957
  try {
1043
958
  return JSON.stringify(e);
1044
959
  } catch {
1045
960
  return "[unserializable]";
1046
961
  }
1047
962
  }
1048
- function it(e, t, n, o, i, a, s) {
963
+ function at(e, t, n, r, a, i, s) {
1049
964
  const l = {
1050
965
  level: e,
1051
- category: i,
1052
- message: a,
966
+ category: a,
967
+ message: i,
1053
968
  data: s,
1054
969
  timestamp: Date.now()
1055
970
  };
1056
- if (io(l), (n || hn()) && St(l), !o) {
1057
- if (!no()) return;
1058
- const f = ro();
1059
- if (f && !f.has(i.toLowerCase())) return;
971
+ if (ro(l), (n || pn()) && vt(l), !r) {
972
+ if (!eo()) return;
973
+ const f = to();
974
+ if (f && !f.has(a.toLowerCase())) return;
1060
975
  }
1061
- const p = oo(), h = s !== void 0 ? " " + ao(s) : "";
976
+ const p = no(), h = s !== void 0 ? " " + oo(s) : "";
1062
977
  t(
1063
- `%c[${p}]%c [${i}]%c ${a}${h}`,
978
+ `%c[${p}]%c [${a}]%c ${i}${h}`,
1064
979
  Fe.time,
1065
980
  Fe.category,
1066
981
  Fe[e]
1067
982
  );
1068
983
  }
1069
984
  function d(e, t, n) {
1070
- it("debug", console.log, !1, !1, e, t, n);
985
+ at("debug", console.log, !1, !1, e, t, n);
1071
986
  }
1072
- function k(e, t, n) {
1073
- it("warn", console.warn, !0, !1, e, t, n);
987
+ function A(e, t, n) {
988
+ at("warn", console.warn, !0, !1, e, t, n);
1074
989
  }
1075
- function ke(e, t, n) {
1076
- it("error", console.error, !0, !0, e, t, n);
990
+ function Ae(e, t, n) {
991
+ at("error", console.error, !0, !0, e, t, n);
1077
992
  }
1078
- function so() {
1079
- return [...ae];
993
+ function ao() {
994
+ return [...ie];
1080
995
  }
1081
- function lo() {
1082
- ae.length = 0;
996
+ function io() {
997
+ ie.length = 0;
1083
998
  }
1084
- function co(e) {
999
+ function so(e) {
1085
1000
  const t = e && e.length > 0 ? e.join(",") : "true";
1086
1001
  ot(te.DEBUG_FLAG, t), console.log("[wp] Debug mode enabled");
1087
1002
  }
1088
- function uo() {
1003
+ function lo() {
1089
1004
  Ne(te.DEBUG_FLAG), console.log("[wp] Debug mode disabled");
1090
1005
  }
1091
- const mo = 1024, fo = 5e4;
1092
- function po(e) {
1006
+ const co = 1024, uo = 5e4;
1007
+ function mo(e) {
1093
1008
  if (e == null) return e;
1094
1009
  try {
1095
1010
  const t = JSON.stringify(e);
1096
- if (t.length <= mo) return e;
1011
+ if (t.length <= co) return e;
1097
1012
  if (typeof e == "object" && !Array.isArray(e)) {
1098
1013
  const n = {};
1099
- for (const [o, i] of Object.entries(e)) {
1100
- const a = JSON.stringify(i);
1101
- n[o] = a && a.length > 200 ? `[truncated ${a.length} chars]` : i;
1014
+ for (const [r, a] of Object.entries(e)) {
1015
+ const i = JSON.stringify(a);
1016
+ n[r] = i && i.length > 200 ? `[truncated ${i.length} chars]` : a;
1102
1017
  }
1103
1018
  return n;
1104
1019
  }
@@ -1107,7 +1022,7 @@ function po(e) {
1107
1022
  return "[unserializable]";
1108
1023
  }
1109
1024
  }
1110
- async function ho() {
1025
+ async function fo() {
1111
1026
  if (Te.length === 0) return;
1112
1027
  const e = Te;
1113
1028
  Te = [], Ye = null;
@@ -1115,42 +1030,42 @@ async function ho() {
1115
1030
  let n = me().serverOrigin || "";
1116
1031
  if ((n === "/" || !n) && typeof window < "u") {
1117
1032
  const l = window.location;
1118
- (l.hostname === "localhost" || l.hostname === "127.0.0.1") && l.port === String(Wt) ? n = `${l.protocol}//${l.hostname}:${Qe}` : n = l.origin;
1033
+ (l.hostname === "localhost" || l.hostname === "127.0.0.1") && l.port === String(qt) ? n = `${l.protocol}//${l.hostname}:${Qe}` : n = l.origin;
1119
1034
  }
1120
- const o = `${n.replace(/\/$/, "")}/api/client-log`, i = e.map((l) => ({
1035
+ const r = `${n.replace(/\/$/, "")}/api/client-log`, a = e.map((l) => ({
1121
1036
  level: l.level,
1122
1037
  category: l.category,
1123
1038
  message: l.message,
1124
- data: po(l.data),
1039
+ data: mo(l.data),
1125
1040
  timestamp: l.timestamp,
1126
1041
  url: typeof window < "u" ? window.location.href : void 0,
1127
1042
  userAgent: typeof navigator < "u" ? navigator.userAgent : void 0,
1128
1043
  room_key: ze?.room_key,
1129
1044
  client_id: ze?.client_id
1130
1045
  }));
1131
- let a = [], s = 0;
1132
- for (const l of i) {
1046
+ let i = [], s = 0;
1047
+ for (const l of a) {
1133
1048
  const p = JSON.stringify(l).length + 1;
1134
- s + p > fo && a.length > 0 && (await fetch(o, {
1049
+ s + p > uo && i.length > 0 && (await fetch(r, {
1135
1050
  method: "POST",
1136
1051
  headers: { "Content-Type": "application/json" },
1137
- body: JSON.stringify({ logs: a })
1138
- }), a = [], s = 0), a.push(l), s += p;
1052
+ body: JSON.stringify({ logs: i })
1053
+ }), i = [], s = 0), i.push(l), s += p;
1139
1054
  }
1140
- a.length > 0 && await fetch(o, {
1055
+ i.length > 0 && await fetch(r, {
1141
1056
  method: "POST",
1142
1057
  headers: { "Content-Type": "application/json" },
1143
- body: JSON.stringify({ logs: a })
1058
+ body: JSON.stringify({ logs: i })
1144
1059
  });
1145
1060
  } catch (t) {
1146
1061
  console.warn("[wp] log flush failed (client logs may be lost):", fe(t).error);
1147
1062
  }
1148
1063
  }
1149
- function St(e) {
1064
+ function vt(e) {
1150
1065
  if (Te.push(e), !Ye) {
1151
- const t = hn() ? to : eo;
1066
+ const t = pn() ? Zr : Qr;
1152
1067
  Ye = setTimeout(() => {
1153
- ho();
1068
+ fo();
1154
1069
  }, t);
1155
1070
  }
1156
1071
  }
@@ -1158,36 +1073,36 @@ function fe(e) {
1158
1073
  return e instanceof Error ? { error: e.message, name: e.name } : { error: String(e), name: typeof e };
1159
1074
  }
1160
1075
  Ue("__wpDebug", {
1161
- enable: co,
1162
- disable: uo,
1163
- history: so,
1164
- clear: lo
1076
+ enable: so,
1077
+ disable: lo,
1078
+ history: ao,
1079
+ clear: io
1165
1080
  });
1166
1081
  const Y = {
1167
1082
  resolved: !1,
1168
1083
  userType: "public",
1169
1084
  accountId: null
1170
1085
  };
1171
- function at() {
1086
+ function it() {
1172
1087
  return Y.accountId ? Y.accountId : Y.resolved && Y.userType === "public" ? "anon" : null;
1173
1088
  }
1174
- function go(e) {
1089
+ function po(e) {
1175
1090
  Y.resolved = !0, e.userType && (Y.userType = e.userType), e.userId !== void 0 && (Y.accountId = e.userId && e.userId !== "public" ? e.userId : null);
1176
1091
  }
1177
1092
  function st() {
1178
1093
  return Y.accountId ?? "public";
1179
1094
  }
1180
- function bo() {
1181
- return at() ?? "unscoped";
1095
+ function ho() {
1096
+ return it() ?? "unscoped";
1182
1097
  }
1183
- function gn(e) {
1184
- return tt(e) ? fr[e] : "var(--color-neutral-bg)";
1098
+ function hn(e) {
1099
+ return tt(e) ? dr[e] : "var(--color-neutral-bg)";
1185
1100
  }
1186
- function yo(e) {
1187
- return tt(e) ? `${me().serverOrigin.replace(/\/$/, "")}${hr(e)}` : void 0;
1101
+ function go(e) {
1102
+ return tt(e) ? `${me().serverOrigin.replace(/\/$/, "")}${mr(e)}` : void 0;
1188
1103
  }
1189
1104
  let ce = null, ve = null;
1190
- function vo() {
1105
+ function yo() {
1191
1106
  return ce ? Promise.resolve() : ve || (ve = (async () => {
1192
1107
  try {
1193
1108
  const e = me().serverOrigin.replace(/\/$/, ""), t = await fetch(`${e}/media/sprites/names.json`, { cache: "no-cache" });
@@ -1206,7 +1121,7 @@ function J(e) {
1206
1121
  const t = e.toLowerCase();
1207
1122
  return Me.some((n) => n === t) ? !0 : ce ? Object.values(ce).some((n) => n.toLowerCase() === t) : !1;
1208
1123
  }
1209
- const So = r.object({
1124
+ const bo = o.object({
1210
1125
  // Identity. There is deliberately NO `name`: a person's name is their
1211
1126
  // hadoku key-registry name, resolved by the server from whoami and renamed
1212
1127
  // through hadoku_site's POST /session/name (operator decision 2026-10-08).
@@ -1217,32 +1132,32 @@ const So = r.object({
1217
1132
  // (lib/avatar.ts). It stays in the schema because prefs-api still reads it:
1218
1133
  // it is the fallback character for a person who never chose one at the
1219
1134
  // top level (operator decision 2026-10-31).
1220
- sprite: r.string().optional(),
1135
+ sprite: o.string().optional(),
1221
1136
  // Chat settings
1222
- chatCollapsed: r.boolean().optional(),
1223
- floatingChatEnabled: r.boolean().optional(),
1137
+ chatCollapsed: o.boolean().optional(),
1138
+ floatingChatEnabled: o.boolean().optional(),
1224
1139
  // RoomChrome's chat column (roomChrome/chatLayout.ts) — separate from the
1225
1140
  // app's chatCollapsed on purpose.
1226
- chromeChatCollapsed: r.boolean().optional(),
1227
- chromeChatWidth: r.number().optional(),
1141
+ chromeChatCollapsed: o.boolean().optional(),
1142
+ chromeChatWidth: o.number().optional(),
1228
1143
  // Media settings
1229
- volume: r.number().min(0).max(1).optional(),
1230
- muted: r.boolean().optional(),
1231
- preferredAudioLang: r.string().optional(),
1232
- subtitlesEnabled: r.boolean().optional(),
1233
- subtitleStyle: r.string().optional()
1234
- }), se = $n({
1144
+ volume: o.number().min(0).max(1).optional(),
1145
+ muted: o.boolean().optional(),
1146
+ preferredAudioLang: o.string().optional(),
1147
+ subtitlesEnabled: o.boolean().optional(),
1148
+ subtitleStyle: o.string().optional()
1149
+ }), se = Hn({
1235
1150
  appId: "watchparty",
1236
- schema: So
1237
- }), _o = /* @__PURE__ */ new Set(["theme", "themeMode"]);
1151
+ schema: bo
1152
+ }), vo = /* @__PURE__ */ new Set(["theme", "themeMode"]);
1238
1153
  function Re(e) {
1239
- const t = at();
1154
+ const t = it();
1240
1155
  return t ? `prefs-cache:${t}:${e}` : null;
1241
1156
  }
1242
- function wo() {
1243
- return at() === null;
1157
+ function So() {
1158
+ return it() === null;
1244
1159
  }
1245
- function _t(e) {
1160
+ function St(e) {
1246
1161
  const t = Re(e);
1247
1162
  if (!t) return {};
1248
1163
  const n = B(t);
@@ -1253,106 +1168,106 @@ function _t(e) {
1253
1168
  return {};
1254
1169
  }
1255
1170
  }
1256
- function xo() {
1171
+ function _o() {
1257
1172
  let e = 0;
1258
- for (const t of Xr()) {
1259
- const n = t.startsWith("prefs-cache:") && t.endsWith(":watchparty"), o = t === De || t.startsWith(`${De}:`) && !t.endsWith(":_serverSynced_v1");
1260
- if (!n && !o) continue;
1261
- const i = B(t);
1262
- if (!i) continue;
1263
- let a;
1173
+ for (const t of Yr()) {
1174
+ const n = t.startsWith("prefs-cache:") && t.endsWith(":watchparty"), r = t === De || t.startsWith(`${De}:`) && !t.endsWith(":_serverSynced_v1");
1175
+ if (!n && !r) continue;
1176
+ const a = B(t);
1177
+ if (!a) continue;
1178
+ let i;
1264
1179
  try {
1265
- a = JSON.parse(i);
1180
+ i = JSON.parse(a);
1266
1181
  } catch {
1267
1182
  continue;
1268
1183
  }
1269
- const s = n ? a?.blob : a;
1184
+ const s = n ? i?.blob : i;
1270
1185
  if (!s || typeof s != "object" || !("name" in s)) continue;
1271
- const { name: l, ...p } = s, h = n ? { ...a, blob: p } : p;
1186
+ const { name: l, ...p } = s, h = n ? { ...i, blob: p } : p;
1272
1187
  ot(t, JSON.stringify(h)) && e++;
1273
1188
  }
1274
1189
  return e > 0 && d("preferences", "Stripped retired name from cached prefs rows", { rewritten: e }), e;
1275
1190
  }
1276
- let bn = null, yn = null;
1277
- const wt = /* @__PURE__ */ new Set();
1191
+ let gn = null, yn = null;
1192
+ const _t = /* @__PURE__ */ new Set();
1278
1193
  function lt() {
1279
- if (wo())
1194
+ if (So())
1280
1195
  return d("preferences", "Boot read deferred — session pending, identity unresolved"), {};
1281
- const e = _t("portfolio"), t = _t("watchparty"), n = Object.keys(e).length > 0 ? e : bn ?? {}, o = Object.keys(t).length > 0 ? t : yn ?? {}, i = st() || "public";
1282
- if (wt.has(i))
1196
+ const e = St("portfolio"), t = St("watchparty"), n = Object.keys(e).length > 0 ? e : gn ?? {}, r = Object.keys(t).length > 0 ? t : yn ?? {}, a = st() || "public";
1197
+ if (_t.has(a))
1283
1198
  return d("preferences", "Loaded (sync, SDK-only after first read)", {
1284
- uid: i,
1199
+ uid: a,
1285
1200
  sdkThemeKeys: Object.keys(n).length,
1286
- sdkAppKeys: Object.keys(o).length,
1201
+ sdkAppKeys: Object.keys(r).length,
1287
1202
  // 'mem' indicates in-memory backstop fired (cache was empty,
1288
1203
  // we used latestBlob instead).
1289
1204
  themeSource: Object.keys(e).length > 0 ? "cache" : "mem",
1290
1205
  appSource: Object.keys(t).length > 0 ? "cache" : "mem"
1291
- }), { ...o, ...n };
1292
- wt.add(i);
1293
- const a = Sn() ?? {}, s = { ...a, ...o, ...n };
1206
+ }), { ...r, ...n };
1207
+ _t.add(a);
1208
+ const i = vn() ?? {}, s = { ...i, ...r, ...n };
1294
1209
  return d("preferences", "Loaded (sync, first read — legacy + SDK)", {
1295
- uid: i,
1210
+ uid: a,
1296
1211
  sdkThemeKeys: Object.keys(n).length,
1297
- sdkAppKeys: Object.keys(o).length,
1298
- legacyKeys: Object.keys(a).length,
1212
+ sdkAppKeys: Object.keys(r).length,
1213
+ legacyKeys: Object.keys(i).length,
1299
1214
  themeSource: Object.keys(e).length > 0 ? "cache" : "mem",
1300
1215
  appSource: Object.keys(t).length > 0 ? "cache" : "mem"
1301
1216
  }), s;
1302
1217
  }
1303
- let vn = !1;
1304
- function Io() {
1218
+ let bn = !1;
1219
+ function wo() {
1305
1220
  const e = st();
1306
1221
  return !e || e === "public";
1307
1222
  }
1308
1223
  function G(e, t) {
1309
- Io() && (vn = !0), _o.has(e) ? ie.save({ [e]: t }, { scope: "device" }).catch((n) => k("preferences", "themePrefs.save failed", { key: e, err: n?.message })) : se.save({ [e]: t }).catch((n) => k("preferences", "watchpartyPrefs.save failed", { key: e, err: n?.message })), d("preferences", "Saved (via SDK)", { key: e, value: t });
1224
+ wo() && (bn = !0), vo.has(e) ? ae.save({ [e]: t }, { scope: "device" }).catch((n) => A("preferences", "themePrefs.save failed", { key: e, err: n?.message })) : se.save({ [e]: t }).catch((n) => A("preferences", "watchpartyPrefs.save failed", { key: e, err: n?.message })), d("preferences", "Saved (via SDK)", { key: e, value: t });
1310
1225
  }
1311
- let Se = null, xt = !1;
1312
- function Co() {
1226
+ let Se = null, wt = !1;
1227
+ function xo() {
1313
1228
  return Se || (Se = (async () => {
1314
1229
  if (typeof window > "u") return !1;
1315
1230
  try {
1316
- xt || (xt = !0, ie.subscribe((s) => {
1317
- bn = s, Tt("portfolio", s), kt("theme");
1231
+ wt || (wt = !0, ae.subscribe((s) => {
1232
+ gn = s, Ct("portfolio", s), Tt("theme");
1318
1233
  }), se.subscribe((s) => {
1319
- yn = s, Tt("watchparty", s), kt("watchparty");
1234
+ yn = s, Ct("watchparty", s), Tt("watchparty");
1320
1235
  }));
1321
1236
  const [e, t] = await Promise.all([
1322
- ie.read(),
1237
+ ae.read(),
1323
1238
  se.read()
1324
1239
  ]);
1325
1240
  try {
1326
- const { useAppStore: s } = await Promise.resolve().then(() => wn);
1241
+ const { useAppStore: s } = await Promise.resolve().then(() => _n);
1327
1242
  s.getState().rehydrateFromPrefs();
1328
1243
  } catch (s) {
1329
- k("preferences", "inline rehydrate after SDK read failed", { err: s?.message });
1244
+ A("preferences", "inline rehydrate after SDK read failed", { err: s?.message });
1330
1245
  }
1331
- const n = Re("portfolio"), o = Re("watchparty"), i = n ? B(n) : null, a = o ? B(o) : null;
1246
+ const n = Re("portfolio"), r = Re("watchparty"), a = n ? B(n) : null, i = r ? B(r) : null;
1332
1247
  return d("preferences", "sdk.read", {
1333
1248
  themeKeys: Object.keys(e ?? {}),
1334
1249
  appKeys: Object.keys(t ?? {}),
1335
1250
  // Post-fetch cache state: should be non-zero if SDK wrote it.
1336
- sdkThemeBytesPost: i?.length ?? 0,
1337
- sdkAppBytesPost: a?.length ?? 0
1338
- }), await To(e, t), vn ? (d("preferences", "Promoting this load's pre-auth picks to the signed-in user"), await Promise.all([
1339
- ie.promoteAnonPrefsToUser().catch(() => {
1251
+ sdkThemeBytesPost: a?.length ?? 0,
1252
+ sdkAppBytesPost: i?.length ?? 0
1253
+ }), await Io(e, t), bn ? (d("preferences", "Promoting this load's pre-auth picks to the signed-in user"), await Promise.all([
1254
+ ae.promoteAnonPrefsToUser().catch(() => {
1340
1255
  }),
1341
1256
  se.promoteAnonPrefsToUser().catch(() => {
1342
1257
  })
1343
1258
  ])) : d("preferences", "Skipping anon promotion — no pre-auth writes this load"), d("preferences", "First-load SDK sync complete"), !0;
1344
1259
  } catch (e) {
1345
- return k("preferences", "First-load SDK sync failed (non-fatal)", { err: e?.message }), !1;
1260
+ return A("preferences", "First-load SDK sync failed (non-fatal)", { err: e?.message }), !1;
1346
1261
  }
1347
1262
  })(), Se);
1348
1263
  }
1349
1264
  const De = "watchparty_preferences";
1350
- xo();
1265
+ _o();
1351
1266
  function Xe() {
1352
1267
  const e = st();
1353
1268
  return !e || e === "public" ? De : `${De}:${e}`;
1354
1269
  }
1355
- function Sn() {
1270
+ function vn() {
1356
1271
  const e = B(Xe());
1357
1272
  if (!e) return null;
1358
1273
  try {
@@ -1362,93 +1277,93 @@ function Sn() {
1362
1277
  return null;
1363
1278
  }
1364
1279
  }
1365
- function It() {
1280
+ function xt() {
1366
1281
  Ne(Xe()), Ne(`${Xe()}:_serverSynced_v1`);
1367
1282
  }
1368
- async function To(e, t) {
1369
- const n = Sn();
1283
+ async function Io(e, t) {
1284
+ const n = vn();
1370
1285
  if (!n || Object.keys(n).length === 0) return;
1371
- const o = Object.keys(e ?? {}).length > 0, i = Object.keys(t ?? {}).length > 0, a = {}, s = {};
1286
+ const r = Object.keys(e ?? {}).length > 0, a = Object.keys(t ?? {}).length > 0, i = {}, s = {};
1372
1287
  for (const [h, f] of Object.entries(n))
1373
- o || (h === "theme" && typeof f == "string" ? a.theme = f : h === "themeMode" && (f === "simple" || f === "advanced") && (a.themeMode = f)), i || (h === "chatCollapsed" && typeof f == "boolean" ? s.chatCollapsed = f : h === "floatingChatEnabled" && typeof f == "boolean" ? s.floatingChatEnabled = f : h === "volume" && typeof f == "number" && f >= 0 && f <= 1 ? s.volume = f : h === "muted" && typeof f == "boolean" ? s.muted = f : h === "preferredAudioLang" && typeof f == "string" ? s.preferredAudioLang = f : h === "subtitlesEnabled" && typeof f == "boolean" ? s.subtitlesEnabled = f : h === "subtitleStyle" && typeof f == "string" && (s.subtitleStyle = f));
1374
- const l = Object.keys(a), p = Object.keys(s);
1288
+ r || (h === "theme" && typeof f == "string" ? i.theme = f : h === "themeMode" && (f === "simple" || f === "advanced") && (i.themeMode = f)), a || (h === "chatCollapsed" && typeof f == "boolean" ? s.chatCollapsed = f : h === "floatingChatEnabled" && typeof f == "boolean" ? s.floatingChatEnabled = f : h === "volume" && typeof f == "number" && f >= 0 && f <= 1 ? s.volume = f : h === "muted" && typeof f == "boolean" ? s.muted = f : h === "preferredAudioLang" && typeof f == "string" ? s.preferredAudioLang = f : h === "subtitlesEnabled" && typeof f == "boolean" ? s.subtitlesEnabled = f : h === "subtitleStyle" && typeof f == "string" && (s.subtitleStyle = f));
1289
+ const l = Object.keys(i), p = Object.keys(s);
1375
1290
  if (l.length === 0 && p.length === 0) {
1376
- It();
1291
+ xt();
1377
1292
  return;
1378
1293
  }
1379
1294
  d("preferences", "Migrating legacy localStorage prefs to SDK", {
1380
1295
  themeKeys: l,
1381
1296
  appKeys: p,
1382
- sdkHasTheme: o,
1383
- sdkHasApp: i
1297
+ sdkHasTheme: r,
1298
+ sdkHasApp: a
1384
1299
  });
1385
1300
  try {
1386
1301
  await Promise.all([
1387
- l.length > 0 ? ie.save(a, { scope: "device" }) : Promise.resolve(),
1302
+ l.length > 0 ? ae.save(i, { scope: "device" }) : Promise.resolve(),
1388
1303
  p.length > 0 ? se.save(s) : Promise.resolve()
1389
- ]), It(), d("preferences", "Legacy migration complete");
1304
+ ]), xt(), d("preferences", "Legacy migration complete");
1390
1305
  } catch (h) {
1391
- k("preferences", "Legacy migration save failed — will retry next load", {
1306
+ A("preferences", "Legacy migration save failed — will retry next load", {
1392
1307
  err: h?.message
1393
1308
  });
1394
1309
  }
1395
1310
  }
1396
- let Ct = !1;
1397
- function Tt(e, t) {
1311
+ let It = !1;
1312
+ function Ct(e, t) {
1398
1313
  const n = Re(e);
1399
1314
  if (n)
1400
1315
  try {
1401
- const o = {
1316
+ const r = {
1402
1317
  blob: t,
1403
1318
  userVersion: 0,
1404
1319
  deviceVersion: 0,
1405
1320
  cachedAt: Date.now()
1406
1321
  };
1407
- localStorage.setItem(n, JSON.stringify(o));
1408
- } catch (o) {
1409
- Ct || (Ct = !0, k("preferences", "writeThrough localStorage failed (in-memory backstop only)", {
1322
+ localStorage.setItem(n, JSON.stringify(r));
1323
+ } catch (r) {
1324
+ It || (It = !0, A("preferences", "writeThrough localStorage failed (in-memory backstop only)", {
1410
1325
  appId: e,
1411
- err: o?.message,
1412
- name: o?.name
1326
+ err: r?.message,
1327
+ name: r?.name
1413
1328
  }));
1414
1329
  }
1415
1330
  }
1416
- function kt(e) {
1417
- Promise.resolve().then(() => wn).then(({ useAppStore: t }) => {
1331
+ function Tt(e) {
1332
+ Promise.resolve().then(() => _n).then(({ useAppStore: t }) => {
1418
1333
  try {
1419
1334
  t.getState().rehydrateFromPrefs();
1420
1335
  } catch (n) {
1421
- k("preferences", "rehydrateFromPrefs threw", { reason: e, err: n?.message });
1336
+ A("preferences", "rehydrateFromPrefs threw", { reason: e, err: n?.message });
1422
1337
  }
1423
- }).catch((t) => k("preferences", "store import failed", { reason: e, err: t?.message }));
1338
+ }).catch((t) => A("preferences", "store import failed", { reason: e, err: t?.message }));
1424
1339
  }
1425
- const _n = 320, Oe = 240, ct = 640, ko = 320, Ao = 36, At = 16;
1426
- function W(e, t) {
1427
- if (!Number.isFinite(e)) return _n;
1340
+ const Sn = 320, Oe = 240, ct = 640, Co = 320, To = 36, At = 16;
1341
+ function V(e, t) {
1342
+ if (!Number.isFinite(e)) return Sn;
1428
1343
  let n = ct;
1429
- return t !== void 0 && Number.isFinite(t) && t > 0 && (n = Math.min(n, t - ko)), n = Math.max(n, Oe), Math.round(Math.min(n, Math.max(Oe, e)));
1344
+ return t !== void 0 && Number.isFinite(t) && t > 0 && (n = Math.min(n, t - Co)), n = Math.max(n, Oe), Math.round(Math.min(n, Math.max(Oe, e)));
1430
1345
  }
1431
- function Et(e, t, n, o) {
1432
- return W(e + (t - n), o);
1346
+ function kt(e, t, n, r) {
1347
+ return V(e + (t - n), r);
1433
1348
  }
1434
- function Eo(e, t, n) {
1349
+ function Ao(e, t, n) {
1435
1350
  switch (t) {
1436
1351
  case "ArrowLeft":
1437
- return W(e + At, n);
1352
+ return V(e + At, n);
1438
1353
  case "ArrowRight":
1439
- return W(e - At, n);
1354
+ return V(e - At, n);
1440
1355
  case "Home":
1441
- return W(Oe, n);
1356
+ return V(Oe, n);
1442
1357
  case "End":
1443
- return W(ct, n);
1358
+ return V(ct, n);
1444
1359
  default:
1445
1360
  return null;
1446
1361
  }
1447
1362
  }
1448
- function Po(e, t) {
1449
- return { collapsed: e, width: e ? Ao : t };
1363
+ function ko(e, t) {
1364
+ return { collapsed: e, width: e ? To : t };
1450
1365
  }
1451
- const K = lt(), u = Hn((e, t) => ({
1366
+ const q = lt(), u = Fn((e, t) => ({
1452
1367
  ready: !1,
1453
1368
  name: "",
1454
1369
  sprite: null,
@@ -1456,9 +1371,9 @@ const K = lt(), u = Hn((e, t) => ({
1456
1371
  snapshot: { roomId: null, mediaId: null, playheadMs: 0, playing: !1, serverSeq: 0, leaderId: null },
1457
1372
  roster: {},
1458
1373
  chat: [],
1459
- chatCollapsed: K.chatCollapsed ?? !1,
1460
- chromeChatCollapsed: K.chromeChatCollapsed ?? !1,
1461
- chromeChatWidth: W(K.chromeChatWidth ?? _n),
1374
+ chatCollapsed: q.chatCollapsed ?? !1,
1375
+ chromeChatCollapsed: q.chromeChatCollapsed ?? !1,
1376
+ chromeChatWidth: V(q.chromeChatWidth ?? Sn),
1462
1377
  // Hardcoded on for everyone — the per-user toggle was removed from the
1463
1378
  // control bar; FloatingChat + toggleFloatingChat code is kept for future
1464
1379
  // re-enablement but the value is no longer user-controllable.
@@ -1470,11 +1385,11 @@ const K = lt(), u = Hn((e, t) => ({
1470
1385
  bufferState: { isBuffering: !1, bufferedEndMs: 0 },
1471
1386
  toasts: [],
1472
1387
  mediaPrefs: {
1473
- volume: K.volume ?? 1,
1474
- muted: K.muted ?? !1,
1475
- preferredAudioLang: K.preferredAudioLang || "jpn",
1476
- subtitlesEnabled: K.subtitlesEnabled ?? !0,
1477
- subtitleStyle: ["classic", "cinema", "minimal", "contrast"].includes(K.subtitleStyle) ? K.subtitleStyle : "classic"
1388
+ volume: q.volume ?? 1,
1389
+ muted: q.muted ?? !1,
1390
+ preferredAudioLang: q.preferredAudioLang || "jpn",
1391
+ subtitlesEnabled: q.subtitlesEnabled ?? !0,
1392
+ subtitleStyle: ["classic", "cinema", "minimal", "contrast"].includes(q.subtitleStyle) ? q.subtitleStyle : "classic"
1478
1393
  },
1479
1394
  healthSnapshot: null,
1480
1395
  sidebarTab: "chat",
@@ -1493,57 +1408,55 @@ const K = lt(), u = Hn((e, t) => ({
1493
1408
  activeGameId: null,
1494
1409
  gameSettings: null,
1495
1410
  roomKeyType: null,
1496
- gameSessionWins: {},
1497
- gameBotCount: 0,
1498
1411
  setReady: () => {
1499
1412
  d("store", "App ready"), e({ ready: !0 });
1500
1413
  },
1501
- setSessionIdentity: (n, o) => {
1502
- d("store", "Session identity set (not persisted)", { name: n, sprite: o }), e({ name: n, sprite: o });
1414
+ setSessionIdentity: (n, r) => {
1415
+ d("store", "Session identity set (not persisted)", { name: n, sprite: r }), e({ name: n, sprite: r });
1503
1416
  },
1504
1417
  ensureAutoIdentity: () => e((n) => {
1505
1418
  if (n.name) return {};
1506
1419
  if (n.sprite) {
1507
- const i = de(n.sprite);
1508
- return d("store", "Auto-identity: deriving name from the requested sprite", { name: i, sprite: n.sprite }), { name: i };
1420
+ const a = de(n.sprite);
1421
+ return d("store", "Auto-identity: deriving name from the requested sprite", { name: a, sprite: n.sprite }), { name: a };
1509
1422
  }
1510
- const o = new Set(Object.values(n.roster).map((i) => i.sprite).filter(Boolean));
1423
+ const r = new Set(Object.values(n.roster).map((a) => a.sprite).filter(Boolean));
1511
1424
  d("store", "ensureAutoIdentity checking", {
1512
1425
  rosterSize: Object.keys(n.roster).length,
1513
- usedSprites: Array.from(o)
1426
+ usedSprites: Array.from(r)
1514
1427
  });
1515
- for (const i of Me)
1516
- if (!o.has(i)) {
1517
- const a = de(i);
1518
- return d("store", "Auto-identity assigned", { name: a, sprite: i }), { name: a, sprite: i };
1428
+ for (const a of Me)
1429
+ if (!r.has(a)) {
1430
+ const i = de(a);
1431
+ return d("store", "Auto-identity assigned", { name: i, sprite: a }), { name: i, sprite: a };
1519
1432
  }
1520
- return k("store", "All characters taken, leaving identity unset"), {};
1433
+ return A("store", "All characters taken, leaving identity unset"), {};
1521
1434
  }),
1522
1435
  ensureMe: (n) => {
1523
- d("store", "Client ID set", { clientId: n }), e((o) => ({ me: { ...o.me, clientId: n } }));
1436
+ d("store", "Client ID set", { clientId: n }), e((r) => ({ me: { ...r.me, clientId: n } }));
1524
1437
  },
1525
- applySnapshot: (n) => e((o) => {
1526
- const i = { ...o.roster };
1438
+ applySnapshot: (n) => e((r) => {
1439
+ const a = { ...r.roster };
1527
1440
  if (n.users)
1528
- for (const p of n.users) i[p.clientId] = p;
1529
- const a = n.mediaId !== void 0 ? n.mediaId : o.snapshot.mediaId, s = n.leaderId !== void 0 ? n.leaderId : o.snapshot.leaderId;
1441
+ for (const p of n.users) a[p.clientId] = p;
1442
+ const i = n.mediaId !== void 0 ? n.mediaId : r.snapshot.mediaId, s = n.leaderId !== void 0 ? n.leaderId : r.snapshot.leaderId;
1530
1443
  d("store", "Snapshot applied", {
1531
- mediaId: a,
1532
- playing: n.playing ?? o.snapshot.playing,
1533
- serverSeq: n.serverSeq ?? o.snapshot.serverSeq,
1444
+ mediaId: i,
1445
+ playing: n.playing ?? r.snapshot.playing,
1446
+ serverSeq: n.serverSeq ?? r.snapshot.serverSeq,
1534
1447
  userCount: n.users?.length ?? 0
1535
1448
  });
1536
- const l = n.playheadMs ?? o.snapshot.playheadMs;
1449
+ const l = n.playheadMs ?? r.snapshot.playheadMs;
1537
1450
  return {
1538
1451
  snapshot: {
1539
- roomId: n.roomId !== void 0 ? n.roomId : o.snapshot.roomId,
1540
- mediaId: a,
1452
+ roomId: n.roomId !== void 0 ? n.roomId : r.snapshot.roomId,
1453
+ mediaId: i,
1541
1454
  playheadMs: l,
1542
- playing: n.playing ?? o.snapshot.playing,
1543
- serverSeq: n.serverSeq ?? o.snapshot.serverSeq,
1455
+ playing: n.playing ?? r.snapshot.playing,
1456
+ serverSeq: n.serverSeq ?? r.snapshot.serverSeq,
1544
1457
  leaderId: s
1545
1458
  },
1546
- roster: i,
1459
+ roster: a,
1547
1460
  // Always update — initial snapshot on join often has playheadMs=0
1548
1461
  // matching the store default, so the old playheadChanged guard left
1549
1462
  // snapshotReceivedAt at page-load time. This inflated viewer correction
@@ -1552,42 +1465,42 @@ const K = lt(), u = Hn((e, t) => ({
1552
1465
  };
1553
1466
  }),
1554
1467
  upsertUser: (n) => {
1555
- d("store", "User upserted", { clientId: n.clientId, name: n.name, isLeader: n.isLeader }), e((o) => ({ roster: { ...o.roster, [n.clientId]: n } }));
1468
+ d("store", "User upserted", { clientId: n.clientId, name: n.name, isLeader: n.isLeader }), e((r) => ({ roster: { ...r.roster, [n.clientId]: n } }));
1556
1469
  },
1557
1470
  removeUser: (n) => {
1558
- d("store", "User removed", { clientId: n }), e((o) => {
1559
- const i = { ...o.roster };
1560
- return delete i[n], { roster: i };
1471
+ d("store", "User removed", { clientId: n }), e((r) => {
1472
+ const a = { ...r.roster };
1473
+ return delete a[n], { roster: a };
1561
1474
  });
1562
1475
  },
1563
1476
  appendChat: (n) => {
1564
- d("chat", "Message appended", { id: n.id, from: n.name, isSystem: n.isSystem }), e((o) => ({ chat: [...o.chat, n].slice(-500) }));
1477
+ d("chat", "Message appended", { id: n.id, from: n.name, isSystem: n.isSystem }), e((r) => ({ chat: [...r.chat, n].slice(-500) }));
1565
1478
  },
1566
1479
  setChat: (n) => e({ chat: n.slice(-500) }),
1567
1480
  toggleChatCollapsed: () => e((n) => {
1568
- const o = !n.chatCollapsed;
1569
- return G("chatCollapsed", o), { chatCollapsed: o };
1481
+ const r = !n.chatCollapsed;
1482
+ return G("chatCollapsed", r), { chatCollapsed: r };
1570
1483
  }),
1571
1484
  toggleChromeChatCollapsed: () => e((n) => {
1572
- const o = !n.chromeChatCollapsed;
1573
- return G("chromeChatCollapsed", o), { chromeChatCollapsed: o };
1485
+ const r = !n.chromeChatCollapsed;
1486
+ return G("chromeChatCollapsed", r), { chromeChatCollapsed: r };
1574
1487
  }),
1575
1488
  setChromeChatWidth: (n) => e(() => {
1576
- const o = W(n);
1577
- return G("chromeChatWidth", o), { chromeChatWidth: o };
1489
+ const r = V(n);
1490
+ return G("chromeChatWidth", r), { chromeChatWidth: r };
1578
1491
  }),
1579
1492
  toggleFloatingChat: () => e((n) => {
1580
- const o = !n.floatingChatEnabled;
1581
- return G("floatingChatEnabled", o), { floatingChatEnabled: o };
1493
+ const r = !n.floatingChatEnabled;
1494
+ return G("floatingChatEnabled", r), { floatingChatEnabled: r };
1582
1495
  }),
1583
1496
  allocateClientSeq: () => {
1584
1497
  const n = t().me.nextClientSeq;
1585
- return e((o) => ({ me: { ...o.me, nextClientSeq: n + 1 } })), n;
1498
+ return e((r) => ({ me: { ...r.me, nextClientSeq: n + 1 } })), n;
1586
1499
  },
1587
1500
  bumpLoadGeneration: () => e((n) => ({ loadGeneration: n.loadGeneration + 1 })),
1588
1501
  updateControlState: (n) => {
1589
- d("store", "updateControlState called", n), e((o) => ({
1590
- snapshot: { ...o.snapshot, ...n },
1502
+ d("store", "updateControlState called", n), e((r) => ({
1503
+ snapshot: { ...r.snapshot, ...n },
1591
1504
  // Always update snapshotReceivedAt — any control_broadcast from the
1592
1505
  // server resets the elapsed-time calculation. The old condition
1593
1506
  // (playheadMs !== s.snapshot.playheadMs) missed media reloads that
@@ -1596,28 +1509,28 @@ const K = lt(), u = Hn((e, t) => ({
1596
1509
  snapshotReceivedAt: Date.now()
1597
1510
  }));
1598
1511
  },
1599
- addRttSample: (n, o, i) => e((a) => {
1600
- const s = [...a.drift.rtts, n].slice(-5);
1601
- let l = a.drift.offsetMs;
1602
- if (o && i) {
1603
- const p = i + n / 2;
1604
- l = o - p;
1512
+ addRttSample: (n, r, a) => e((i) => {
1513
+ const s = [...i.drift.rtts, n].slice(-5);
1514
+ let l = i.drift.offsetMs;
1515
+ if (r && a) {
1516
+ const p = a + n / 2;
1517
+ l = r - p;
1605
1518
  }
1606
1519
  return { drift: { rtts: s, offsetMs: l } };
1607
1520
  }),
1608
- pushToast: (n, o) => {
1609
- d("store", "Toast pushed", { kind: n, msg: o }), e((i) => ({ toasts: [...i.toasts, { id: Math.random().toString(36).slice(2), kind: n, msg: o, ts: Date.now() }].slice(-5) }));
1521
+ pushToast: (n, r) => {
1522
+ d("store", "Toast pushed", { kind: n, msg: r }), e((a) => ({ toasts: [...a.toasts, { id: Math.random().toString(36).slice(2), kind: n, msg: r, ts: Date.now() }].slice(-5) }));
1610
1523
  },
1611
- popToast: (n) => e((o) => ({ toasts: o.toasts.filter((i) => i.id !== n) })),
1524
+ popToast: (n) => e((r) => ({ toasts: r.toasts.filter((a) => a.id !== n) })),
1612
1525
  setReadiness: (n) => e({ readiness: { mediaId: n.mediaId, ready: n.ready, readyCount: n.readyCount, total: n.total } }),
1613
- setBufferState: (n) => e((o) => ({ bufferState: { ...o.bufferState, ...n } })),
1526
+ setBufferState: (n) => e((r) => ({ bufferState: { ...r.bufferState, ...n } })),
1614
1527
  setMutedForAutoplay: (n) => e({ mutedForAutoplay: n }),
1615
1528
  // Media preference actions
1616
- setVolume: (n) => e((o) => (G("volume", n), { mediaPrefs: { ...o.mediaPrefs, volume: n } })),
1617
- setMuted: (n) => e((o) => (G("muted", n), { mediaPrefs: { ...o.mediaPrefs, muted: n } })),
1618
- setPreferredAudioLang: (n) => e((o) => (G("preferredAudioLang", n), { mediaPrefs: { ...o.mediaPrefs, preferredAudioLang: n } })),
1619
- setSubtitlesEnabled: (n) => e((o) => (G("subtitlesEnabled", n), { mediaPrefs: { ...o.mediaPrefs, subtitlesEnabled: n } })),
1620
- setSubtitleStyle: (n) => e((o) => (G("subtitleStyle", n), { mediaPrefs: { ...o.mediaPrefs, subtitleStyle: n } })),
1529
+ setVolume: (n) => e((r) => (G("volume", n), { mediaPrefs: { ...r.mediaPrefs, volume: n } })),
1530
+ setMuted: (n) => e((r) => (G("muted", n), { mediaPrefs: { ...r.mediaPrefs, muted: n } })),
1531
+ setPreferredAudioLang: (n) => e((r) => (G("preferredAudioLang", n), { mediaPrefs: { ...r.mediaPrefs, preferredAudioLang: n } })),
1532
+ setSubtitlesEnabled: (n) => e((r) => (G("subtitlesEnabled", n), { mediaPrefs: { ...r.mediaPrefs, subtitlesEnabled: n } })),
1533
+ setSubtitleStyle: (n) => e((r) => (G("subtitleStyle", n), { mediaPrefs: { ...r.mediaPrefs, subtitleStyle: n } })),
1621
1534
  setHealthSnapshot: (n) => e({ healthSnapshot: n }),
1622
1535
  setBufferStatus: (n) => e({ bufferStatus: n }),
1623
1536
  applyPlaylistState: (n) => e({
@@ -1640,9 +1553,9 @@ const K = lt(), u = Hn((e, t) => ({
1640
1553
  * board or saves its own, which are the two moments its draft is not ahead of
1641
1554
  * the server.
1642
1555
  */
1643
- setTierlistSnapshot: (n, o) => e((i) => ({
1556
+ setTierlistSnapshot: (n, r) => e((a) => ({
1644
1557
  tierlist: n,
1645
- tierlistDraft: o ? { ...n.myBoard } : i.tierlistDraft
1558
+ tierlistDraft: r ? { ...n.myBoard } : a.tierlistDraft
1646
1559
  })),
1647
1560
  /**
1648
1561
  * Move one item on the draft board. Local only — nothing reaches the server
@@ -1653,15 +1566,15 @@ const K = lt(), u = Hn((e, t) => ({
1653
1566
  * present-with-a-low-value — is what keeps "not rated" distinguishable from
1654
1567
  * "rated F" in placeTierlist.
1655
1568
  */
1656
- moveTierlistItem: (n, o, i) => e((a) => {
1569
+ moveTierlistItem: (n, r, a) => e((i) => {
1657
1570
  const s = {};
1658
- for (const [l, p] of Object.entries(a.tierlistDraft)) {
1571
+ for (const [l, p] of Object.entries(i.tierlistDraft)) {
1659
1572
  const h = (p ?? []).filter((f) => f !== n);
1660
1573
  h.length > 0 && (s[l] = h);
1661
1574
  }
1662
- if (o !== null) {
1663
- const l = s[o] ?? [], p = Math.max(0, Math.min(i ?? l.length, l.length));
1664
- l.splice(p, 0, n), s[o] = l;
1575
+ if (r !== null) {
1576
+ const l = s[r] ?? [], p = Math.max(0, Math.min(a ?? l.length, l.length));
1577
+ l.splice(p, 0, n), s[r] = l;
1665
1578
  }
1666
1579
  return { tierlistDraft: s };
1667
1580
  }),
@@ -1669,37 +1582,35 @@ const K = lt(), u = Hn((e, t) => ({
1669
1582
  setActiveGameId: (n) => e({ activeGameId: n }),
1670
1583
  setGameSettings: (n) => e({ gameSettings: n }),
1671
1584
  setRoomKeyType: (n) => e({ roomKeyType: n }),
1672
- setGameSessionWins: (n) => e({ gameSessionWins: { ...n } }),
1673
- setGameBotCount: (n) => e({ gameBotCount: Math.max(0, Math.floor(n)) }),
1674
1585
  rehydrateFromPrefs: () => e((n) => {
1675
- const o = lt(), i = {};
1676
- if (o.chatCollapsed !== void 0 && (i.chatCollapsed = o.chatCollapsed), o.chromeChatCollapsed !== void 0 && (i.chromeChatCollapsed = o.chromeChatCollapsed), o.chromeChatWidth !== void 0 && (i.chromeChatWidth = W(o.chromeChatWidth)), ["volume", "muted", "preferredAudioLang", "subtitlesEnabled", "subtitleStyle"].some((l) => o[l] !== void 0)) {
1586
+ const r = lt(), a = {};
1587
+ if (r.chatCollapsed !== void 0 && (a.chatCollapsed = r.chatCollapsed), r.chromeChatCollapsed !== void 0 && (a.chromeChatCollapsed = r.chromeChatCollapsed), r.chromeChatWidth !== void 0 && (a.chromeChatWidth = V(r.chromeChatWidth)), ["volume", "muted", "preferredAudioLang", "subtitlesEnabled", "subtitleStyle"].some((l) => r[l] !== void 0)) {
1677
1588
  const l = { ...n.mediaPrefs };
1678
- o.volume !== void 0 && (l.volume = o.volume), o.muted !== void 0 && (l.muted = o.muted), o.preferredAudioLang !== void 0 && (l.preferredAudioLang = o.preferredAudioLang), o.subtitlesEnabled !== void 0 && (l.subtitlesEnabled = o.subtitlesEnabled), o.subtitleStyle !== void 0 && ["classic", "cinema", "minimal", "contrast"].includes(o.subtitleStyle) && (l.subtitleStyle = o.subtitleStyle), i.mediaPrefs = l;
1589
+ r.volume !== void 0 && (l.volume = r.volume), r.muted !== void 0 && (l.muted = r.muted), r.preferredAudioLang !== void 0 && (l.preferredAudioLang = r.preferredAudioLang), r.subtitlesEnabled !== void 0 && (l.subtitlesEnabled = r.subtitlesEnabled), r.subtitleStyle !== void 0 && ["classic", "cinema", "minimal", "contrast"].includes(r.subtitleStyle) && (l.subtitleStyle = r.subtitleStyle), a.mediaPrefs = l;
1679
1590
  }
1680
- return i;
1591
+ return a;
1681
1592
  }),
1682
- setSidebarTab: (n) => e((o) => o.sidebarTab === n && n !== "chat" ? { sidebarTab: "chat" } : { sidebarTab: n, chatCollapsed: !1 })
1593
+ setSidebarTab: (n) => e((r) => r.sidebarTab === n && n !== "chat" ? { sidebarTab: "chat" } : { sidebarTab: n, chatCollapsed: !1 })
1683
1594
  }));
1684
1595
  Ue("__ZUSTAND_STORE__", u);
1685
- const wn = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1596
+ const _n = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1686
1597
  __proto__: null,
1687
1598
  useAppStore: u
1688
1599
  }, Symbol.toStringTag, { value: "Module" }));
1689
- function No(e) {
1690
- return `${cn()}/media/${e}`.replace(/\\/g, "/");
1600
+ function Eo(e) {
1601
+ return `${ln()}/media/${e}`.replace(/\\/g, "/");
1691
1602
  }
1692
- function Ro(e, t) {
1693
- return No(t ?? `${e}/poster.jpg`);
1603
+ function Po(e, t) {
1604
+ return Eo(t ?? `${e}/poster.jpg`);
1694
1605
  }
1695
- function Do(e) {
1696
- return `${cn()}${e}`.replace(/\\/g, "/");
1606
+ function No(e) {
1607
+ return `${ln()}${e}`.replace(/\\/g, "/");
1697
1608
  }
1698
- async function Oo(e) {
1609
+ async function Ro(e) {
1699
1610
  try {
1700
- const t = await fetch(Do("/api/tierlist"));
1611
+ const t = await fetch(No("/api/tierlist"));
1701
1612
  if (!t.ok)
1702
- return k("tierlist", "Board fetch failed", { status: t.status }), null;
1613
+ return A("tierlist", "Board fetch failed", { status: t.status }), null;
1703
1614
  const n = await t.json();
1704
1615
  return u.getState().setTierlistSnapshot(n, e), d("tierlist", "Board loaded", {
1705
1616
  items: n.items.length,
@@ -1707,81 +1618,81 @@ async function Oo(e) {
1707
1618
  placed: n.placed.length
1708
1619
  }), n;
1709
1620
  } catch (t) {
1710
- return k("tierlist", "Board fetch threw", fe(t)), null;
1621
+ return A("tierlist", "Board fetch threw", fe(t)), null;
1711
1622
  }
1712
1623
  }
1713
- let Pt = !1;
1714
- function Mo() {
1715
- if (Pt || typeof Image > "u") return;
1624
+ let Et = !1;
1625
+ function Do() {
1626
+ if (Et || typeof Image > "u") return;
1716
1627
  const e = u.getState().tierlist;
1717
1628
  if (!(!e || e.items.length === 0)) {
1718
- Pt = !0;
1629
+ Et = !0;
1719
1630
  for (const t of e.items) {
1720
1631
  const n = new Image();
1721
- n.decoding = "async", n.src = Ro(t.id, t.thumbnail);
1632
+ n.decoding = "async", n.src = Po(t.id, t.thumbnail);
1722
1633
  }
1723
1634
  d("tierlist", "Warming posters", { count: e.items.length });
1724
1635
  }
1725
1636
  }
1726
- function Lo() {
1727
- const e = u.getState(), t = new Set(Object.values(e.roster).map((a) => a.sprite).filter(Boolean)), n = Me.find((a) => !t.has(a));
1637
+ function Oo() {
1638
+ const e = u.getState(), t = new Set(Object.values(e.roster).map((i) => i.sprite).filter(Boolean)), n = Me.find((i) => !t.has(i));
1728
1639
  if (!n)
1729
- return k("socket", "sprite_taken: no available sprites to retry with"), null;
1730
- const o = !!e.name && !J(e.name), i = o ? e.name : de(n);
1731
- return d("socket", "sprite_taken: retrying with next available", { from: e.sprite, to: n, name: i, keptCustomName: o }), e.setSessionIdentity(i, n), { name: i, sprite: n };
1640
+ return A("socket", "sprite_taken: no available sprites to retry with"), null;
1641
+ const r = !!e.name && !J(e.name), a = r ? e.name : de(n);
1642
+ return d("socket", "sprite_taken: retrying with next available", { from: e.sprite, to: n, name: a, keptCustomName: r }), e.setSessionIdentity(a, n), { name: a, sprite: n };
1732
1643
  }
1733
- function jo(e) {
1644
+ function Mo(e) {
1734
1645
  const t = u.getState(), n = e ? t.roster[e] : void 0;
1735
1646
  return !n || !!n.sprite && n.sprite === t.sprite;
1736
1647
  }
1737
- const Nt = "hadoku:avatar";
1738
- function xn(e) {
1648
+ const Pt = "hadoku:avatar";
1649
+ function wn(e) {
1739
1650
  const t = e?.sprite ?? e?.avatar?.sprite ?? null;
1740
1651
  return tt(t) ? t : null;
1741
1652
  }
1742
- async function Uo(e = {}) {
1743
- const t = e.fetch ?? (typeof fetch > "u" ? void 0 : fetch), n = typeof window > "u" ? void 0 : window.location?.origin, o = e.baseUrl ?? (n ? `${n}/prefs` : void 0);
1744
- if (!t || !o) return null;
1653
+ async function Lo(e = {}) {
1654
+ const t = e.fetch ?? (typeof fetch > "u" ? void 0 : fetch), n = typeof window > "u" ? void 0 : window.location?.origin, r = e.baseUrl ?? (n ? `${n}/prefs` : void 0);
1655
+ if (!t || !r) return null;
1745
1656
  try {
1746
- const i = await Wn({ baseUrl: o, fetch: t }).get(), a = xn(i);
1747
- return d("avatar", "Requested character from prefs-api", { sprite: a }), a;
1748
- } catch (i) {
1749
- return i instanceof ht && (i.status === 401 || i.status === 403 || i.status === 404) ? d("avatar", "No avatar settings here (signed out, or no prefs-api on this origin)", { status: i.status }) : k("avatar", "Avatar settings read failed — keeping the auto-assigned character", {
1750
- status: i instanceof ht ? i.status : void 0,
1751
- ...fe(i)
1657
+ const a = await qn({ baseUrl: r, fetch: t }).get(), i = wn(a);
1658
+ return d("avatar", "Requested character from prefs-api", { sprite: i }), i;
1659
+ } catch (a) {
1660
+ return a instanceof ht && (a.status === 401 || a.status === 403 || a.status === 404) ? d("avatar", "No avatar settings here (signed out, or no prefs-api on this origin)", { status: a.status }) : A("avatar", "Avatar settings read failed — keeping the auto-assigned character", {
1661
+ status: a instanceof ht ? a.status : void 0,
1662
+ ...fe(a)
1752
1663
  }), null;
1753
1664
  }
1754
1665
  }
1755
- function Rt(e) {
1666
+ function Nt(e) {
1756
1667
  if (!e) return !1;
1757
1668
  const t = u.getState();
1758
1669
  if (t.sprite === e) return !1;
1759
- const o = !!(t.me.clientId && t.roster[t.me.clientId]?.registryName) || !t.name || !J(t.name) ? t.name : de(e);
1760
- return t.setSessionIdentity(o, e), !0;
1670
+ const r = !!(t.me.clientId && t.roster[t.me.clientId]?.registryName) || !t.name || !J(t.name) ? t.name : de(e);
1671
+ return t.setSessionIdentity(r, e), !0;
1761
1672
  }
1762
- function Fo(e, t = typeof window > "u" ? void 0 : window) {
1673
+ function jo(e, t = typeof window > "u" ? void 0 : window) {
1763
1674
  if (!t) return () => {
1764
1675
  };
1765
- const n = (o) => {
1766
- const i = o.detail;
1767
- !i || typeof i != "object" || e(i);
1676
+ const n = (r) => {
1677
+ const a = r.detail;
1678
+ !a || typeof a != "object" || e(a);
1768
1679
  };
1769
- return t.addEventListener(Nt, n), () => t.removeEventListener(Nt, n);
1680
+ return t.addEventListener(Pt, n), () => t.removeEventListener(Pt, n);
1770
1681
  }
1771
- const Ho = 10;
1772
- function $o(e = typeof window < "u" ? window : void 0) {
1682
+ const Uo = 10;
1683
+ function Fo(e = typeof window < "u" ? window : void 0) {
1773
1684
  if (!e) return { framed: !1, depth: 0 };
1774
1685
  try {
1775
1686
  let t = 0, n = e;
1776
- for (; n !== n.parent && t < Ho; )
1687
+ for (; n !== n.parent && t < Uo; )
1777
1688
  t++, n = n.parent;
1778
1689
  return { framed: e.top ? e.top !== e.self : t > 0, depth: t };
1779
1690
  } catch {
1780
1691
  return { framed: !1, depth: 0 };
1781
1692
  }
1782
1693
  }
1783
- const Bo = "watchparty_fragment_delivery";
1784
- function Go() {
1694
+ const Ho = "watchparty_fragment_delivery";
1695
+ function $o() {
1785
1696
  if (typeof window > "u") return null;
1786
1697
  try {
1787
1698
  const e = new URLSearchParams(window.location.search).get("fragmentDelivery");
@@ -1789,93 +1700,93 @@ function Go() {
1789
1700
  if (e === "0" || e === "false") return !1;
1790
1701
  } catch {
1791
1702
  }
1792
- return Jr(Bo);
1703
+ return zr(Ho);
1793
1704
  }
1794
- let Ko = { ...Zt }, He = null;
1795
- const Dt = "watchparty_delivery_client_id";
1796
- function Wo() {
1797
- const e = B(Dt);
1705
+ let Bo = { ...Qt }, He = null;
1706
+ const Rt = "watchparty_delivery_client_id";
1707
+ function Go() {
1708
+ const e = B(Rt);
1798
1709
  if (e) return e;
1799
1710
  const t = globalThis.crypto?.randomUUID?.() ?? `d${Math.random().toString(36).slice(2)}`;
1800
- return ot(Dt, t) ? t : "";
1711
+ return ot(Rt, t) ? t : "";
1801
1712
  }
1802
1713
  function qo() {
1803
- return He === null && (He = _r(Ko, Wo(), Go())), He;
1714
+ return He === null && (He = br(Bo, Go(), $o())), He;
1804
1715
  }
1805
1716
  function Vo() {
1806
1717
  return qo();
1807
1718
  }
1808
- let Ae;
1809
- function In() {
1810
- return B(Gn) || void 0;
1719
+ let ke;
1720
+ function xn() {
1721
+ return B(Bn) || void 0;
1811
1722
  }
1812
- function Yo() {
1813
- if (Ae) return;
1814
- const e = In();
1723
+ function Ko() {
1724
+ if (ke) return;
1725
+ const e = xn();
1815
1726
  if (e) {
1816
- Ae = e;
1727
+ ke = e;
1817
1728
  return;
1818
1729
  }
1819
- Bn().then((t) => {
1820
- t && (Ae = t);
1730
+ $n().then((t) => {
1731
+ t && (ke = t);
1821
1732
  }).catch(() => {
1822
1733
  d("identity", "device id unavailable — joining without one");
1823
1734
  });
1824
1735
  }
1825
- function zo() {
1826
- return Ae ??= In();
1736
+ function Wo() {
1737
+ return ke ??= xn();
1827
1738
  }
1828
- function Xo(e, t) {
1739
+ function Yo(e, t) {
1829
1740
  let n = 0;
1830
- for (const o of e.videos) {
1831
- const i = te.voteKey(t, e.id, o.mediaId);
1832
- globalThis.localStorage?.getItem(i) != null && n++, Ne(i);
1741
+ for (const r of e.videos) {
1742
+ const a = te.voteKey(t, e.id, r.mediaId);
1743
+ globalThis.localStorage?.getItem(a) != null && n++, Ne(a);
1833
1744
  }
1834
1745
  return n;
1835
1746
  }
1836
- const Jo = 2e4, Qo = 1e4;
1837
- function Zo() {
1747
+ const zo = 2e4, Xo = 1e4;
1748
+ function Jo() {
1838
1749
  return { unansweredSince: null, lastPongAt: null, lastTickAt: null };
1839
1750
  }
1840
- function ei(e, t) {
1751
+ function Qo(e, t) {
1841
1752
  e.lastPongAt = t, e.unansweredSince = null;
1842
1753
  }
1843
- function ti(e, t, n) {
1844
- const o = e.lastTickAt !== null && t - e.lastTickAt > Qo;
1845
- return e.lastTickAt = t, n ? o || e.unansweredSince === null ? (e.unansweredSince = t, !1) : t - e.unansweredSince > Jo : (e.unansweredSince = null, !1);
1754
+ function Zo(e, t, n) {
1755
+ const r = e.lastTickAt !== null && t - e.lastTickAt > Xo;
1756
+ return e.lastTickAt = t, n ? r || e.unansweredSince === null ? (e.unansweredSince = t, !1) : t - e.unansweredSince > zo : (e.unansweredSince = null, !1);
1846
1757
  }
1847
- function ni(e, t) {
1758
+ function ea(e, t) {
1848
1759
  return e.lastPongAt === null ? void 0 : Math.max(0, t - e.lastPongAt);
1849
1760
  }
1850
- let S = null, H = null, Ee = null, $ = null, q = null;
1851
- const ri = ai(), Z = Zo();
1852
- let _e = null, $e = null, Ot = 0, dt = null, ue = !1, ut = !1, oe = !1, Cn = null;
1853
- function oi(e) {
1761
+ let S = null, H = null, Ee = null, $ = null, K = null;
1762
+ const ta = oa(), Z = Jo();
1763
+ let _e = null, $e = null, Dt = 0, dt = null, ue = !1, ut = !1, oe = !1, In = null;
1764
+ function na(e) {
1854
1765
  const t = ne(), n = u.getState();
1855
1766
  if (n.me.clientId && n.roster[n.me.clientId])
1856
1767
  return (e.name || e.sprite) && (d("socket", "Identity update (already joined)", { name: e.name, sprite: e.sprite }), t.emit(w.IDENTITY_UPDATE, { name: e.name, sprite: e.sprite })), t;
1857
- const o = ii(e);
1858
- return q = o, dt = { name: o.name, sprite: o.sprite }, t.connected ? (d("socket", "Emitting join", o), t.emit(w.JOIN, o)) : t.once("connect", () => {
1859
- d("socket", "Emitting join", o), t.emit(w.JOIN, o);
1768
+ const r = ra(e);
1769
+ return K = r, dt = { name: r.name, sprite: r.sprite }, t.connected ? (d("socket", "Emitting join", r), t.emit(w.JOIN, r)) : t.once("connect", () => {
1770
+ d("socket", "Emitting join", r), t.emit(w.JOIN, r);
1860
1771
  }), t;
1861
1772
  }
1862
- function ii(e) {
1773
+ function ra(e) {
1863
1774
  return {
1864
1775
  room_key: e.room_key,
1865
1776
  name: e.name,
1866
1777
  sprite: e.sprite,
1867
1778
  // Entry-path telemetry — see lib/embedContext.ts. Sent on every join AND
1868
1779
  // rejoin (lastJoinPayload carries it), so a reconnect keeps the attribution.
1869
- embed: $o(),
1780
+ embed: Fo(),
1870
1781
  delivery_arm: Vo(),
1871
1782
  // Identity tier input — see lib/deviceId.ts. Sent on every join AND rejoin
1872
1783
  // (lastJoinPayload carries it) so a reconnect lands on the same
1873
1784
  // ParticipantId rather than minting a new person.
1874
- device_id: zo(),
1875
- tab_id: ri
1785
+ device_id: Wo(),
1786
+ tab_id: ta
1876
1787
  };
1877
1788
  }
1878
- function ai() {
1789
+ function oa() {
1879
1790
  const e = globalThis.crypto;
1880
1791
  if (e && typeof e.randomUUID == "function") return e.randomUUID();
1881
1792
  const t = new Uint8Array(16);
@@ -1887,63 +1798,63 @@ function ne() {
1887
1798
  if (!S) {
1888
1799
  let t = me().serverOrigin || "/";
1889
1800
  if (t === "/" && typeof window < "u") {
1890
- const o = window.location;
1891
- (o.hostname === "localhost" || o.hostname === "127.0.0.1") && o.port === String(Wt) && (t = `${o.protocol}//${o.hostname}:${Qe}`, d("socket", "Using dev fallback origin", { origin: t }));
1801
+ const r = window.location;
1802
+ (r.hostname === "localhost" || r.hostname === "127.0.0.1") && r.port === String(qt) && (t = `${r.protocol}//${r.hostname}:${Qe}`, d("socket", "Using dev fallback origin", { origin: t }));
1892
1803
  }
1893
1804
  const n = new URL(t.startsWith("http") ? t : `${window.location.origin}${t}`).origin;
1894
- S = Kn(n, { path: zn, transports: ["websocket", "polling"] }), d("socket", "Socket initialized", { origin: t }), Ue("__SOCKET__", S), $ && (clearTimeout($), $ = null), H = null, Ee = setInterval(() => {
1895
- if (ti(Z, Date.now(), !!S?.connected)) {
1896
- k("socket", "PONG-WATCHDOG no time_pong for 20s — replacing the connection", {
1805
+ S = Gn(n, { path: Yn, transports: ["websocket", "polling"] }), d("socket", "Socket initialized", { origin: t }), Ue("__SOCKET__", S), $ && (clearTimeout($), $ = null), H = null, Ee = setInterval(() => {
1806
+ if (Zo(Z, Date.now(), !!S?.connected)) {
1807
+ A("socket", "PONG-WATCHDOG no time_pong for 20s — replacing the connection", {
1897
1808
  sid: S?.id,
1898
- lastPongAgeMs: ni(Z, Date.now()) ?? null
1809
+ lastPongAgeMs: ea(Z, Date.now()) ?? null
1899
1810
  }), $e = "pong-watchdog", Z.unansweredSince = null, S?.io.engine?.close();
1900
1811
  return;
1901
1812
  }
1902
- bi();
1903
- }, gr), S.on("connect", () => {
1813
+ ha();
1814
+ }, fr), S.on("connect", () => {
1904
1815
  ut = !1;
1905
- const o = S?.id;
1906
- if (d("socket", "Connected", { id: o, isReconnect: oe }), o)
1816
+ const r = S?.id;
1817
+ if (d("socket", "Connected", { id: r, isReconnect: oe }), r)
1907
1818
  try {
1908
- u.getState().ensureMe(o), u.setState((i) => ({ me: { ...i.me, nextClientSeq: 1 } })), d("socket", "Reset client sequence for new connection");
1909
- } catch (i) {
1910
- ke("socket", "Failed to initialize store on connect", { error: i.message, sid: o });
1819
+ u.getState().ensureMe(r), u.setState((a) => ({ me: { ...a.me, nextClientSeq: 1 } })), d("socket", "Reset client sequence for new connection");
1820
+ } catch (a) {
1821
+ Ae("socket", "Failed to initialize store on connect", { error: a.message, sid: r });
1911
1822
  }
1912
- if (oe && q) {
1913
- const i = u.getState();
1914
- Ot += 1;
1915
- const a = {
1916
- ...q,
1917
- name: i.name,
1918
- sprite: i.sprite,
1823
+ if (oe && K) {
1824
+ const a = u.getState();
1825
+ Dt += 1;
1826
+ const i = {
1827
+ ...K,
1828
+ name: a.name,
1829
+ sprite: a.sprite,
1919
1830
  reconnect: {
1920
- count: Ot,
1831
+ count: Dt,
1921
1832
  reason: (_e?.reason ?? "unknown").slice(0, 64),
1922
1833
  offline_ms: _e ? Math.max(0, Date.now() - _e.at) : 0
1923
1834
  }
1924
- }, s = Cn;
1925
- if (d("socket", "Re-emitting join after reconnect", { room_key: a.room_key, name: a.name, sprite: a.sprite }), s) {
1835
+ }, s = In;
1836
+ if (d("socket", "Re-emitting join after reconnect", { room_key: i.room_key, name: i.name, sprite: i.sprite }), s) {
1926
1837
  let l = !1;
1927
1838
  const p = () => {
1928
1839
  l || (l = !0, S.off(w.SNAPSHOT, p), S.emit(w.CLIENT_READY, { media_id: s }), d("socket", "Re-emitted client_ready after reconnect snapshot", { mediaId: s }));
1929
1840
  };
1930
1841
  S.on(w.SNAPSHOT, p), setTimeout(() => {
1931
- l || (l = !0, S.off(w.SNAPSHOT, p), k("socket", "client_ready re-emit timed out waiting for snapshot", { mediaId: s }));
1842
+ l || (l = !0, S.off(w.SNAPSHOT, p), A("socket", "client_ready re-emit timed out waiting for snapshot", { mediaId: s }));
1932
1843
  }, 1e4);
1933
1844
  }
1934
- dt = { name: a.name, sprite: a.sprite }, S.emit(w.JOIN, a), window.dispatchEvent(new CustomEvent("watchparty:socket-reconnect"));
1935
- } else oe && k("socket", "Reconnected — no join payload, not re-joining any room");
1845
+ dt = { name: i.name, sprite: i.sprite }, S.emit(w.JOIN, i), window.dispatchEvent(new CustomEvent("watchparty:socket-reconnect"));
1846
+ } else oe && A("socket", "Reconnected — no join payload, not re-joining any room");
1936
1847
  oe = !0;
1937
- }), S.on("disconnect", (o) => {
1938
- pn(null), _e = { reason: $e ?? o, at: Date.now() }, $e = null, d("socket", "Disconnected", { reason: o });
1939
- }), S.on("connect_error", (o) => ke("socket", "Connection error", { message: o?.message })), S.on("reconnect_attempt", (o) => k("socket", "Reconnect attempt", { attempt: o })), S.on("reconnect_failed", () => ke("socket", "Reconnect failed")), hi(S);
1848
+ }), S.on("disconnect", (r) => {
1849
+ fn(null), _e = { reason: $e ?? r, at: Date.now() }, $e = null, d("socket", "Disconnected", { reason: r });
1850
+ }), S.on("connect_error", (r) => Ae("socket", "Connection error", { message: r?.message })), S.on("reconnect_attempt", (r) => A("socket", "Reconnect attempt", { attempt: r })), S.on("reconnect_failed", () => Ae("socket", "Reconnect failed")), fa(S);
1940
1851
  }
1941
1852
  return S;
1942
1853
  }
1943
1854
  function Be(e) {
1944
1855
  return e.play_state === "playing" || e.playing === !0;
1945
1856
  }
1946
- function Mt(e, t) {
1857
+ function Ot(e, t) {
1947
1858
  return {
1948
1859
  id: String(e.id ?? e.server_seq ?? t ?? `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`),
1949
1860
  clientId: e.client_id,
@@ -1955,14 +1866,14 @@ function Mt(e, t) {
1955
1866
  // Attachments arrive from other clients, so the key shape is re-checked
1956
1867
  // here at the boundary rather than trusted at render time. A malformed
1957
1868
  // entry is dropped, not rendered and not allowed near an <img src>.
1958
- images: Array.isArray(e.images) ? e.images.filter((n) => !!n && Je(n.key)).slice(0, V) : void 0,
1869
+ images: Array.isArray(e.images) ? e.images.filter((n) => !!n && Je(n.key)).slice(0, W) : void 0,
1959
1870
  isSystem: e.isSystem || !1,
1960
1871
  systemType: e.systemType
1961
1872
  };
1962
1873
  }
1963
- function si(e) {
1874
+ function aa(e) {
1964
1875
  e.on(w.SNAPSHOT, (t) => {
1965
- e.emit(Qt.SYNC), u.getState().applySnapshot({
1876
+ e.emit(Jt.SYNC), u.getState().applySnapshot({
1966
1877
  roomId: t.room_id ?? null,
1967
1878
  mediaId: t.media_id ?? null,
1968
1879
  playheadMs: t.playhead_ms || 0,
@@ -1970,9 +1881,9 @@ function si(e) {
1970
1881
  serverSeq: t.server_seq || 0,
1971
1882
  leaderId: t.leader_id || null
1972
1883
  }), u.getState().name || d("socket", "Deferring identity to presence event (snapshot carries no roster)");
1973
- const n = u.getState(), o = S?.id, a = (o ? n.roster[o] : void 0) ?? dt, s = qn(
1884
+ const n = u.getState(), r = S?.id, i = (r ? n.roster[r] : void 0) ?? dt, s = Vn(
1974
1885
  { name: n.name, avatarId: n.sprite },
1975
- a ? { name: a.name, avatarId: a.sprite ?? null } : void 0,
1886
+ i ? { name: i.name, avatarId: i.sprite ?? null } : void 0,
1976
1887
  // A join that carried no name counts as a default one, so a name that
1977
1888
  // landed after the join (prefs) is still asserted.
1978
1889
  (l) => l === "" || J(l)
@@ -1991,12 +1902,12 @@ function si(e) {
1991
1902
  leaderId: t.leader_id || null,
1992
1903
  serverSeq: t.server_seq || 0,
1993
1904
  rosterSize: Object.keys(n.roster).length
1994
- }), q?.room_key && S?.id && pn({ room_key: q.room_key, client_id: S.id });
1905
+ }), K?.room_key && S?.id && fn({ room_key: K.room_key, client_id: S.id });
1995
1906
  }), e.on(w.CONTROL_BROADCAST, (t) => {
1996
1907
  const n = u.getState();
1997
1908
  if (Object.prototype.hasOwnProperty.call(t, "media_id")) {
1998
- const o = t.media_id ?? null;
1999
- n.snapshot.mediaId !== o && (n.applySnapshot({ mediaId: o }), o && n.setReadiness({ mediaId: o, ready: !1, readyCount: 0, total: 0 }), n.bumpLoadGeneration());
1909
+ const r = t.media_id ?? null;
1910
+ n.snapshot.mediaId !== r && (n.applySnapshot({ mediaId: r }), r && n.setReadiness({ mediaId: r, ready: !1, readyCount: 0, total: 0 }), n.bumpLoadGeneration());
2000
1911
  }
2001
1912
  n.updateControlState({
2002
1913
  playheadMs: t.playhead_ms,
@@ -2013,23 +1924,23 @@ function si(e) {
2013
1924
  }), e.on(w.CONTROL_ACK, (t) => {
2014
1925
  typeof t?.client_seq == "number" && typeof t?.server_seq == "number" && d("socket", "Control ack received", t);
2015
1926
  }), e.on(w.TIME_PONG, (t) => {
2016
- if (ei(Z, Date.now()), H && H.ts) {
1927
+ if (Qo(Z, Date.now()), H && H.ts) {
2017
1928
  const n = Date.now() - H.ts;
2018
1929
  u.getState().addRttSample(n, t?.server_ts, H.ts), H = null, $ && (clearTimeout($), $ = null), d("socket", "Time sync RTT", { rtt: n, offset: u.getState().drift.offsetMs });
2019
1930
  }
2020
1931
  }), e.on(w.READY_STATE, (t) => {
2021
1932
  if (!t) return;
2022
- const n = t.media_id ?? null, o = typeof t.ready_count == "number" ? t.ready_count : 0, i = typeof t.total == "number" ? t.total : 0, a = t.ready === !0;
2023
- u.getState().setReadiness({ mediaId: n, ready: a, readyCount: o, total: i }), d("socket", "Ready state received", { mediaId: n, readyCount: o, total: i, ready: a });
1933
+ const n = t.media_id ?? null, r = typeof t.ready_count == "number" ? t.ready_count : 0, a = typeof t.total == "number" ? t.total : 0, i = t.ready === !0;
1934
+ u.getState().setReadiness({ mediaId: n, ready: i, readyCount: r, total: a }), d("socket", "Ready state received", { mediaId: n, readyCount: r, total: a, ready: i });
2024
1935
  });
2025
1936
  }
2026
- function li(e) {
1937
+ function ia(e) {
2027
1938
  e.on(w.PRESENCE, (t) => {
2028
1939
  if (!t) return;
2029
1940
  if (Array.isArray(t.users)) {
2030
- const o = {};
1941
+ const r = {};
2031
1942
  for (const l of t.users)
2032
- o[l.client_id] = {
1943
+ r[l.client_id] = {
2033
1944
  clientId: l.client_id,
2034
1945
  ...l.author ? { author: l.author } : {},
2035
1946
  name: l.name || "Anon",
@@ -2038,14 +1949,14 @@ function li(e) {
2038
1949
  ...l.registry_name ? { registryName: !0 } : {},
2039
1950
  ...l.avatar_url ? { avatarUrl: l.avatar_url } : {}
2040
1951
  };
2041
- const i = u.getState(), a = S?.id, s = a ? o[a] : void 0;
1952
+ const a = u.getState(), i = S?.id, s = i ? r[i] : void 0;
2042
1953
  if (s?.registryName)
2043
- u.setState({ roster: o }), (s.name !== i.name || s.sprite && s.sprite !== i.sprite) && (d("socket", "Adopting registry name", { from: i.name, to: s.name }), u.getState().setSessionIdentity(s.name, s.sprite ?? i.sprite));
2044
- else if (a && o[a]) {
2045
- const l = o[a].name, p = o[a].sprite;
2046
- if (i.name && !J(i.name) && (o[a].name = i.name), u.setState({ roster: o }), p && p !== i.sprite) {
2047
- const h = i.name && !J(i.name), f = h ? i.name : de(p);
2048
- d("socket", "Server reassigned sprite", { from: i.sprite, to: p, newName: f, preservingCustomName: h }), u.getState().setSessionIdentity(f, p), f !== l && e.emit(w.IDENTITY_UPDATE, { name: f });
1954
+ u.setState({ roster: r }), (s.name !== a.name || s.sprite && s.sprite !== a.sprite) && (d("socket", "Adopting registry name", { from: a.name, to: s.name }), u.getState().setSessionIdentity(s.name, s.sprite ?? a.sprite));
1955
+ else if (i && r[i]) {
1956
+ const l = r[i].name, p = r[i].sprite;
1957
+ if (a.name && !J(a.name) && (r[i].name = a.name), u.setState({ roster: r }), p && p !== a.sprite) {
1958
+ const h = a.name && !J(a.name), f = h ? a.name : de(p);
1959
+ d("socket", "Server reassigned sprite", { from: a.sprite, to: p, newName: f, preservingCustomName: h }), u.getState().setSessionIdentity(f, p), f !== l && e.emit(w.IDENTITY_UPDATE, { name: f });
2049
1960
  }
2050
1961
  }
2051
1962
  }
@@ -2053,89 +1964,89 @@ function li(e) {
2053
1964
  const n = u.getState();
2054
1965
  if (!n.name) {
2055
1966
  n.ensureAutoIdentity?.();
2056
- const o = u.getState();
2057
- o.name && (d("socket", "Auto-assigned identity on presence", { name: o.name, sprite: o.sprite }), e.emit(w.IDENTITY_UPDATE, { name: o.name, sprite: o.sprite || void 0 }));
1967
+ const r = u.getState();
1968
+ r.name && (d("socket", "Auto-assigned identity on presence", { name: r.name, sprite: r.sprite }), e.emit(w.IDENTITY_UPDATE, { name: r.name, sprite: r.sprite || void 0 }));
2058
1969
  }
2059
1970
  });
2060
1971
  }
2061
- function ci(e) {
1972
+ function sa(e) {
2062
1973
  e.on(w.CHAT_BROADCAST, (t) => {
2063
- const n = Mt(t, t.server_seq);
1974
+ const n = Ot(t, t.server_seq);
2064
1975
  u.getState().appendChat(n), d("chat", "Message received", n);
2065
1976
  }), e.on(w.CHAT_HISTORY, (t) => {
2066
1977
  if (!t?.messages || !Array.isArray(t.messages)) return;
2067
- const n = t.messages.map((o) => Mt(o));
1978
+ const n = t.messages.map((r) => Ot(r));
2068
1979
  u.getState().setChat(n), d("chat", "History loaded", { count: n.length });
2069
1980
  });
2070
1981
  }
2071
- function di(e) {
2072
- e.on(be.STATE, (t) => {
1982
+ function la(e) {
1983
+ e.on(ye.STATE, (t) => {
2073
1984
  u.getState().applyPlaylistState({
2074
1985
  playlist: t?.playlist ?? null,
2075
1986
  activeIndex: t?.activeIndex ?? null,
2076
1987
  myVotes: t?.myVotes ?? {}
2077
1988
  }), d("playlist", "Playlist state received", { playlistId: t?.playlist?.id ?? null, activeIndex: t?.activeIndex, myVoteCount: Object.keys(t?.myVotes || {}).length });
2078
- }), e.on(be.VOTE_PROGRESS, (t) => {
1989
+ }), e.on(ye.VOTE_PROGRESS, (t) => {
2079
1990
  u.getState().setVoteProgress(t?.progress ?? []), d("playlist", "Vote progress", { progressCount: t?.progress?.length });
2080
- }), e.on(be.RESULTS, (t) => {
1991
+ }), e.on(ye.RESULTS, (t) => {
2081
1992
  u.getState().setPlaylistResults(t ?? null), d("playlist", "Results received", { playlistId: t?.playlist?.id, update: t?.update === !0 });
2082
- }), e.on(be.VOTES_CLEARED, (t) => {
1993
+ }), e.on(ye.VOTES_CLEARED, (t) => {
2083
1994
  if (!t?.playlistId || !Array.isArray(t.mediaIds)) return;
2084
- const n = Xo(
2085
- { id: t.playlistId, videos: t.mediaIds.map((i) => ({ mediaId: i })) },
2086
- bo()
2087
- ), o = u.getState();
2088
- o.playlist?.id === t.playlistId && o.applyPlaylistState({ playlist: o.playlist, activeIndex: o.activePlaylistIndex, myVotes: {} }), d("playlist", "Votes cleared by leader", { playlistId: t.playlistId, removed: n });
1995
+ const n = Yo(
1996
+ { id: t.playlistId, videos: t.mediaIds.map((a) => ({ mediaId: a })) },
1997
+ ho()
1998
+ ), r = u.getState();
1999
+ r.playlist?.id === t.playlistId && r.applyPlaylistState({ playlist: r.playlist, activeIndex: r.activePlaylistIndex, myVotes: {} }), d("playlist", "Votes cleared by leader", { playlistId: t.playlistId, removed: n });
2089
2000
  });
2090
2001
  }
2091
- function ui(e) {
2092
- e.on(lr.UPDATED, () => {
2093
- d("tierlist", "Someone saved — refreshing the board"), Oo(!1);
2002
+ function ca(e) {
2003
+ e.on(sr.UPDATED, () => {
2004
+ d("tierlist", "Someone saved — refreshing the board"), Ro(!1);
2094
2005
  });
2095
2006
  }
2096
- function mi(e) {
2097
- e.on(cr.STATE, (t) => {
2007
+ function da(e) {
2008
+ e.on(lr.STATE, (t) => {
2098
2009
  if (!t || typeof t.active != "boolean") return;
2099
- const n = Array.isArray(t.ready) ? t.ready.filter((o) => typeof o == "string") : [];
2010
+ const n = Array.isArray(t.ready) ? t.ready.filter((r) => typeof r == "string") : [];
2100
2011
  u.getState().setReadyCheckState({ active: t.active, ready: n }), d("ready-check", "State received", { active: t.active, readyCount: n.length });
2101
2012
  });
2102
2013
  }
2103
- function fi(e) {
2104
- e.on(Qt.ACTIVE, (t) => {
2014
+ function ua(e) {
2015
+ e.on(Jt.ACTIVE, (t) => {
2105
2016
  const n = typeof t?.gameId == "string" ? t.gameId : null;
2106
- u.getState().setActiveGameId(n), t?.sessionWins && typeof t.sessionWins == "object" ? u.getState().setGameSessionWins(t.sessionWins) : n === null && u.getState().setGameSessionWins({}), typeof t?.botCount == "number" ? u.getState().setGameBotCount(t.botCount) : n === null && u.getState().setGameBotCount(0), d("game", "game_active", { gameId: n, sessionWins: t?.sessionWins, botCount: t?.botCount });
2017
+ u.getState().setActiveGameId(n), d("game", "game_active", { gameId: n });
2107
2018
  });
2108
2019
  }
2109
- function pi(e) {
2020
+ function ma(e) {
2110
2021
  e.on(w.HEALTH_SNAPSHOT, (t) => {
2111
2022
  u.getState().setHealthSnapshot(t);
2112
2023
  }), e.on(w.BUFFER_STATUS, (t) => {
2113
2024
  u.getState().setBufferStatus(t);
2114
2025
  });
2115
2026
  }
2116
- function hi(e) {
2117
- si(e), li(e), ci(e), pi(e), di(e), ui(e), mi(e), fi(e), e.on(w.ERROR, (t) => {
2027
+ function fa(e) {
2028
+ aa(e), ia(e), sa(e), ma(e), la(e), ca(e), da(e), ua(e), e.on(w.ERROR, (t) => {
2118
2029
  const n = t?.code || "error/unknown";
2119
2030
  if (n === "conflict" && t?.message === "sprite_held_by_you") {
2120
2031
  ut = !0, d("socket", "sprite held by this account's other connection: keeping the server-assigned sprite");
2121
2032
  return;
2122
2033
  }
2123
2034
  if (n === "conflict" && t?.message === "sprite_taken") {
2124
- if (jo(S?.id)) {
2035
+ if (Mo(S?.id)) {
2125
2036
  d("socket", "sprite_taken: stale, the server already has our sprite");
2126
2037
  return;
2127
2038
  }
2128
2039
  ue = !0;
2129
2040
  let s;
2130
2041
  try {
2131
- s = Lo();
2042
+ s = Oo();
2132
2043
  } finally {
2133
2044
  ue = !1;
2134
2045
  }
2135
2046
  s && e.emit(w.IDENTITY_UPDATE, s);
2136
2047
  return;
2137
2048
  }
2138
- const i = {
2049
+ const a = {
2139
2050
  "control/forbidden": "You are not the leader.",
2140
2051
  "control/stale_seq": "Stale control sequence.",
2141
2052
  "control/seq_gap": "Control sequence gap detected.",
@@ -2153,55 +2064,55 @@ function hi(e) {
2153
2064
  "recap/not_found": "No recap available for the previous episode."
2154
2065
  }[n] || n;
2155
2066
  if (n.startsWith("recap/")) {
2156
- d("socket", `recap unavailable: ${i}`, { code: n }), u.getState().pushToast("info", i);
2067
+ d("socket", `recap unavailable: ${a}`, { code: n }), u.getState().pushToast("info", a);
2157
2068
  return;
2158
2069
  }
2159
- (n.startsWith("auth/") ? k : ke)("socket", `Server error: ${i}`, { code: n, raw: t }), u.getState().pushToast("error", i);
2070
+ (n.startsWith("auth/") ? A : Ae)("socket", `Server error: ${a}`, { code: n, raw: t }), u.getState().pushToast("error", a);
2160
2071
  });
2161
2072
  }
2162
- function gi(e, t) {
2073
+ function pa(e, t) {
2163
2074
  ne().emit(w.CHAT_SEND, t?.length ? { text: e, images: t } : { text: e });
2164
2075
  }
2165
- function bi() {
2076
+ function ha() {
2166
2077
  H || (H = { ts: Date.now() }, ne().emit(w.TIME_PING, {}), $ = setTimeout(() => {
2167
2078
  H && (d("socket", "Time ping timed out after 10s, clearing inflight"), H = null), $ = null;
2168
2079
  }, 1e4));
2169
2080
  }
2170
- function Tn(e) {
2081
+ function Cn(e) {
2171
2082
  const t = u.getState(), n = t.me.clientId;
2172
2083
  if (!n || !t.roster[n]) {
2173
- Rt(e), d("socket", "Avatar change before join: the join will carry it", { sprite: e });
2084
+ Nt(e), d("socket", "Avatar change before join: the join will carry it", { sprite: e });
2174
2085
  return;
2175
2086
  }
2176
2087
  ue = !0;
2177
2088
  try {
2178
- Rt(e);
2089
+ Nt(e);
2179
2090
  } finally {
2180
2091
  ue = !1;
2181
2092
  }
2182
- const o = u.getState(), i = { avatar: !0 };
2183
- o.sprite && o.sprite !== t.sprite && (i.sprite = o.sprite), o.name && o.name !== t.name && (i.name = o.name), d("socket", "Sending avatar change", i), ne().emit(w.IDENTITY_UPDATE, i);
2093
+ const r = u.getState(), a = { avatar: !0 };
2094
+ r.sprite && r.sprite !== t.sprite && (a.sprite = r.sprite), r.name && r.name !== t.name && (a.name = r.name), d("socket", "Sending avatar change", a), ne().emit(w.IDENTITY_UPDATE, a);
2184
2095
  }
2185
2096
  let we = { name: "", sprite: "" };
2186
2097
  u.subscribe((e, t) => {
2187
2098
  if (e.name === t.name && e.sprite === t.sprite || ue) return;
2188
2099
  const n = e.me.clientId;
2189
2100
  if (!n) return;
2190
- const o = e.roster[n];
2191
- if (!o) return;
2192
- const i = !!e.name && !J(e.name) && e.name !== we.name && (J(o.name || "") || o.name !== e.name), a = !!e.sprite && e.sprite !== we.sprite && o.sprite !== e.sprite;
2193
- if (!i && !a) return;
2101
+ const r = e.roster[n];
2102
+ if (!r) return;
2103
+ const a = !!e.name && !J(e.name) && e.name !== we.name && (J(r.name || "") || r.name !== e.name), i = !!e.sprite && e.sprite !== we.sprite && r.sprite !== e.sprite;
2104
+ if (!a && !i) return;
2194
2105
  const s = {};
2195
- i && (s.name = e.name, we.name = e.name), a && (s.sprite = e.sprite, we.sprite = e.sprite), d("socket", "Identity reassert (store change)", s), S?.connected ? S.emit(w.IDENTITY_UPDATE, s) : ne().emit(w.IDENTITY_UPDATE, s);
2106
+ a && (s.name = e.name, we.name = e.name), i && (s.sprite = e.sprite, we.sprite = e.sprite), d("socket", "Identity reassert (store change)", s), S?.connected ? S.emit(w.IDENTITY_UPDATE, s) : ne().emit(w.IDENTITY_UPDATE, s);
2196
2107
  });
2197
- function yi() {
2108
+ function ga() {
2198
2109
  Ee && (clearInterval(Ee), Ee = null), $ && (clearTimeout($), $ = null), H = null, Z.unansweredSince = null, Z.lastTickAt = null;
2199
2110
  }
2200
- function vi() {
2201
- d("socket", "clearJoinState called", { hadPayload: q !== null, room_key: q?.room_key }), q = null, oe = !1, Cn = null;
2111
+ function ya() {
2112
+ d("socket", "clearJoinState called", { hadPayload: K !== null, room_key: K?.room_key }), K = null, oe = !1, In = null;
2202
2113
  }
2203
- function Lt() {
2204
- d("socket", "leaveRoom called", { room_key: q?.room_key }), vi(), yi(), S && (S.disconnect(), S = null), u.setState({
2114
+ function Mt() {
2115
+ d("socket", "leaveRoom called", { room_key: K?.room_key }), ya(), ga(), S && (S.disconnect(), S = null), u.setState({
2205
2116
  me: { clientId: null, nextClientSeq: 1 },
2206
2117
  roster: {},
2207
2118
  snapshot: { roomId: null, mediaId: null, playheadMs: 0, playing: !1, serverSeq: 0, leaderId: null },
@@ -2213,54 +2124,53 @@ function Lt() {
2213
2124
  playlistResults: null,
2214
2125
  readiness: { mediaId: null, ready: !1, readyCount: 0, total: 0 },
2215
2126
  readyCheck: { active: !1, ready: [] },
2216
- activeGameId: null,
2217
- gameSessionWins: {}
2127
+ activeGameId: null
2218
2128
  });
2219
2129
  }
2220
- function Si() {
2130
+ function ba() {
2221
2131
  d("chat", "Emitting recap_request"), ne().emit("recap_request");
2222
2132
  }
2223
- function _i() {
2224
- D(() => Fo((e) => {
2225
- const t = xn(e);
2226
- d("avatar", "Avatar changed in the settings popout", { sprite: t, source: e.avatar?.source }), Tn(t);
2133
+ function va() {
2134
+ D(() => jo((e) => {
2135
+ const t = wn(e);
2136
+ d("avatar", "Avatar changed in the settings popout", { sprite: t, source: e.avatar?.source }), Cn(t);
2227
2137
  }), []);
2228
2138
  }
2229
- function wi(e, t) {
2139
+ function Sa(e, t) {
2230
2140
  if (t) {
2231
2141
  for (const n of Object.values(e))
2232
2142
  if (n.author === t && n.avatarUrl) return n.avatarUrl;
2233
2143
  }
2234
2144
  }
2235
- function kn({ sprite: e, url: t, alt: n = "", className: o, fallback: i }) {
2236
- const [a, s] = R(null);
2237
- if (t && t !== a)
2145
+ function Tn({ sprite: e, url: t, alt: n = "", className: r, fallback: a }) {
2146
+ const [i, s] = R(null);
2147
+ if (t && t !== i)
2238
2148
  return /* @__PURE__ */ c(
2239
2149
  "img",
2240
2150
  {
2241
2151
  src: t,
2242
2152
  alt: n,
2243
2153
  referrerPolicy: "no-referrer",
2244
- className: o,
2154
+ className: r,
2245
2155
  draggable: !1,
2246
2156
  onError: () => s(t)
2247
2157
  }
2248
2158
  );
2249
- const l = yo(e);
2250
- return l ? /* @__PURE__ */ c("img", { src: l, alt: n, crossOrigin: "anonymous", className: o, draggable: !1 }) : /* @__PURE__ */ c(le, { children: i });
2159
+ const l = go(e);
2160
+ return l ? /* @__PURE__ */ c("img", { src: l, alt: n, crossOrigin: "anonymous", className: r, draggable: !1 }) : /* @__PURE__ */ c(le, { children: a });
2251
2161
  }
2252
- function xi(e) {
2162
+ function _a(e) {
2253
2163
  return !(e.button !== 0 || e.ctrlKey || e.metaKey || e.shiftKey || e.altKey);
2254
2164
  }
2255
- function Ii({ src: e, title: t, onClose: n }) {
2165
+ function wa({ src: e, title: t, onClose: n }) {
2256
2166
  D(() => {
2257
- const a = (s) => {
2167
+ const i = (s) => {
2258
2168
  s.key === "Escape" && (s.stopPropagation(), n());
2259
2169
  };
2260
- return document.addEventListener("keydown", a, !0), () => document.removeEventListener("keydown", a, !0);
2170
+ return document.addEventListener("keydown", i, !0), () => document.removeEventListener("keydown", i, !0);
2261
2171
  }, [n]);
2262
- const o = zr(), i = typeof document > "u" ? null : document.fullscreenElement ?? o ?? document.body;
2263
- return i ? Vn(
2172
+ const r = Wr(), a = typeof document > "u" ? null : document.fullscreenElement ?? r ?? document.body;
2173
+ return a ? Kn(
2264
2174
  /* @__PURE__ */ _(
2265
2175
  "div",
2266
2176
  {
@@ -2276,7 +2186,7 @@ function Ii({ src: e, title: t, onClose: n }) {
2276
2186
  {
2277
2187
  src: e,
2278
2188
  alt: t ?? "",
2279
- onClick: (a) => a.stopPropagation(),
2189
+ onClick: (i) => i.stopPropagation(),
2280
2190
  className: "max-h-full max-w-full rounded object-contain shadow-2xl",
2281
2191
  "data-testid": "chat-image-lightbox-img"
2282
2192
  }
@@ -2295,82 +2205,82 @@ function Ii({ src: e, title: t, onClose: n }) {
2295
2205
  ]
2296
2206
  }
2297
2207
  ),
2298
- i
2208
+ a
2299
2209
  ) : null;
2300
2210
  }
2301
- const Ge = 240, Ci = 320;
2302
- function Ti({ image: e }) {
2303
- const [t, n] = R(!1), o = Pe(e.key);
2304
- if (!o) return null;
2305
- const i = e.w > 0 && e.h > 0, a = i ? Math.min(1, Ci / e.w, Ge / e.h) : 1;
2211
+ const Ge = 240, xa = 320;
2212
+ function Ia({ image: e }) {
2213
+ const [t, n] = R(!1), r = Pe(e.key);
2214
+ if (!r) return null;
2215
+ const a = e.w > 0 && e.h > 0, i = a ? Math.min(1, xa / e.w, Ge / e.h) : 1;
2306
2216
  return /* @__PURE__ */ _(le, { children: [
2307
2217
  /* @__PURE__ */ c(
2308
2218
  "a",
2309
2219
  {
2310
- href: o,
2220
+ href: r,
2311
2221
  target: "_blank",
2312
2222
  rel: "noreferrer noopener",
2313
2223
  className: "block max-w-full cursor-zoom-in",
2314
2224
  "data-testid": "chat-image",
2315
2225
  onClick: (s) => {
2316
- xi(s) && (s.preventDefault(), n(!0));
2226
+ _a(s) && (s.preventDefault(), n(!0));
2317
2227
  },
2318
2228
  children: /* @__PURE__ */ c(
2319
2229
  "img",
2320
2230
  {
2321
- src: o,
2231
+ src: r,
2322
2232
  alt: e.title ?? "",
2323
2233
  loading: "lazy",
2324
2234
  decoding: "async",
2325
- width: i ? Math.round(e.w * a) : void 0,
2326
- height: i ? Math.round(e.h * a) : void 0,
2235
+ width: a ? Math.round(e.w * i) : void 0,
2236
+ height: a ? Math.round(e.h * i) : void 0,
2327
2237
  className: "rounded border border-border-light object-contain bg-bg-alt/30",
2328
- style: i ? { aspectRatio: `${e.w} / ${e.h}`, maxWidth: "100%", maxHeight: Ge } : { maxWidth: "100%", maxHeight: Ge }
2238
+ style: a ? { aspectRatio: `${e.w} / ${e.h}`, maxWidth: "100%", maxHeight: Ge } : { maxWidth: "100%", maxHeight: Ge }
2329
2239
  }
2330
2240
  )
2331
2241
  }
2332
2242
  ),
2333
2243
  t && /* @__PURE__ */ c(
2334
- Ii,
2244
+ wa,
2335
2245
  {
2336
- src: o,
2246
+ src: r,
2337
2247
  title: e.title,
2338
2248
  onClose: () => n(!1)
2339
2249
  }
2340
2250
  )
2341
2251
  ] });
2342
2252
  }
2343
- function ki({ images: e }) {
2344
- return e?.length ? /* @__PURE__ */ c("div", { className: "flex flex-wrap gap-1 mt-1", "data-testid": "chat-images", children: e.map((t, n) => /* @__PURE__ */ c(Ti, { image: t }, `${t.key}-${n}`)) }) : null;
2253
+ function Ca({ images: e }) {
2254
+ return e?.length ? /* @__PURE__ */ c("div", { className: "flex flex-wrap gap-1 mt-1", "data-testid": "chat-images", children: e.map((t, n) => /* @__PURE__ */ c(Ia, { image: t }, `${t.key}-${n}`)) }) : null;
2345
2255
  }
2346
- function Ai(e, t) {
2256
+ function Ta(e, t) {
2347
2257
  return e.author && t.author ? e.author === t.author : !!t.clientId && e.clientId === t.clientId;
2348
2258
  }
2349
- function Ke(e) {
2259
+ function qe(e) {
2350
2260
  return new Date(e).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
2351
2261
  }
2352
- const Ei = Ht.memo(function({ message: t }) {
2353
- const n = u((l) => l.me.clientId), o = u((l) => l.me.clientId ? l.roster[l.me.clientId]?.author : void 0), i = Ai(t, { clientId: n, author: o }), a = u((l) => wi(l.roster, t.author));
2262
+ const Aa = Ft.memo(function({ message: t }) {
2263
+ const n = u((l) => l.me.clientId), r = u((l) => l.me.clientId ? l.roster[l.me.clientId]?.author : void 0), a = Ta(t, { clientId: n, author: r }), i = u((l) => Sa(l.roster, t.author));
2354
2264
  if (t.isSystem && t.systemType === "recap")
2355
2265
  return /* @__PURE__ */ c("div", { className: "px-2 py-1.5", children: /* @__PURE__ */ _("div", { className: "border-l-2 border-border-light pl-2.5 py-0.5", children: [
2356
2266
  /* @__PURE__ */ _("div", { className: "text-[10px] uppercase tracking-wide text-text-muted mb-0.5", children: [
2357
2267
  "Recap",
2358
- /* @__PURE__ */ c("span", { className: "ml-1.5 normal-case tracking-normal opacity-60", children: Ke(t.ts) })
2268
+ /* @__PURE__ */ c("span", { className: "ml-1.5 normal-case tracking-normal opacity-60", children: qe(t.ts) })
2359
2269
  ] }),
2360
2270
  /* @__PURE__ */ c("p", { className: "text-[13px] text-text-secondary leading-relaxed whitespace-pre-wrap break-words", children: t.text })
2361
2271
  ] }) });
2362
2272
  if (t.isSystem)
2363
2273
  return /* @__PURE__ */ _("div", { className: "px-2 py-0.5 text-[11px] text-text-muted italic text-center leading-tight", children: [
2364
2274
  t.text,
2365
- /* @__PURE__ */ c("span", { className: "ml-1 text-[10px] opacity-50", children: Ke(t.ts) })
2275
+ /* @__PURE__ */ c("span", { className: "ml-1 text-[10px] opacity-50", children: qe(t.ts) })
2366
2276
  ] });
2367
- const s = gn(t.sprite);
2368
- return /* @__PURE__ */ _("div", { className: `flex items-start gap-2 px-2 py-1 hover:bg-bg-card/20 ${i ? "bg-bg-card/30" : ""}`, children: [
2277
+ const s = hn(t.sprite);
2278
+ return /* @__PURE__ */ _("div", { className: `flex items-start gap-2 px-2 py-1 hover:bg-bg-card/20 ${a ? "bg-bg-card/30" : ""}`, children: [
2369
2279
  /* @__PURE__ */ c(
2370
- kn,
2280
+ Tn,
2371
2281
  {
2372
2282
  sprite: t.sprite,
2373
- url: a,
2283
+ url: i,
2374
2284
  alt: t.name,
2375
2285
  className: "w-8 h-8 rounded-full object-cover flex-shrink-0",
2376
2286
  fallback: /* @__PURE__ */ c("span", { className: "w-8 h-8 bg-bg-alt/50 rounded-full flex-shrink-0" })
@@ -2378,38 +2288,38 @@ const Ei = Ht.memo(function({ message: t }) {
2378
2288
  ),
2379
2289
  /* @__PURE__ */ _("div", { className: "flex-1 min-w-0 -mt-0.5", children: [
2380
2290
  /* @__PURE__ */ c("span", { className: "font-medium text-[13px]", style: { color: s }, children: t.name }),
2381
- /* @__PURE__ */ c("span", { className: "text-[10px] text-text-muted opacity-60 ml-1.5", children: Ke(t.ts) }),
2291
+ /* @__PURE__ */ c("span", { className: "text-[10px] text-text-muted opacity-60 ml-1.5", children: qe(t.ts) }),
2382
2292
  t.text && /* @__PURE__ */ c("p", { className: "text-[13px] text-text break-words leading-snug m-0", children: t.text }),
2383
- /* @__PURE__ */ c(ki, { images: t.images })
2293
+ /* @__PURE__ */ c(Ca, { images: t.images })
2384
2294
  ] })
2385
2295
  ] });
2386
2296
  });
2387
- function Pi() {
2388
- const e = u((i) => i.chat), t = z(null), n = z(!1), o = E(() => {
2389
- const i = t.current;
2390
- if (!i) return;
2391
- const { scrollHeight: a, scrollTop: s, clientHeight: l } = i, p = a - s - l;
2297
+ function ka() {
2298
+ const e = u((a) => a.chat), t = z(null), n = z(!1), r = E(() => {
2299
+ const a = t.current;
2300
+ if (!a) return;
2301
+ const { scrollHeight: i, scrollTop: s, clientHeight: l } = a, p = i - s - l;
2392
2302
  n.current = p > 40;
2393
2303
  }, []);
2394
2304
  return D(() => {
2395
- const i = t.current;
2396
- i && !n.current && i.scrollTo({ top: i.scrollHeight, behavior: "smooth" });
2305
+ const a = t.current;
2306
+ a && !n.current && a.scrollTo({ top: a.scrollHeight, behavior: "smooth" });
2397
2307
  }, [e.length]), /* @__PURE__ */ c(
2398
2308
  "div",
2399
2309
  {
2400
2310
  ref: t,
2401
- onScroll: o,
2311
+ onScroll: r,
2402
2312
  className: "flex-1 overflow-y-auto overflow-x-hidden chat-messages",
2403
- children: e.length === 0 ? /* @__PURE__ */ c("div", { className: "p-4 text-xs text-text-muted text-center", children: "No messages yet. Be the first to say something!" }) : /* @__PURE__ */ c(le, { children: e.map((i, a) => {
2404
- const s = a > 0 ? e[a - 1] : null, l = s && i.ts - s.ts > 1440 * 60 * 1e3;
2405
- return /* @__PURE__ */ _(Ht.Fragment, { children: [
2313
+ children: e.length === 0 ? /* @__PURE__ */ c("div", { className: "p-4 text-xs text-text-muted text-center", children: "No messages yet. Be the first to say something!" }) : /* @__PURE__ */ c(le, { children: e.map((a, i) => {
2314
+ const s = i > 0 ? e[i - 1] : null, l = s && a.ts - s.ts > 1440 * 60 * 1e3;
2315
+ return /* @__PURE__ */ _(Ft.Fragment, { children: [
2406
2316
  l && /* @__PURE__ */ _("div", { className: "flex items-center gap-2 px-4 py-2 my-1", children: [
2407
2317
  /* @__PURE__ */ c("div", { className: "flex-1 h-px bg-border" }),
2408
- /* @__PURE__ */ c("span", { className: "text-[10px] text-text-muted whitespace-nowrap", children: new Date(i.ts).toLocaleDateString([], { weekday: "short", month: "short", day: "numeric" }) }),
2318
+ /* @__PURE__ */ c("span", { className: "text-[10px] text-text-muted whitespace-nowrap", children: new Date(a.ts).toLocaleDateString([], { weekday: "short", month: "short", day: "numeric" }) }),
2409
2319
  /* @__PURE__ */ c("div", { className: "flex-1 h-px bg-border" })
2410
2320
  ] }),
2411
- /* @__PURE__ */ c(Ei, { message: i })
2412
- ] }, i.id);
2321
+ /* @__PURE__ */ c(Aa, { message: a })
2322
+ ] }, a.id);
2413
2323
  }) })
2414
2324
  }
2415
2325
  );
@@ -2435,49 +2345,49 @@ const mt = [
2435
2345
  scope: "local"
2436
2346
  }
2437
2347
  ], ee = "/";
2438
- function Ni(e) {
2348
+ function Ea(e) {
2439
2349
  if (!e.startsWith(ee)) return null;
2440
2350
  const t = e.slice(ee.length);
2441
2351
  return /\s/.test(t) ? null : t.toLowerCase();
2442
2352
  }
2443
- function Ri(e, t = mt) {
2353
+ function Pa(e, t = mt) {
2444
2354
  const n = e.toLowerCase();
2445
- if (!n) return [...t].sort((i, a) => i.name.localeCompare(a.name));
2446
- const o = [];
2447
- for (const i of t) {
2448
- const a = i.name.toLowerCase();
2449
- a.startsWith(n) ? o.push({ cmd: i, rank: 0 }) : a.includes(n) && o.push({ cmd: i, rank: 1 });
2355
+ if (!n) return [...t].sort((a, i) => a.name.localeCompare(i.name));
2356
+ const r = [];
2357
+ for (const a of t) {
2358
+ const i = a.name.toLowerCase();
2359
+ i.startsWith(n) ? r.push({ cmd: a, rank: 0 }) : i.includes(n) && r.push({ cmd: a, rank: 1 });
2450
2360
  }
2451
- return o.sort((i, a) => i.rank - a.rank || i.cmd.name.localeCompare(a.cmd.name)).map((i) => i.cmd);
2361
+ return r.sort((a, i) => a.rank - i.rank || a.cmd.name.localeCompare(i.cmd.name)).map((a) => a.cmd);
2452
2362
  }
2453
- function Di(e) {
2363
+ function Na(e) {
2454
2364
  return `${ee}${e.name} `;
2455
2365
  }
2456
- function We(e, t) {
2366
+ function Ve(e, t) {
2457
2367
  return t <= 0 ? 0 : (e % t + t) % t;
2458
2368
  }
2459
- function Oi(e, t = mt) {
2369
+ function Ra(e, t = mt) {
2460
2370
  const n = e.trim();
2461
2371
  if (!n) return null;
2462
2372
  if (!n.startsWith(ee)) return { kind: "chat", text: n };
2463
- const o = n.slice(ee.length), i = o.search(/\s/), a = (i === -1 ? o : o.slice(0, i)).toLowerCase(), s = i === -1 ? "" : o.slice(i).trim(), l = t.find((p) => p.name.toLowerCase() === a);
2373
+ const r = n.slice(ee.length), a = r.search(/\s/), i = (a === -1 ? r : r.slice(0, a)).toLowerCase(), s = a === -1 ? "" : r.slice(a).trim(), l = t.find((p) => p.name.toLowerCase() === i);
2464
2374
  return l ? { kind: "command", command: l, args: s } : { kind: "chat", text: n };
2465
2375
  }
2466
- function Mi(e, t) {
2376
+ function Da(e, t) {
2467
2377
  return e.requiresMedia && !t.hasMedia ? `${ee}${e.name} needs an episode loaded.` : null;
2468
2378
  }
2469
- function Li({
2379
+ function Oa({
2470
2380
  commands: e,
2471
2381
  activeIndex: t,
2472
2382
  hasMedia: n,
2473
- onPick: o,
2474
- onHover: i,
2475
- listboxId: a
2383
+ onPick: r,
2384
+ onHover: a,
2385
+ listboxId: i
2476
2386
  }) {
2477
2387
  return e.length === 0 ? null : /* @__PURE__ */ c(
2478
2388
  "ul",
2479
2389
  {
2480
- id: a,
2390
+ id: i,
2481
2391
  role: "listbox",
2482
2392
  "aria-label": "Slash commands",
2483
2393
  className: `absolute bottom-full left-0 right-0 z-30 max-h-56 overflow-y-auto
@@ -2488,14 +2398,14 @@ function Li({
2488
2398
  return /* @__PURE__ */ _(
2489
2399
  "li",
2490
2400
  {
2491
- id: `${a}-opt-${s.name}`,
2401
+ id: `${i}-opt-${s.name}`,
2492
2402
  role: "option",
2493
2403
  "aria-selected": h,
2494
2404
  "aria-disabled": p,
2495
2405
  onMouseDown: (f) => {
2496
- f.preventDefault(), o(s);
2406
+ f.preventDefault(), r(s);
2497
2407
  },
2498
- onMouseEnter: () => i(l),
2408
+ onMouseEnter: () => a(l),
2499
2409
  className: `px-3 py-1.5 cursor-pointer flex items-baseline gap-2 ${h ? "bg-bg-alt" : ""} ${p ? "opacity-50" : ""}`,
2500
2410
  children: [
2501
2411
  /* @__PURE__ */ c("span", { className: "text-sm font-semibold text-text shrink-0", children: s.usage }),
@@ -2508,16 +2418,16 @@ function Li({
2508
2418
  }
2509
2419
  );
2510
2420
  }
2511
- function ji({
2421
+ function Ma({
2512
2422
  pending: e,
2513
2423
  uploading: t,
2514
2424
  onRemove: n
2515
2425
  }) {
2516
- return e.length ? /* @__PURE__ */ c("div", { className: "flex flex-wrap gap-1.5 pb-1.5", "data-testid": "chat-attachment-strip", children: e.map((o) => /* @__PURE__ */ _("div", { className: "relative", children: [
2426
+ return e.length ? /* @__PURE__ */ c("div", { className: "flex flex-wrap gap-1.5 pb-1.5", "data-testid": "chat-attachment-strip", children: e.map((r) => /* @__PURE__ */ _("div", { className: "relative", children: [
2517
2427
  /* @__PURE__ */ c(
2518
2428
  "img",
2519
2429
  {
2520
- src: o.previewUrl,
2430
+ src: r.previewUrl,
2521
2431
  alt: "",
2522
2432
  className: `h-14 w-14 rounded border border-border-light object-cover ${t ? "opacity-50" : ""}`
2523
2433
  }
@@ -2526,58 +2436,58 @@ function ji({
2526
2436
  "button",
2527
2437
  {
2528
2438
  type: "button",
2529
- onClick: () => n(o.id),
2439
+ onClick: () => n(r.id),
2530
2440
  disabled: t,
2531
2441
  "aria-label": "Remove attachment",
2532
2442
  className: "absolute -right-1 -top-1 flex h-4 w-4 items-center justify-center rounded-full bg-bg-card border border-border-light text-[10px] text-text-secondary hover:bg-danger-bg hover:text-on-danger-bg disabled:opacity-50",
2533
2443
  children: "×"
2534
2444
  }
2535
2445
  )
2536
- ] }, o.id)) }) : null;
2446
+ ] }, r.id)) }) : null;
2537
2447
  }
2538
- function Ui() {
2539
- const [e, t] = R([]), [n, o] = R(!1), i = u((m) => m.pushToast), a = z(/* @__PURE__ */ new Set());
2448
+ function La() {
2449
+ const [e, t] = R([]), [n, r] = R(!1), a = u((m) => m.pushToast), i = z(/* @__PURE__ */ new Set());
2540
2450
  D(() => () => {
2541
- for (const m of a.current) URL.revokeObjectURL(m);
2542
- a.current.clear();
2451
+ for (const m of i.current) URL.revokeObjectURL(m);
2452
+ i.current.clear();
2543
2453
  }, []);
2544
2454
  const s = E((m) => {
2545
- Rr(m) && (URL.revokeObjectURL(m.previewUrl), a.current.delete(m.previewUrl));
2455
+ Pr(m) && (URL.revokeObjectURL(m.previewUrl), i.current.delete(m.previewUrl));
2546
2456
  }, []), l = E(async (m) => {
2547
2457
  if (!m.length) return;
2548
2458
  const v = [];
2549
- for (const y of m) {
2550
- const I = Or(y);
2459
+ for (const b of m) {
2460
+ const I = Rr(b);
2551
2461
  if (I) {
2552
- i("error", I);
2462
+ a("error", I);
2553
2463
  continue;
2554
2464
  }
2555
- const { w: g, h: A } = await jr(y), N = URL.createObjectURL(y);
2556
- a.current.add(N), v.push({
2465
+ const { w: g, h: k } = await Mr(b), N = URL.createObjectURL(b);
2466
+ i.current.add(N), v.push({
2557
2467
  kind: "file",
2558
2468
  id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
2559
- file: y,
2469
+ file: b,
2560
2470
  previewUrl: N,
2561
2471
  w: g,
2562
- h: A
2472
+ h: k
2563
2473
  });
2564
2474
  }
2565
- v.length && t((y) => {
2566
- const I = V - y.length;
2475
+ v.length && t((b) => {
2476
+ const I = W - b.length;
2567
2477
  if (I <= 0) {
2568
- i("info", `Up to ${V} images per message`);
2478
+ a("info", `Up to ${W} images per message`);
2569
2479
  for (const g of v) s(g);
2570
- return y;
2480
+ return b;
2571
2481
  }
2572
2482
  if (v.length > I) {
2573
- i("info", `Up to ${V} images per message`);
2483
+ a("info", `Up to ${W} images per message`);
2574
2484
  for (const g of v.slice(I)) s(g);
2575
2485
  }
2576
- return [...y, ...v.slice(0, I)];
2486
+ return [...b, ...v.slice(0, I)];
2577
2487
  });
2578
- }, [i, s]), p = E((m) => {
2488
+ }, [a, s]), p = E((m) => {
2579
2489
  const v = Pe(m.key);
2580
- v && (t((y) => y.length >= V ? (i("info", `Up to ${V} images per message`), y) : [...y, {
2490
+ v && (t((b) => b.length >= W ? (a("info", `Up to ${W} images per message`), b) : [...b, {
2581
2491
  kind: "remote",
2582
2492
  id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
2583
2493
  key: m.key,
@@ -2587,11 +2497,11 @@ function Ui() {
2587
2497
  w: m.width ?? 0,
2588
2498
  h: m.height ?? 0,
2589
2499
  title: m.title || void 0
2590
- }]), Le().catalogue(ln).recordUse(m.key));
2591
- }, [i]), h = E((m) => {
2500
+ }]), Le().catalogue(sn).recordUse(m.key));
2501
+ }, [a]), h = E((m) => {
2592
2502
  t((v) => {
2593
- const y = v.find((I) => I.id === m);
2594
- return y && s(y), v.filter((I) => I.id !== m);
2503
+ const b = v.find((I) => I.id === m);
2504
+ return b && s(b), v.filter((I) => I.id !== m);
2595
2505
  });
2596
2506
  }, [s]), f = E(() => {
2597
2507
  t((m) => {
@@ -2599,24 +2509,24 @@ function Ui() {
2599
2509
  return [];
2600
2510
  });
2601
2511
  }, [s]), L = E((m) => {
2602
- const v = Mr(m.clipboardData);
2512
+ const v = Dr(m.clipboardData);
2603
2513
  v.length && (m.preventDefault(), l(v));
2604
2514
  }, [l]), O = E((m) => {
2605
- const v = Lr(m.dataTransfer);
2515
+ const v = Or(m.dataTransfer);
2606
2516
  v.length && (m.preventDefault(), l(v));
2607
2517
  }, [l]), M = E((m) => {
2608
2518
  m.dataTransfer?.types?.includes("Files") && m.preventDefault();
2609
2519
  }, []), C = E(async () => {
2610
2520
  if (!e.length) return [];
2611
- o(!0);
2521
+ r(!0);
2612
2522
  try {
2613
- return await Fr(e);
2523
+ return await jr(e);
2614
2524
  } catch (m) {
2615
- return k("chat", "Image upload failed", Hr(m)), i("error", Dr(m)), null;
2525
+ return A("chat", "Image upload failed", Ur(m)), a("error", Nr(m)), null;
2616
2526
  } finally {
2617
- o(!1);
2527
+ r(!1);
2618
2528
  }
2619
- }, [e, i]);
2529
+ }, [e, a]);
2620
2530
  return {
2621
2531
  pending: e,
2622
2532
  uploading: n,
@@ -2630,41 +2540,41 @@ function Ui() {
2630
2540
  onDragOver: M
2631
2541
  };
2632
2542
  }
2633
- const jt = qt, Fi = Xn;
2634
- function Hi({ commands: e = mt }) {
2635
- const [t, n] = R(""), [o, i] = R(!1), [a, s] = R({ q: null, i: 0 }), [l, p] = R(!1), h = z(null), f = Pn(), [L, O] = R(!1), [M, C] = R(!1), m = Ui(), v = u((b) => b.snapshot.mediaId), y = u((b) => b.pushToast), I = u((b) => b.setTierlistOpen), g = !!v, A = Ni(t), N = Q(
2636
- () => A === null ? [] : Ri(A, e),
2637
- [A, e]
2638
- ), U = A !== null && !l && N.length > 0, F = a.q === A ? We(a.i, N.length) : 0, x = E(
2639
- (b) => s({ q: A, i: b }),
2640
- [A]
2641
- ), P = E((b, j) => {
2642
- const re = Mi(b, { hasMedia: g });
2543
+ const Lt = Vt, ja = zn;
2544
+ function Ua({ commands: e = mt }) {
2545
+ const [t, n] = R(""), [r, a] = R(!1), [i, s] = R({ q: null, i: 0 }), [l, p] = R(!1), h = z(null), f = En(), [L, O] = R(!1), [M, C] = R(!1), m = La(), v = u((y) => y.snapshot.mediaId), b = u((y) => y.pushToast), I = u((y) => y.setTierlistOpen), g = !!v, k = Ea(t), N = Q(
2546
+ () => k === null ? [] : Pa(k, e),
2547
+ [k, e]
2548
+ ), U = k !== null && !l && N.length > 0, F = i.q === k ? Ve(i.i, N.length) : 0, x = E(
2549
+ (y) => s({ q: k, i: y }),
2550
+ [k]
2551
+ ), P = E((y, j) => {
2552
+ const re = Da(y, { hasMedia: g });
2643
2553
  if (re) {
2644
- y("info", re);
2554
+ b("info", re);
2645
2555
  return;
2646
2556
  }
2647
- switch (b.name) {
2557
+ switch (y.name) {
2648
2558
  case "help":
2649
- y("info", e.map((An) => An.usage).join(" "));
2559
+ b("info", e.map((An) => An.usage).join(" "));
2650
2560
  break;
2651
2561
  case "recap":
2652
- Si();
2562
+ ba();
2653
2563
  break;
2654
2564
  case "tierlist":
2655
- Mo(), I(!0);
2565
+ Do(), I(!0);
2656
2566
  break;
2657
2567
  default:
2658
- y("info", `${b.usage} is not implemented yet.`);
2568
+ b("info", `${y.usage} is not implemented yet.`);
2659
2569
  }
2660
- }, [g, y, e, I]), T = E((b) => {
2661
- n(Di(b)), p(!1), h.current?.focus();
2662
- }, []), pe = E(async (b) => {
2663
- if (b.preventDefault(), o || m.uploading) return;
2664
- const j = Oi(t, e);
2570
+ }, [g, b, e, I]), T = E((y) => {
2571
+ n(Na(y)), p(!1), h.current?.focus();
2572
+ }, []), pe = E(async (y) => {
2573
+ if (y.preventDefault(), r || m.uploading) return;
2574
+ const j = Ra(t, e);
2665
2575
  if (!j && !m.pending.length) return;
2666
2576
  if (j?.kind === "command" && m.pending.length) {
2667
- y("info", "Send images on their own, not with a command.");
2577
+ b("info", "Send images on their own, not with a command.");
2668
2578
  return;
2669
2579
  }
2670
2580
  if (j?.kind === "command") {
@@ -2672,50 +2582,50 @@ function Hi({ commands: e = mt }) {
2672
2582
  return;
2673
2583
  }
2674
2584
  const re = await m.uploadPending();
2675
- re !== null && (gi(j?.text ?? "", re), n(""), m.clear(), i(!0), setTimeout(() => i(!1), Fi), !document.hidden && document.hasFocus() && h.current?.focus());
2676
- }, [t, o, P, m, y, e]), he = E((b) => {
2677
- if (b.key === "Escape" && U) {
2678
- b.preventDefault(), p(!0);
2585
+ re !== null && (pa(j?.text ?? "", re), n(""), m.clear(), a(!0), setTimeout(() => a(!1), ja), !document.hidden && document.hasFocus() && h.current?.focus());
2586
+ }, [t, r, P, m, b, e]), he = E((y) => {
2587
+ if (y.key === "Escape" && U) {
2588
+ y.preventDefault(), p(!0);
2679
2589
  return;
2680
2590
  }
2681
2591
  if (U) {
2682
- if (b.key === "ArrowDown")
2683
- b.preventDefault(), x(We(F + 1, N.length));
2684
- else if (b.key === "ArrowUp")
2685
- b.preventDefault(), x(We(F - 1, N.length));
2686
- else if (b.key === "Tab") {
2687
- b.preventDefault();
2592
+ if (y.key === "ArrowDown")
2593
+ y.preventDefault(), x(Ve(F + 1, N.length));
2594
+ else if (y.key === "ArrowUp")
2595
+ y.preventDefault(), x(Ve(F - 1, N.length));
2596
+ else if (y.key === "Tab") {
2597
+ y.preventDefault();
2688
2598
  const j = N[F];
2689
2599
  j && T(j);
2690
- } else if (b.key === "Enter") {
2691
- b.preventDefault();
2600
+ } else if (y.key === "Enter") {
2601
+ y.preventDefault();
2692
2602
  const j = N[F];
2693
2603
  j && T(j);
2694
2604
  }
2695
2605
  }
2696
2606
  }, [U, N, F, T, x]);
2697
2607
  D(() => {
2698
- const b = () => {
2608
+ const y = () => {
2699
2609
  document.hidden || !document.hasFocus() || (h.current?.focus(), h.current?.scrollIntoView({ block: "nearest" }));
2700
2610
  };
2701
- return window.addEventListener("watchparty:focus-chat-input", b), () => window.removeEventListener("watchparty:focus-chat-input", b);
2611
+ return window.addEventListener("watchparty:focus-chat-input", y), () => window.removeEventListener("watchparty:focus-chat-input", y);
2702
2612
  }, []);
2703
- const ge = jt - t.length, ft = ge <= 100, pt = U ? N[F] : void 0;
2613
+ const ge = Lt - t.length, ft = ge <= 100, pt = U ? N[F] : void 0;
2704
2614
  return /* @__PURE__ */ _(
2705
2615
  "form",
2706
2616
  {
2707
- onSubmit: (b) => {
2708
- pe(b);
2617
+ onSubmit: (y) => {
2618
+ pe(y);
2709
2619
  },
2710
2620
  onPaste: m.onPaste,
2711
2621
  onDrop: m.onDrop,
2712
2622
  onDragOver: m.onDragOver,
2713
2623
  className: "p-2 border-t border-border",
2714
2624
  children: [
2715
- /* @__PURE__ */ c(ji, { pending: m.pending, uploading: m.uploading, onRemove: m.remove }),
2625
+ /* @__PURE__ */ c(Ma, { pending: m.pending, uploading: m.uploading, onRemove: m.remove }),
2716
2626
  /* @__PURE__ */ _("div", { className: "relative", children: [
2717
2627
  U && /* @__PURE__ */ c(
2718
- Li,
2628
+ Oa,
2719
2629
  {
2720
2630
  commands: N,
2721
2631
  activeIndex: F,
@@ -2726,7 +2636,7 @@ function Hi({ commands: e = mt }) {
2726
2636
  }
2727
2637
  ),
2728
2638
  /* @__PURE__ */ c(
2729
- Wr,
2639
+ Gr,
2730
2640
  {
2731
2641
  open: L,
2732
2642
  onClose: () => O(!1),
@@ -2744,11 +2654,11 @@ function Hi({ commands: e = mt }) {
2744
2654
  ref: h,
2745
2655
  type: "text",
2746
2656
  value: t,
2747
- onChange: (b) => {
2748
- n(b.target.value), p(!1);
2657
+ onChange: (y) => {
2658
+ n(y.target.value), p(!1);
2749
2659
  },
2750
2660
  onKeyDown: he,
2751
- maxLength: jt,
2661
+ maxLength: Lt,
2752
2662
  placeholder: "Send a message",
2753
2663
  role: "combobox",
2754
2664
  "aria-expanded": U,
@@ -2764,13 +2674,13 @@ function Hi({ commands: e = mt }) {
2764
2674
  "button",
2765
2675
  {
2766
2676
  type: "button",
2767
- onClick: () => O((b) => !b),
2677
+ onClick: () => O((y) => !y),
2768
2678
  "aria-label": "Add a meme",
2769
2679
  "aria-expanded": L,
2770
2680
  title: "Add a meme",
2771
2681
  "data-testid": "meme-button",
2772
2682
  className: `shrink-0 rounded border border-border-light px-2 py-1.5 text-sm hover:border-primary ${L ? "text-text border-primary" : "text-text-secondary"}`,
2773
- children: /* @__PURE__ */ c(Nn, { name: "image" })
2683
+ children: /* @__PURE__ */ c(Pn, { name: "image" })
2774
2684
  }
2775
2685
  )
2776
2686
  ] })
@@ -2779,13 +2689,13 @@ function Hi({ commands: e = mt }) {
2779
2689
  }
2780
2690
  );
2781
2691
  }
2782
- function $i() {
2692
+ function Fa() {
2783
2693
  const e = u((n) => n.roster), t = Object.values(e);
2784
2694
  return t.length ? /* @__PURE__ */ c("div", { className: "flex flex-col gap-1", children: t.map((n) => {
2785
- const o = gn(n.sprite);
2695
+ const r = hn(n.sprite);
2786
2696
  return /* @__PURE__ */ _("div", { className: "flex items-center gap-2 py-0.5", children: [
2787
2697
  /* @__PURE__ */ c(
2788
- kn,
2698
+ Tn,
2789
2699
  {
2790
2700
  sprite: n.sprite,
2791
2701
  url: n.avatarUrl,
@@ -2794,20 +2704,20 @@ function $i() {
2794
2704
  fallback: /* @__PURE__ */ c("span", { className: "w-6 h-6 bg-bg-alt rounded-full flex-shrink-0" })
2795
2705
  }
2796
2706
  ),
2797
- /* @__PURE__ */ c("span", { className: "text-xs font-medium truncate", style: { color: o }, children: n.name || "Anon" }),
2707
+ /* @__PURE__ */ c("span", { className: "text-xs font-medium truncate", style: { color: r }, children: n.name || "Anon" }),
2798
2708
  n.isLeader && /* @__PURE__ */ c("span", { className: "ml-auto px-1.5 py-0.5 rounded text-[9px] font-medium bg-success/20 text-success", children: "Leader" })
2799
2709
  ] }, n.clientId);
2800
2710
  }) }) : /* @__PURE__ */ c("div", { className: "text-xs text-text-muted", children: "No users online" });
2801
2711
  }
2802
- function Bi() {
2803
- const e = u((i) => Object.keys(i.roster).length), [t, n] = R(!1), o = z(null);
2712
+ function Ha() {
2713
+ const e = u((a) => Object.keys(a.roster).length), [t, n] = R(!1), r = z(null);
2804
2714
  return D(() => {
2805
2715
  if (!t) return;
2806
- function i(a) {
2807
- o.current && !o.current.contains(a.target) && n(!1);
2716
+ function a(i) {
2717
+ r.current && !r.current.contains(i.target) && n(!1);
2808
2718
  }
2809
- return document.addEventListener("mousedown", i), () => document.removeEventListener("mousedown", i);
2810
- }, [t]), /* @__PURE__ */ _("div", { className: "relative", ref: o, children: [
2719
+ return document.addEventListener("mousedown", a), () => document.removeEventListener("mousedown", a);
2720
+ }, [t]), /* @__PURE__ */ _("div", { className: "relative", ref: r, children: [
2811
2721
  /* @__PURE__ */ _(
2812
2722
  "button",
2813
2723
  {
@@ -2827,105 +2737,105 @@ function Bi() {
2827
2737
  e,
2828
2738
  " online"
2829
2739
  ] }),
2830
- /* @__PURE__ */ c($i, {})
2740
+ /* @__PURE__ */ c(Fa, {})
2831
2741
  ] })
2832
2742
  ] });
2833
2743
  }
2834
- function Ut({ className: e = "fixed bottom-4 left-1/2 -translate-x-1/2" }) {
2835
- const t = u((o) => o.toasts), n = u((o) => o.popToast);
2744
+ function jt({ className: e = "fixed bottom-4 left-1/2 -translate-x-1/2" }) {
2745
+ const t = u((r) => r.toasts), n = u((r) => r.popToast);
2836
2746
  return D(() => {
2837
- const o = t.map((i) => setTimeout(() => n(i.id), 4e3));
2747
+ const r = t.map((a) => setTimeout(() => n(a.id), 4e3));
2838
2748
  return () => {
2839
- o.forEach(clearTimeout);
2749
+ r.forEach(clearTimeout);
2840
2750
  };
2841
- }, [t, n]), /* @__PURE__ */ c("div", { className: `${e} flex flex-col gap-2 z-50`, children: t.map((o) => /* @__PURE__ */ c("div", { className: `px-3 py-2 rounded text-sm shadow font-medium border ${o.kind === "error" ? "bg-danger-bg text-on-danger-bg border-danger" : "bg-bg-card border-border-light text-text"}`, children: o.msg }, o.id)) });
2751
+ }, [t, n]), /* @__PURE__ */ c("div", { className: `${e} flex flex-col gap-2 z-50`, children: t.map((r) => /* @__PURE__ */ c("div", { className: `px-3 py-2 rounded text-sm shadow font-medium border ${r.kind === "error" ? "bg-danger-bg text-on-danger-bg border-danger" : "bg-bg-card border-border-light text-text"}`, children: r.msg }, r.id)) });
2842
2752
  }
2843
- const Ft = (e) => typeof e == "string" && Rn.includes(e);
2844
- function Gi(e, t, n) {
2845
- return e || (Ft(t) ? t : Ft(n) ? n : "dark");
2753
+ const Ut = (e) => typeof e == "string" && Nn.includes(e);
2754
+ function $a(e, t, n) {
2755
+ return e || (Ut(t) ? t : Ut(n) ? n : "dark");
2846
2756
  }
2847
- function Ki(e, t) {
2757
+ function Ba(e, t) {
2848
2758
  if (t(e.clientWidth), typeof ResizeObserver > "u") return () => {
2849
2759
  };
2850
2760
  const n = new ResizeObserver(() => t(e.clientWidth));
2851
2761
  return n.observe(e), () => n.disconnect();
2852
2762
  }
2853
- function Wi(e) {
2763
+ function Ga(e) {
2854
2764
  const t = e?.trim() ?? "";
2855
2765
  return t ? { source: "host", name: t } : { source: "auto" };
2856
2766
  }
2857
- function qi(e) {
2767
+ function qa(e) {
2858
2768
  if (e.source !== "host") return;
2859
2769
  const { setSessionIdentity: t, sprite: n } = u.getState();
2860
2770
  t(e.name, n);
2861
2771
  }
2862
- function Vi({ className: e = "w-4 h-4" }) {
2772
+ function Va({ className: e = "w-4 h-4" }) {
2863
2773
  return /* @__PURE__ */ _("svg", { className: e, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: [
2864
2774
  /* @__PURE__ */ c("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 4v16" }),
2865
2775
  /* @__PURE__ */ c("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12l-5 4v-8l5 4z" })
2866
2776
  ] });
2867
2777
  }
2868
- function Yi({ className: e = "w-4 h-4" }) {
2778
+ function Ka({ className: e = "w-4 h-4" }) {
2869
2779
  return /* @__PURE__ */ _("svg", { className: e, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: [
2870
2780
  /* @__PURE__ */ c("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M20 4v16" }),
2871
2781
  /* @__PURE__ */ c("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 12l5 4v-8l-5 4z" })
2872
2782
  ] });
2873
2783
  }
2874
- const zi = 1500;
2875
- function ca({
2784
+ const Wa = 1500;
2785
+ function si({
2876
2786
  roomKey: e,
2877
2787
  serverOrigin: t,
2878
2788
  userType: n,
2879
- userId: o,
2880
- theme: i,
2881
- name: a,
2789
+ userId: r,
2790
+ theme: a,
2791
+ name: i,
2882
2792
  onLeave: s,
2883
2793
  onLayoutChange: l,
2884
2794
  collapsible: p = !0,
2885
2795
  debug: h,
2886
2796
  children: f
2887
2797
  }) {
2888
- const [L, O] = R(null), { setFrame: M, ...C } = Xi(l, p), m = Bt(() => a), v = Q(() => (go({ userType: n, userId: o ?? null }), lt().theme), [n, o]), y = Dn(), I = y?.theme, g = Q(
2889
- () => Gi(i, I, v),
2890
- [i, I, v]
2798
+ const [L, O] = R(null), { setFrame: M, ...C } = Ya(l, p), m = $t(() => i), v = Q(() => (po({ userType: n, userId: r ?? null }), lt().theme), [n, r]), b = Rn(), I = b?.theme, g = Q(
2799
+ () => $a(a, I, v),
2800
+ [a, I, v]
2891
2801
  );
2892
2802
  D(() => {
2893
- }, [i, y !== null]);
2803
+ }, [a, b !== null]);
2894
2804
  const N = Q(
2895
2805
  () => ({ ...rt, serverOrigin: t, defaultRoomKey: e }),
2896
2806
  [t, e]
2897
2807
  );
2898
2808
  return D(() => {
2899
- h && Qr();
2900
- }, [h]), _i(), D(() => {
2901
- qr({ serverOrigin: t, defaultRoomKey: e }), u.getState().rehydrateFromPrefs(), Yo();
2809
+ h && Xr();
2810
+ }, [h]), va(), D(() => {
2811
+ qr({ serverOrigin: t, defaultRoomKey: e }), u.getState().rehydrateFromPrefs(), Ko();
2902
2812
  let U = !1;
2903
- const F = vo();
2813
+ const F = yo();
2904
2814
  return (async () => {
2905
2815
  try {
2906
2816
  await Promise.race([
2907
2817
  Promise.all([
2908
2818
  F,
2909
- Co().then((T) => {
2819
+ xo().then((T) => {
2910
2820
  T && u.getState().rehydrateFromPrefs();
2911
2821
  }),
2912
2822
  // The character chosen in the settings popout (lib/avatar.ts).
2913
- Uo().then(Tn)
2823
+ Lo().then(Cn)
2914
2824
  ]),
2915
- new Promise((T) => setTimeout(T, zi))
2825
+ new Promise((T) => setTimeout(T, Wa))
2916
2826
  ]);
2917
2827
  } catch (T) {
2918
- k("room-chrome", "pre-join wait threw, proceeding anyway", fe(T));
2828
+ A("room-chrome", "pre-join wait threw, proceeding anyway", fe(T));
2919
2829
  }
2920
2830
  if (U) return;
2921
- const x = Wi(m());
2922
- u.getState().ensureAutoIdentity(), qi(x);
2831
+ const x = Ga(m());
2832
+ u.getState().ensureAutoIdentity(), qa(x);
2923
2833
  const P = u.getState();
2924
- d("room-chrome", "Joining room", { roomKey: e, name: P.name, sprite: P.sprite }), oi({ room_key: e, name: P.name || void 0, sprite: P.sprite || void 0 });
2834
+ d("room-chrome", "Joining room", { roomKey: e, name: P.name, sprite: P.sprite }), na({ room_key: e, name: P.name || void 0, sprite: P.sprite || void 0 });
2925
2835
  })(), () => {
2926
- U = !0, Lt();
2836
+ U = !0, Mt();
2927
2837
  };
2928
- }, [e, t, n, o]), /* @__PURE__ */ c(Vr.Provider, { value: N, children: /* @__PURE__ */ c(dn.Provider, { value: L, children: /* @__PURE__ */ _("div", { ref: M, className: "wp-room-chrome-frame", children: [
2838
+ }, [e, t, n, r]), /* @__PURE__ */ c(Vr.Provider, { value: N, children: /* @__PURE__ */ c(cn.Provider, { value: L, children: /* @__PURE__ */ _("div", { ref: M, className: "wp-room-chrome-frame", children: [
2929
2839
  /* @__PURE__ */ c("div", { className: "wp-room-chrome-frame__content", children: f }),
2930
2840
  /* @__PURE__ */ c(
2931
2841
  "aside",
@@ -2944,10 +2854,10 @@ function ca({
2944
2854
  title: "Show chat",
2945
2855
  "aria-label": "Show chat",
2946
2856
  "aria-expanded": !1,
2947
- children: /* @__PURE__ */ c(Yi, {})
2857
+ children: /* @__PURE__ */ c(Ka, {})
2948
2858
  }
2949
2859
  ),
2950
- /* @__PURE__ */ c(Ut, { className: "absolute bottom-2 right-full mr-2 w-72" })
2860
+ /* @__PURE__ */ c(jt, { className: "absolute bottom-2 right-full mr-2 w-72" })
2951
2861
  ] }) : /* @__PURE__ */ _(le, { children: [
2952
2862
  /* @__PURE__ */ c(
2953
2863
  "div",
@@ -2969,13 +2879,13 @@ function ca({
2969
2879
  }
2970
2880
  ),
2971
2881
  /* @__PURE__ */ _("div", { className: "flex items-center gap-1 px-2 py-1.5 border-b border-border", children: [
2972
- /* @__PURE__ */ c(Bi, {}),
2882
+ /* @__PURE__ */ c(Ha, {}),
2973
2883
  /* @__PURE__ */ c("div", { className: "flex-1" }),
2974
2884
  s && /* @__PURE__ */ c(
2975
2885
  "button",
2976
2886
  {
2977
2887
  onClick: () => {
2978
- Lt(), s();
2888
+ Mt(), s();
2979
2889
  },
2980
2890
  className: "wp-room-chrome__leave",
2981
2891
  title: "Leave room",
@@ -2991,25 +2901,25 @@ function ca({
2991
2901
  title: "Hide chat",
2992
2902
  "aria-label": "Hide chat",
2993
2903
  "aria-expanded": !0,
2994
- children: /* @__PURE__ */ c(Vi, {})
2904
+ children: /* @__PURE__ */ c(Va, {})
2995
2905
  }
2996
2906
  )
2997
2907
  ] }),
2998
- /* @__PURE__ */ c(Pi, {}),
2999
- /* @__PURE__ */ c(Hi, { commands: [] }),
3000
- /* @__PURE__ */ c(Ut, { className: "absolute bottom-14 left-2 right-2" })
2908
+ /* @__PURE__ */ c(ka, {}),
2909
+ /* @__PURE__ */ c(Ua, { commands: [] }),
2910
+ /* @__PURE__ */ c(jt, { className: "absolute bottom-14 left-2 right-2" })
3001
2911
  ] })
3002
2912
  }
3003
2913
  )
3004
2914
  ] }) }) });
3005
2915
  }
3006
- function Xi(e, t) {
3007
- const n = u((g) => g.chromeChatCollapsed) && t, o = u((g) => g.chromeChatWidth), i = u((g) => g.toggleChromeChatCollapsed), a = u((g) => g.setChromeChatWidth), [s, l] = R(null), [p, h] = R(void 0), [f, L] = R(null);
2916
+ function Ya(e, t) {
2917
+ const n = u((g) => g.chromeChatCollapsed) && t, r = u((g) => g.chromeChatWidth), a = u((g) => g.toggleChromeChatCollapsed), i = u((g) => g.setChromeChatWidth), [s, l] = R(null), [p, h] = R(void 0), [f, L] = R(null);
3008
2918
  D(() => {
3009
2919
  if (s)
3010
- return Ki(s, h);
2920
+ return Ba(s, h);
3011
2921
  }, [s]);
3012
- const O = W(f?.current ?? o, p), M = Q(() => Po(n, O), [n, O]), C = Bt((g) => e?.(g));
2922
+ const O = V(f?.current ?? r, p), M = Q(() => ko(n, O), [n, O]), C = $t((g) => e?.(g));
3013
2923
  return D(() => {
3014
2924
  C(M);
3015
2925
  }, [M]), {
@@ -3017,25 +2927,25 @@ function Xi(e, t) {
3017
2927
  collapsed: n,
3018
2928
  state: M,
3019
2929
  dragging: f !== null,
3020
- toggleCollapsed: i,
2930
+ toggleCollapsed: a,
3021
2931
  onPointerDown: (g) => {
3022
2932
  g.button === 0 && (g.preventDefault(), g.currentTarget.setPointerCapture(g.pointerId), L({ pointerId: g.pointerId, startX: g.clientX, startWidth: O, current: O }));
3023
2933
  },
3024
2934
  onPointerMove: (g) => {
3025
- !f || f.pointerId !== g.pointerId || L({ ...f, current: Et(f.startWidth, f.startX, g.clientX, p) });
2935
+ !f || f.pointerId !== g.pointerId || L({ ...f, current: kt(f.startWidth, f.startX, g.clientX, p) });
3026
2936
  },
3027
2937
  onPointerEnd: (g) => {
3028
2938
  if (!f || f.pointerId !== g.pointerId) return;
3029
- const A = Et(f.startWidth, f.startX, g.clientX, p);
3030
- L(null), A !== o && a(A);
2939
+ const k = kt(f.startWidth, f.startX, g.clientX, p);
2940
+ L(null), k !== r && i(k);
3031
2941
  },
3032
2942
  onKeyDown: (g) => {
3033
- const A = Eo(O, g.key, p);
3034
- A !== null && (g.preventDefault(), A !== o && a(A));
2943
+ const k = Ao(O, g.key, p);
2944
+ k !== null && (g.preventDefault(), k !== r && i(k));
3035
2945
  }
3036
2946
  };
3037
2947
  }
3038
2948
  export {
3039
- ca as RoomChrome
2949
+ si as RoomChrome
3040
2950
  };
3041
2951
  //# sourceMappingURL=room-chrome.js.map