@hadoku/watchparty-ui 0.44.13 → 0.44.18

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