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