live-quiz 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1772 @@
1
+ var Z = Object.defineProperty;
2
+ var ee = (n, e, t) => e in n ? Z(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t;
3
+ var A = (n, e, t) => ee(n, typeof e != "symbol" ? e + "" : e, t);
4
+ let j = () => ({
5
+ emit(n, ...e) {
6
+ for (let t = this.events[n] || [], s = 0, i = t.length; s < i; s++)
7
+ t[s](...e);
8
+ },
9
+ events: {},
10
+ on(n, e) {
11
+ var t;
12
+ return ((t = this.events)[n] || (t[n] = [])).push(e), () => {
13
+ var s;
14
+ this.events[n] = (s = this.events[n]) == null ? void 0 : s.filter((i) => e !== i);
15
+ };
16
+ }
17
+ });
18
+ class x extends Error {
19
+ constructor(e, t) {
20
+ e instanceof Error ? (super(e.message), this.cause = e) : super(e), this.reason = t, this.name = "ReasonError";
21
+ }
22
+ }
23
+ class G extends x {
24
+ constructor(e) {
25
+ super("Rejected", e), this.name = "SubscriptionRejectedError";
26
+ }
27
+ }
28
+ class te extends x {
29
+ constructor(e) {
30
+ super(e || "Timed out to receive subscription ack"), this.name = "SubscriptionTimeoutError";
31
+ }
32
+ }
33
+ class v extends x {
34
+ constructor(e, t) {
35
+ t ? super(e, t) : super("Disconnected", e), this.name = "DisconnectedError";
36
+ }
37
+ }
38
+ class se extends v {
39
+ constructor(e) {
40
+ super(e, "stale_connection"), this.name = "StaleConnectionError";
41
+ }
42
+ }
43
+ function W(n) {
44
+ return n ? `{${Object.keys(n).sort().filter((t) => n[t] !== void 0).map((t) => {
45
+ let s = JSON.stringify(n[t]);
46
+ return `${JSON.stringify(t)}:${s}`;
47
+ }).join(",")}}` : "";
48
+ }
49
+ class ie {
50
+ constructor(e) {
51
+ this.channel = e, this.listeners = [];
52
+ }
53
+ watch() {
54
+ this.listeners.push(
55
+ this.channel.on("presence", (e) => {
56
+ if (e.type === "info") {
57
+ this._state || (this._state = this.stateFromInfo(e));
58
+ return;
59
+ }
60
+ this._state && (e.type === "join" ? this._state[e.id] = e.info : e.type === "leave" && delete this._state[e.id]);
61
+ })
62
+ );
63
+ }
64
+ // Reset the state to make sure the fresh one is
65
+ // requested the next time info() is called
66
+ reset() {
67
+ delete this._state;
68
+ }
69
+ dispose() {
70
+ delete this._info, delete this._state, this.listeners.forEach((e) => e()), this.listeners.length = 0;
71
+ }
72
+ async join(e, t) {
73
+ if (!this._info)
74
+ return this._info = { id: String(e), info: t }, this.channel.perform("$presence:join", this._info);
75
+ }
76
+ async leave() {
77
+ if (!this._info) return;
78
+ let e = await this.channel.perform("$presence:leave");
79
+ return delete this._info, e;
80
+ }
81
+ async info() {
82
+ return this._state ? this._state : (this._promise || (this._promise = this._sync()), await this._promise, this._state);
83
+ }
84
+ async _sync() {
85
+ this.watch();
86
+ try {
87
+ let e = await this.channel.perform("$presence:info", {});
88
+ return this._state = this.stateFromInfo(e), this._state;
89
+ } finally {
90
+ delete this._promise;
91
+ }
92
+ }
93
+ stateFromInfo(e) {
94
+ return e.records ? e.records.reduce((t, { id: s, info: i }) => (t[s] = i, t), {}) : {};
95
+ }
96
+ }
97
+ const q = Symbol("state");
98
+ class J {
99
+ // Unique channel identifier
100
+ // static identifier = ''
101
+ constructor(e = {}) {
102
+ this.emitter = j(), this.params = Object.freeze(e), this.presence = new ie(this), this.initialConnect = !0, this[q] = "idle";
103
+ }
104
+ get identifier() {
105
+ return this._identifier ? this._identifier : (this._identifier = W({
106
+ channel: this.channelId,
107
+ ...this.params
108
+ }), this._identifier);
109
+ }
110
+ get channelId() {
111
+ return this.constructor.identifier;
112
+ }
113
+ get state() {
114
+ return this[q];
115
+ }
116
+ attached(e) {
117
+ if (this.receiver) {
118
+ if (this.receiver !== e)
119
+ throw Error("Already connected to a different receiver");
120
+ return !1;
121
+ }
122
+ return this.receiver = e, !0;
123
+ }
124
+ connecting() {
125
+ this[q] = "connecting";
126
+ }
127
+ connected() {
128
+ if (this.state === "connected" || this.state === "closed") return;
129
+ this[q] = "connected";
130
+ let e = !1;
131
+ this.initialConnect ? (this.initialConnect = !1, this.emit("connect", { reconnect: !1, restored: e })) : this.emit("connect", { reconnect: !0, restored: e });
132
+ }
133
+ restored() {
134
+ if (this.state === "connected") throw Error("Already connected");
135
+ this[q] = "connected";
136
+ let e = !0, t = !0;
137
+ this.initialConnect = !1, this.emit("connect", { reconnect: t, restored: e });
138
+ }
139
+ disconnected(e) {
140
+ this.state === "disconnected" || this.state === "closed" || (this[q] = "disconnected", this.presence.reset(), this.emit("disconnect", e));
141
+ }
142
+ closed(e) {
143
+ this.state !== "closed" && (this[q] = "closed", delete this.receiver, this.initialConnect = !0, this.presence.dispose(), this.emit("close", e));
144
+ }
145
+ disconnect() {
146
+ this.state === "idle" || this.state === "closed" || this.receiver.unsubscribe(this);
147
+ }
148
+ async perform(e, t) {
149
+ if (this.state === "idle" || this.state === "closed")
150
+ throw Error("Channel is not subscribed");
151
+ return this.receiver.perform(this.identifier, e, t);
152
+ }
153
+ async send(e) {
154
+ return this.perform(void 0, e);
155
+ }
156
+ async whisper(e) {
157
+ try {
158
+ await this.perform("$whisper", e);
159
+ } catch (t) {
160
+ let s = this.receiver ? this.receiver.logger : null;
161
+ s && s.warn("whisper failed: ", t);
162
+ }
163
+ }
164
+ receive(e, t) {
165
+ this.emit("message", e, t);
166
+ }
167
+ on(e, t) {
168
+ return this.emitter.on(e, t);
169
+ }
170
+ once(e, t) {
171
+ let s = this.emitter.on(e, (...i) => {
172
+ s(), t(...i);
173
+ });
174
+ return s;
175
+ }
176
+ emit(e, ...t) {
177
+ return this.emitter.emit(e, ...t);
178
+ }
179
+ ensureSubscribed() {
180
+ return this.state === "connected" ? Promise.resolve() : this.state === "closed" ? Promise.reject(Error("Channel is unsubscribed")) : this.pendingSubscribe();
181
+ }
182
+ // This promise resolves when subscription is confirmed
183
+ // and rejects when rejected or closed.
184
+ // It ignores disconnect events.
185
+ pendingSubscribe() {
186
+ return this._pendingSubscribe ? this._pendingSubscribe : (this._pendingSubscribe = new Promise((e, t) => {
187
+ let s = [() => delete this._pendingSubscribe];
188
+ s.push(
189
+ this.on("connect", () => {
190
+ s.forEach((i) => i()), e();
191
+ })
192
+ ), s.push(
193
+ this.on("close", (i) => {
194
+ s.forEach((r) => r()), t(
195
+ i || new x(
196
+ "Channel was disconnected before subscribing",
197
+ "canceled"
198
+ )
199
+ );
200
+ })
201
+ );
202
+ }), this._pendingSubscribe);
203
+ }
204
+ }
205
+ class ne {
206
+ constructor(e) {
207
+ this.id = e, this.intent = "unsubscribed", this.state = "idle", this.channels = [], this.disposed = !1, this._pendings = [];
208
+ }
209
+ add(e) {
210
+ this.channels.includes(e) || this.channels.push(e);
211
+ }
212
+ remove(e) {
213
+ let t = this.channels.indexOf(e);
214
+ t > -1 && this.channels.splice(t, 1);
215
+ }
216
+ notify(e, ...t) {
217
+ this.state = e === "restored" ? "connected" : e, t.length === 1 ? this.channels.forEach((s) => s[e](t[0])) : this.channels.forEach((s) => s[e]());
218
+ }
219
+ pending(e) {
220
+ this._checkIntent(e);
221
+ let t = this._pendings[0];
222
+ return !t || t.intent !== e ? Promise.resolve() : t.promise;
223
+ }
224
+ ensureResubscribed() {
225
+ this.disposed || (this.intent = void 0, this.ensureSubscribed());
226
+ }
227
+ ensureSubscribed() {
228
+ if (this.intent === "subscribed") return;
229
+ if (this.disposed) throw Error("Subscription is disposed");
230
+ this.intent = "subscribed", !this._mergeWithPending("unsubscribed") && this.subscriber(this);
231
+ }
232
+ maybeUnsubscribe() {
233
+ this.disposed || this.intent === "unsubscribed" || this.channels.length > 0 || (this.intent = "unsubscribed", this._mergeWithPending("subscribed")) || this.unsubscriber(this);
234
+ }
235
+ async acquire(e) {
236
+ this._checkIntent(e);
237
+ let t, i = {
238
+ promise: new Promise((o) => {
239
+ t = o;
240
+ }),
241
+ intent: e,
242
+ release: () => {
243
+ this._pendings.splice(this._pendings.indexOf(i), 1), t(i);
244
+ },
245
+ canceled: !1,
246
+ acquired: !1
247
+ }, r = this._pendingTop;
248
+ return this._pendings.push(i), r && await r.promise, this.gvl && await this.gvl.acquire(i, e), i.acquired = !0, i;
249
+ }
250
+ close(e) {
251
+ this.disposed = !0, this.intent = void 0, this.notify("closed", e);
252
+ }
253
+ _checkIntent(e) {
254
+ if (!(e === "unsubscribed" || e === "subscribed"))
255
+ throw Error(`Unknown subscription intent: ${e}`);
256
+ }
257
+ get _pendingTop() {
258
+ return this._pendings.length ? this._pendings[this._pendings.length - 1] : void 0;
259
+ }
260
+ _mergeWithPending(e) {
261
+ let t = this._pendingTop;
262
+ return !t || t.acquired || t.intent !== e ? !1 : (this._pendings.pop(), t.canceled = !0, !0);
263
+ }
264
+ }
265
+ class re {
266
+ constructor() {
267
+ this.queue = [];
268
+ }
269
+ async acquire(e, t) {
270
+ t === "subscribed" && (this.queue.push(
271
+ e.promise.then(() => {
272
+ this.queue.splice(this.queue.indexOf(e), 1);
273
+ })
274
+ ), this.queue.length > 1 && await this.queue[this.queue.length - 2]);
275
+ }
276
+ }
277
+ class oe {
278
+ constructor(e) {
279
+ e.concurrentSubscribes === !1 && (this.glv = new re()), this._subscriptions = {}, this._localToRemote = {};
280
+ }
281
+ all() {
282
+ return Object.values(this._subscriptions);
283
+ }
284
+ get(e) {
285
+ return this._subscriptions[e];
286
+ }
287
+ create(e, { subscribe: t, unsubscribe: s }) {
288
+ let i = this._subscriptions[e] = new ne(e);
289
+ return i.remoteId = this._localToRemote[e], i.subscriber = t, i.unsubscriber = s, i.gvl = this.glv, i;
290
+ }
291
+ remove(e) {
292
+ delete this._subscriptions[e], delete this._localToRemote[e];
293
+ }
294
+ storeRemoteId(e, t) {
295
+ this._localToRemote[e] = t;
296
+ let s = this.get(e);
297
+ s && (s.remoteId = t);
298
+ }
299
+ }
300
+ class ce {
301
+ constructor(e = {}) {
302
+ this.subscriptions = new oe(e), this._pendingMessages = [], this._remoteToLocal = {};
303
+ }
304
+ subscribe(e, t) {
305
+ this._remoteToLocal[t] = e, this.subscriptions.storeRemoteId(e, t), this.flush(t);
306
+ }
307
+ unsubscribe(e) {
308
+ let t = this.subscriptions.get(e);
309
+ if (!t) return;
310
+ let s = t.remoteId;
311
+ s && delete this._remoteToLocal[s], this.subscriptions.remove(e);
312
+ }
313
+ transmit(e, t, s) {
314
+ let i = this._remoteToLocal[e];
315
+ if (!i) {
316
+ this._pendingMessages.push([e, t, s]);
317
+ return;
318
+ }
319
+ let r = this.subscriptions.get(i);
320
+ r && r.channels.forEach((o) => {
321
+ o.receive(t, s);
322
+ });
323
+ }
324
+ notify(e, t, s) {
325
+ let i = this._remoteToLocal[e];
326
+ if (!i)
327
+ return;
328
+ let r = this.subscriptions.get(i);
329
+ r && r.channels.forEach((o) => o.emit(t, s));
330
+ }
331
+ close() {
332
+ this._pendingMessages.length = 0;
333
+ }
334
+ get size() {
335
+ return this.channels.length;
336
+ }
337
+ get channels() {
338
+ return this.subscriptions.all().flatMap((e) => e.channels);
339
+ }
340
+ flush(e) {
341
+ let t = [];
342
+ for (let s of this._pendingMessages)
343
+ s[0] === e ? this.transmit(s[0], s[1], s[2]) : t.push(s);
344
+ this._pendingMessages = t;
345
+ }
346
+ }
347
+ const F = {
348
+ debug: 0,
349
+ info: 1,
350
+ warn: 2,
351
+ error: 3
352
+ };
353
+ class V {
354
+ constructor(e) {
355
+ this.level = e || "warn";
356
+ }
357
+ log(e, t, s) {
358
+ F[e] < F[this.level] || this.writeLogEntry(e, t, s);
359
+ }
360
+ writeLogEntry() {
361
+ throw Error("Not implemented");
362
+ }
363
+ debug(e, t) {
364
+ this.log("debug", e, t);
365
+ }
366
+ info(e, t) {
367
+ this.log("info", e, t);
368
+ }
369
+ warn(e, t) {
370
+ this.log("warn", e, t);
371
+ }
372
+ error(e, t) {
373
+ this.log("error", e, t);
374
+ }
375
+ }
376
+ class z extends V {
377
+ writeLogEntry() {
378
+ }
379
+ }
380
+ class ae {
381
+ encode(e) {
382
+ return JSON.stringify(e);
383
+ }
384
+ decode(e) {
385
+ try {
386
+ return JSON.parse(e);
387
+ } catch {
388
+ }
389
+ }
390
+ }
391
+ let he = 0;
392
+ class H {
393
+ constructor(e = {}) {
394
+ let { logger: t } = e;
395
+ this.logger = t || new z(), this.pendingSubscriptions = {}, this.pendingUnsubscriptions = {}, this.subscribeCooldownInterval = e.subscribeCooldownInterval || 250, this.subscribeRetryInterval = e.subscribeRetryInterval || 5e3;
396
+ }
397
+ attached(e) {
398
+ this.cable = e;
399
+ }
400
+ subscribe(e, t) {
401
+ let s = { channel: e };
402
+ t && Object.assign(s, t);
403
+ let i = W(s);
404
+ if (this.pendingUnsubscriptions[i]) {
405
+ let o = this.subscribeCooldownInterval * 1.5;
406
+ return this.logger.debug(
407
+ `unsubscribed recently, cooldown for ${o}`,
408
+ i
409
+ ), new Promise((c) => {
410
+ setTimeout(() => {
411
+ c(this.subscribe(e, t));
412
+ }, o);
413
+ });
414
+ }
415
+ if (this.pendingSubscriptions[i])
416
+ return this.logger.warn("subscription is already pending, skipping", i), Promise.reject(Error("Already subscribing"));
417
+ let r = this.subscribeRetryInterval;
418
+ return new Promise((o, c) => {
419
+ let d = ++he;
420
+ this.pendingSubscriptions[i] = {
421
+ resolve: o,
422
+ reject: c,
423
+ id: d
424
+ }, this.cable.send(this.buildSubscribeRequest(i)), this.maybeRetrySubscribe(d, i, r);
425
+ });
426
+ }
427
+ buildSubscribeRequest(e) {
428
+ return {
429
+ command: "subscribe",
430
+ identifier: e
431
+ };
432
+ }
433
+ maybeRetrySubscribe(e, t, s) {
434
+ setTimeout(() => {
435
+ let i = this.pendingSubscriptions[t];
436
+ i && i.id === e && (this.logger.warn(
437
+ `no subscription ack received in ${s}ms, retrying subscribe`,
438
+ t
439
+ ), this.cable.send(this.buildSubscribeRequest(t)), this.maybeExpireSubscribe(e, t, s));
440
+ }, s);
441
+ }
442
+ maybeExpireSubscribe(e, t, s) {
443
+ setTimeout(() => {
444
+ let i = this.pendingSubscriptions[t];
445
+ i && i.id === e && (delete this.pendingSubscriptions[t], i.reject(
446
+ new te(
447
+ `Haven't received subscription ack in ${s * 2}ms for ${t}`
448
+ )
449
+ ));
450
+ }, s);
451
+ }
452
+ unsubscribe(e) {
453
+ return this.cable.send({
454
+ command: "unsubscribe",
455
+ identifier: e
456
+ }), this.pendingUnsubscriptions[e] = !0, setTimeout(() => {
457
+ delete this.pendingUnsubscriptions[e];
458
+ }, this.subscribeCooldownInterval), Promise.resolve();
459
+ }
460
+ perform(e, t, s) {
461
+ return t === "$whisper" ? this.whisper(e, s) : (s || (s = {}), s.action || (s.action = t), this.cable.send({
462
+ command: "message",
463
+ identifier: e,
464
+ data: JSON.stringify(s)
465
+ }), Promise.resolve());
466
+ }
467
+ whisper(e, t) {
468
+ return this.cable.send({
469
+ command: "whisper",
470
+ identifier: e,
471
+ data: t
472
+ }), Promise.resolve();
473
+ }
474
+ receive(e) {
475
+ if (typeof e != "object") {
476
+ this.logger.error("unsupported message format", { message: e });
477
+ return;
478
+ }
479
+ let { type: t, identifier: s, message: i, reason: r, reconnect: o } = e;
480
+ if (t === "ping")
481
+ return this.cable.keepalive(e.message);
482
+ if (this.cable.keepalive(), t === "welcome") {
483
+ let c = e.sid;
484
+ return c && this.cable.setSessionId(c), this.cable.connected();
485
+ }
486
+ if (t === "disconnect") {
487
+ let c = new v(r);
488
+ this.reset(c), o === !1 ? this.cable.closed(c) : this.cable.disconnected(c);
489
+ return;
490
+ }
491
+ if (t === "confirm_subscription") {
492
+ let c = this.pendingSubscriptions[s];
493
+ if (!c) {
494
+ this.logger.error("subscription not found, unsubscribing", {
495
+ type: t,
496
+ identifier: s
497
+ }), this.unsubscribe(s);
498
+ return;
499
+ }
500
+ return delete this.pendingSubscriptions[s], c.resolve(s);
501
+ }
502
+ if (t === "reject_subscription") {
503
+ let c = this.pendingSubscriptions[s];
504
+ return c ? (delete this.pendingSubscriptions[s], c.reject(new G())) : this.logger.error("subscription not found", { type: t, identifier: s });
505
+ }
506
+ if (i)
507
+ return { identifier: s, message: i };
508
+ this.logger.warn(`unknown message type: ${t}`, { message: e });
509
+ }
510
+ reset(e) {
511
+ for (let t in this.pendingSubscriptions)
512
+ this.pendingSubscriptions[t].reject(e);
513
+ this.pendingSubscriptions = {};
514
+ }
515
+ recoverableClosure() {
516
+ return !1;
517
+ }
518
+ }
519
+ const Q = () => Date.now() / 1e3 | 0;
520
+ class le extends H {
521
+ constructor(e = {}) {
522
+ super(e), this.streamsPositions = {}, this.subscriptionStreams = {}, this.pendingHistory = {}, this.pendingPresence = {}, this.presenceInfo = {}, this.restoreSince = e.historyTimestamp, this.disableSessionRecovery = e.disableSessionRecovery, this.restoreSince === void 0 && (this.restoreSince = Q()), this.sessionId = void 0, this.sendPongs = e.pongs;
523
+ }
524
+ reset(e) {
525
+ for (let t in this.pendingPresence)
526
+ this.pendingPresence[t].reject(e);
527
+ return this.pendingPresence = {}, super.reset();
528
+ }
529
+ receive(e) {
530
+ if (typeof e != "object") {
531
+ this.logger.error("unsupported message format", { message: e });
532
+ return;
533
+ }
534
+ let { type: t, identifier: s, message: i } = e;
535
+ if (t === "disconnect")
536
+ return delete this.sessionId, this.cable.setSessionId(""), super.receive(e);
537
+ if (t === "reject_subscription")
538
+ return super.receive(e);
539
+ if (t === "confirm_subscription")
540
+ return this.subscriptionStreams[s] || (this.subscriptionStreams[s] = /* @__PURE__ */ new Set()), super.receive(e);
541
+ if (t === "ping")
542
+ return this.restoreSince && (this.restoreSince = Q()), this.sendPongs && this.sendPong(), this.cable.keepalive(e.message);
543
+ if (this.cable.keepalive(), t === "confirm_history") {
544
+ this.logger.debug("history result received", e), this.cable.notify("history_received", s);
545
+ return;
546
+ }
547
+ if (t === "reject_history") {
548
+ this.logger.warn("failed to retrieve history", e), this.cable.notify("history_not_found", s);
549
+ return;
550
+ }
551
+ if (t === "welcome") {
552
+ if (this.disableSessionRecovery || (this.sessionId = e.sid, this.sessionId && this.cable.setSessionId(this.sessionId)), e.restored) {
553
+ let r = e.restored_ids || Object.keys(this.subscriptionStreams);
554
+ for (let o of r)
555
+ this.cable.send({
556
+ identifier: o,
557
+ command: "history",
558
+ history: this.historyRequestFor(o)
559
+ }), this.presenceInfo[o] && this.cable.send({
560
+ identifier: o,
561
+ command: "join",
562
+ presence: this.presenceInfo[o]
563
+ });
564
+ return this.cable.restored(r);
565
+ }
566
+ return this.cable.connected(this.sessionId);
567
+ }
568
+ if (t === "presence") {
569
+ let r = i.type;
570
+ if (r === "info") {
571
+ let o = this.pendingPresence[s];
572
+ o && (delete this.pendingPresence[s], o.resolve(i));
573
+ } else if (r === "error") {
574
+ let o = this.pendingPresence[s];
575
+ o && (delete this.pendingPresence[s], o.reject(new Error("failed to retrieve presence")));
576
+ }
577
+ return {
578
+ type: t,
579
+ identifier: s,
580
+ message: i
581
+ };
582
+ }
583
+ if (i) {
584
+ let r = this.trackStreamPosition(
585
+ s,
586
+ e.stream_id,
587
+ e.epoch,
588
+ e.offset
589
+ );
590
+ return { identifier: s, message: i, meta: r };
591
+ }
592
+ this.logger.warn(`unknown message type: ${t}`, { message: e });
593
+ }
594
+ perform(e, t, s) {
595
+ switch (t) {
596
+ case "$presence:join":
597
+ return this.join(e, s);
598
+ case "$presence:leave":
599
+ return this.leave(e, s);
600
+ case "$presence:info":
601
+ return this.presence(e, s);
602
+ }
603
+ return super.perform(e, t, s);
604
+ }
605
+ unsubscribe(e) {
606
+ return delete this.presenceInfo[e], super.unsubscribe(e);
607
+ }
608
+ buildSubscribeRequest(e) {
609
+ let t = super.buildSubscribeRequest(e), s = this.historyRequestFor(e);
610
+ s && (t.history = s, this.pendingHistory[e] = !0);
611
+ let i = this.presenceInfo[e];
612
+ return i && (t.presence = i), t;
613
+ }
614
+ // TODO: Which error can be non-recoverable?
615
+ recoverableClosure() {
616
+ return !!this.sessionId;
617
+ }
618
+ historyRequestFor(e) {
619
+ let t = {}, s = !1;
620
+ if (this.subscriptionStreams[e])
621
+ for (let i of this.subscriptionStreams[e]) {
622
+ let r = this.streamsPositions[i];
623
+ r && (s = !0, t[i] = r);
624
+ }
625
+ if (!(!s && !this.restoreSince))
626
+ return { since: this.restoreSince, streams: t };
627
+ }
628
+ trackStreamPosition(e, t, s, i) {
629
+ if (!(!t || !s))
630
+ return this.subscriptionStreams[e] || (this.subscriptionStreams[e] = /* @__PURE__ */ new Set()), this.subscriptionStreams[e].add(t), this.streamsPositions[t] = { epoch: s, offset: i }, { stream: t, epoch: s, offset: i };
631
+ }
632
+ // Send pongs asynchrounously—no need to block the main thread
633
+ async sendPong() {
634
+ await new Promise((e) => setTimeout(e, 0)), this.cable.state === "connected" && this.cable.send({ command: "pong" });
635
+ }
636
+ async join(e, t) {
637
+ return this.presenceInfo[e] = t, this.cable.send({
638
+ command: "join",
639
+ identifier: e,
640
+ presence: t
641
+ }), Promise.resolve();
642
+ }
643
+ async leave(e, t) {
644
+ return delete this.presenceInfo[e], this.cable.send({
645
+ command: "leave",
646
+ identifier: e,
647
+ presence: t
648
+ }), Promise.resolve();
649
+ }
650
+ presence(e, t) {
651
+ return this.pendingPresence[e] ? (this.logger.warn("presence is already pending, skipping", e), Promise.reject(Error("presence request is already pending"))) : new Promise((s, i) => {
652
+ this.pendingPresence[e] = {
653
+ resolve: s,
654
+ reject: i
655
+ }, this.cable.send({
656
+ command: "presence",
657
+ identifier: e,
658
+ data: t
659
+ });
660
+ });
661
+ }
662
+ }
663
+ class ue extends x {
664
+ constructor() {
665
+ super("No connection", "closed"), this.name = "NoConnectionError";
666
+ }
667
+ }
668
+ class B extends J {
669
+ constructor(e, t) {
670
+ super(t), this.channelId = e;
671
+ }
672
+ set channelId(e) {
673
+ this._channelId = e;
674
+ }
675
+ get channelId() {
676
+ return this._channelId;
677
+ }
678
+ }
679
+ A(B, "identifier", "__ghost__");
680
+ const de = "$pubsub";
681
+ class U extends J {
682
+ async perform(e, t) {
683
+ if (e.startsWith("$"))
684
+ return super.perform(e, t);
685
+ throw Error("not implemented");
686
+ }
687
+ }
688
+ A(U, "identifier", de);
689
+ const C = Symbol("state");
690
+ class pe {
691
+ constructor({
692
+ transport: e,
693
+ protocol: t,
694
+ encoder: s,
695
+ logger: i,
696
+ lazy: r,
697
+ hubOptions: o,
698
+ performFailures: c,
699
+ transportConfigurator: d
700
+ }) {
701
+ this.emitter = j(), this.transport = e, this.encoder = s, this.logger = i || new z(), this.protocol = t, this.performFailures = c || "throw", this.protocol.attached(this), this.hub = new ce(o || {}), this[C] = "idle", this.handleClose = this.handleClose.bind(this), this.handleIncoming = this.handleIncoming.bind(this), this.transportConfigurator = d, this.transport.on("close", this.handleClose), this.transport.on("data", this.handleIncoming), this.initialConnect = !0, this.recovering = !1, r === !1 && this.connect().catch(() => {
702
+ });
703
+ }
704
+ get state() {
705
+ return this[C];
706
+ }
707
+ async connect() {
708
+ if (this.state === "connected") return Promise.resolve();
709
+ if (this.state === "connecting")
710
+ return this.pendingConnect();
711
+ let e = this.state === "idle";
712
+ this[C] = "connecting";
713
+ let t = this.pendingConnect();
714
+ this.logger.debug("connecting");
715
+ try {
716
+ this.transportConfigurator && await this.transportConfigurator(this.transport, {
717
+ initial: e
718
+ }), await this.transport.open();
719
+ } catch (s) {
720
+ this.handleClose(s);
721
+ }
722
+ return t;
723
+ }
724
+ setSessionId(e) {
725
+ this.sessionId = e, this.transport.setParam("sid", e);
726
+ }
727
+ connected() {
728
+ if (this.state === "connected") return;
729
+ this.logger.info("connected"), this[C] = "connected", this.recovering && this.hub.subscriptions.all().forEach(
730
+ (t) => t.notify(
731
+ "disconnected",
732
+ new v("recovery_failed")
733
+ )
734
+ ), this.hub.subscriptions.all().forEach((t) => this._resubscribe(t));
735
+ let e = !1;
736
+ this.recovering = !1, this.initialConnect ? (this.initialConnect = !1, this.emit("connect", { reconnect: !1, restored: e })) : this.emit("connect", { reconnect: !0, restored: e });
737
+ }
738
+ restored(e) {
739
+ this.logger.info("connection recovered", { remoteIds: e }), this[C] = "connected", this.hub.subscriptions.all().forEach((i) => {
740
+ e && i.remoteId && e.includes(i.remoteId) ? i.notify("restored") : (i.notify(
741
+ "disconnected",
742
+ new v("recovery_failed")
743
+ ), this._resubscribe(i));
744
+ });
745
+ let t = !this.initialConnect, s = !0;
746
+ this.recovering = !1, this.initialConnect = !1, this.emit("connect", { reconnect: t, restored: s });
747
+ }
748
+ notify(e, t, s) {
749
+ t && typeof t != "string" && (s = t, t = void 0), t ? this.hub.notify(t, "info", { type: e, data: s }) : this.emit("info", { type: e, data: s });
750
+ }
751
+ handleClose(e) {
752
+ this.logger.debug("transport closed", { error: e }), this.disconnected(new v(e, "transport_closed"));
753
+ }
754
+ disconnected(e) {
755
+ (this.state === "connected" || this.state === "connecting") && (this.logger.info("disconnected", { reason: e }), this[C] = "disconnected", this.recovering = this.protocol.recoverableClosure(e), this.recovering ? this.hub.subscriptions.all().forEach((t) => t.notify("connecting")) : this.hub.subscriptions.all().forEach((t) => {
756
+ t.notify("disconnected", e);
757
+ }), this.protocol.reset(e), this.hub.close(), this.transport.close(), this.emit("disconnect", e));
758
+ }
759
+ closed(e) {
760
+ if (this.state === "closed" || this.state === "idle") return;
761
+ let t;
762
+ e && (t = e instanceof v ? e : new v(e, void 0)), this.logger.info("closed", { reason: e || "user" }), this[C] = "closed";
763
+ let s = t || new v("cable_closed");
764
+ this.hub.subscriptions.all().forEach((i) => i.notify("disconnected", s)), this.hub.close(), this.protocol.reset(), this.transport.close(), this.initialConnect = !0, this.emit("close", t);
765
+ }
766
+ disconnect() {
767
+ this.closed();
768
+ }
769
+ handleIncoming(e) {
770
+ if (this.state === "closed" || this.state === "idle")
771
+ return;
772
+ let t = this.encoder.decode(e);
773
+ if (t === void 0) {
774
+ this.logger.error("failed to decode message", { message: e });
775
+ return;
776
+ }
777
+ this.logger.debug("incoming data", t);
778
+ let s = this.protocol.receive(t);
779
+ if (s) {
780
+ this.logger.debug("processed incoming message", s);
781
+ let { type: i, identifier: r, message: o, meta: c } = s;
782
+ i ? this.hub.notify(r, i, o) : this.hub.transmit(r, o, c);
783
+ }
784
+ }
785
+ send(e) {
786
+ if (this.state === "closed")
787
+ throw Error("Cable is closed");
788
+ let t = this.encoder.encode(e);
789
+ if (t === void 0) {
790
+ this.logger.error("failed to encode message", { message: e });
791
+ return;
792
+ }
793
+ this.logger.debug("outgoing message", e), this.transport.send(t);
794
+ }
795
+ keepalive(e) {
796
+ this.emit("keepalive", e);
797
+ }
798
+ streamFrom(e) {
799
+ let t = new U({ stream_name: e });
800
+ return this.subscribe(t);
801
+ }
802
+ streamFromSigned(e) {
803
+ let t = new U({ signed_stream_name: e });
804
+ return this.subscribe(t);
805
+ }
806
+ subscribeTo(e, t) {
807
+ let s, i;
808
+ return typeof e == "string" && (i = e, e = B), s = i ? new e(i, t) : new e(t), this.subscribe(s);
809
+ }
810
+ subscribe(e) {
811
+ if (!e.attached(this)) return e;
812
+ let t = e.identifier;
813
+ e.connecting();
814
+ let s = this.hub.subscriptions.get(t) || this.hub.subscriptions.create(t, {
815
+ subscribe: (i) => this._subscribe(i, e.channelId, e.params),
816
+ unsubscribe: (i) => this._unsubscribe(i)
817
+ });
818
+ return s.add(e), s.intent === "subscribed" && s.state === "connected" && e.connected(), s.ensureSubscribed(), e;
819
+ }
820
+ async _resubscribe(e) {
821
+ e.intent !== "subscribed" || !e.channels[0] || (e.notify("connecting"), e.ensureResubscribed());
822
+ }
823
+ async _subscribe(e, t, s) {
824
+ let i = e.id;
825
+ if (this.state === "idle" && this.connect().catch(() => {
826
+ }), this.state !== "connected") {
827
+ this.logger.debug("cancel subscribe, no connection", { identifier: i });
828
+ return;
829
+ }
830
+ this.logger.debug("acquiring subscribe lock", { identifier: i });
831
+ let r = await e.acquire("subscribed");
832
+ if (r.canceled) {
833
+ this.logger.debug("subscribe lock has been canceled", { identifier: i }), r.release();
834
+ return;
835
+ }
836
+ if (this.logger.debug("subscribe lock has been acquired", { identifier: i }), e.intent !== "subscribed") {
837
+ this.logger.debug("cancel subscribe request, already unsubscribed"), r.release();
838
+ return;
839
+ }
840
+ if (this.state !== "connected") {
841
+ this.logger.debug("cancel subscribe, no connection", { identifier: i }), r.release();
842
+ return;
843
+ }
844
+ if (e.state === "connected") {
845
+ this.logger.debug("already connected, skip subscribe command", {
846
+ identifier: i
847
+ }), e.notify("connected"), r.release();
848
+ return;
849
+ }
850
+ let o = {
851
+ identifier: t,
852
+ params: s
853
+ };
854
+ this.logger.debug("subscribing", o);
855
+ try {
856
+ let c = await this.protocol.subscribe(t, s);
857
+ this.hub.subscribe(i, c), this.logger.debug("subscribed", { ...o, remoteId: c }), e.notify("connected");
858
+ } catch (c) {
859
+ if (c) {
860
+ if (c instanceof G && this.logger.warn("rejected", o), c instanceof v) {
861
+ this.logger.debug(
862
+ "disconnected during subscription; will retry on connect",
863
+ o
864
+ ), r.release();
865
+ return;
866
+ }
867
+ this.logger.error("failed to subscribe", {
868
+ error: c,
869
+ ...o
870
+ });
871
+ }
872
+ e.close(c), this.hub.unsubscribe(i);
873
+ }
874
+ r.release();
875
+ }
876
+ unsubscribe(e) {
877
+ let t = e.identifier, s = this.hub.subscriptions.get(t);
878
+ if (!s)
879
+ throw Error(`Subscription not found: ${t}`);
880
+ s.remove(e), e.closed(), s.maybeUnsubscribe();
881
+ }
882
+ async _unsubscribe(e) {
883
+ let t = e.id;
884
+ this.logger.debug("acquiring unsubscribe lock", { identifier: t });
885
+ let s = await e.acquire("unsubscribed");
886
+ if (s.canceled) {
887
+ this.logger.debug("unsubscribe lock has been canceled", { identifier: t }), s.release();
888
+ return;
889
+ }
890
+ if (this.logger.debug("unsubscribe lock has been acquired", { identifier: t }), e.intent !== "unsubscribed") {
891
+ this.logger.debug("cancel unsubscribe, no longer needed", {
892
+ identifier: t,
893
+ intent: e.intent
894
+ }), s.release();
895
+ return;
896
+ }
897
+ if (e.state === "disconnected" || e.state === "closed") {
898
+ this.logger.debug(
899
+ `already ${e.state} connected, skip unsubscribe command`,
900
+ { identifier: t }
901
+ ), s.release();
902
+ return;
903
+ }
904
+ let i = e.remoteId;
905
+ if (this.logger.debug("unsubscribing...", { remoteId: i }), this.state !== "connected") {
906
+ this.logger.debug("unsubscribe skipped (cable is not connected)", {
907
+ id: t
908
+ }), e.close(), this.hub.unsubscribe(t), s.release();
909
+ return;
910
+ }
911
+ try {
912
+ await this.protocol.unsubscribe(i), this.logger.debug("unsubscribed remotely", { id: t });
913
+ } catch (r) {
914
+ r && (r instanceof v ? this.logger.debug(
915
+ "cable disconnected during the unsubscribe command execution",
916
+ { id: t, error: r }
917
+ ) : this.logger.error("unsubscribe failed", {
918
+ id: t,
919
+ error: r
920
+ }));
921
+ }
922
+ e.intent === "unsubscribed" ? (e.close(), this.hub.unsubscribe(t)) : e.state = "closed", s.release();
923
+ }
924
+ async perform(e, t, s) {
925
+ if (this.performFailures === "throw")
926
+ return this._perform(e, t, s);
927
+ try {
928
+ return await this._perform(e, t, s);
929
+ } catch (i) {
930
+ this.performFailures === "warn" && this.logger.warn("perform failed", { error: i });
931
+ return;
932
+ }
933
+ }
934
+ async _perform(e, t, s) {
935
+ if (this.state === "connecting" && await this.pendingConnect(), this.state === "closed" || this.state === "disconnected")
936
+ throw new ue();
937
+ let i = this.hub.subscriptions.get(e);
938
+ if (!i)
939
+ throw Error(`Subscription not found: ${e}`);
940
+ if (await i.pending("subscribed"), i.intent !== "subscribed")
941
+ throw Error(`Subscription is closed: ${e}`);
942
+ let r = i.remoteId, o = {
943
+ id: r,
944
+ action: t,
945
+ payload: s
946
+ };
947
+ this.logger.debug("perform", o);
948
+ try {
949
+ let c = await this.protocol.perform(r, t, s);
950
+ return c && this.logger.debug("perform result", {
951
+ message: c,
952
+ request: o
953
+ }), c;
954
+ } catch (c) {
955
+ throw this.logger.error("perform failed", {
956
+ error: c,
957
+ request: o
958
+ }), c;
959
+ }
960
+ }
961
+ on(e, t) {
962
+ return this.emitter.on(e, t);
963
+ }
964
+ once(e, t) {
965
+ let s = this.emitter.on(e, (...i) => {
966
+ s(), t(...i);
967
+ });
968
+ return s;
969
+ }
970
+ emit(e, ...t) {
971
+ return this.emitter.emit(e, ...t);
972
+ }
973
+ pendingConnect() {
974
+ return this._pendingConnect ? this._pendingConnect : (this._pendingConnect = new Promise((e, t) => {
975
+ let s = [() => delete this._pendingConnect];
976
+ s.push(
977
+ this.on("connect", () => {
978
+ s.forEach((i) => i()), e();
979
+ })
980
+ ), s.push(
981
+ this.on("close", (i) => {
982
+ s.forEach((r) => r()), t(i);
983
+ })
984
+ ), s.push(
985
+ this.on("disconnect", (i) => {
986
+ s.forEach((r) => r()), t(i);
987
+ })
988
+ );
989
+ }), this._pendingConnect);
990
+ }
991
+ }
992
+ const fe = {
993
+ maxMissingPings: 2,
994
+ maxReconnectAttempts: 1 / 0
995
+ }, k = () => Date.now(), K = (n, e) => {
996
+ e = e || {};
997
+ let { backoffRate: t, jitterRatio: s, maxInterval: i } = e;
998
+ return t = t || 2, s === void 0 && (s = 0.5), (r) => {
999
+ let o = n * t ** r, c = o * t, d = o + (c - o) * Math.random(), p = 2 * (Math.random() - 0.5) * s;
1000
+ return d = d * (1 + p), i && i < d && (d = i), d;
1001
+ };
1002
+ };
1003
+ let X = class {
1004
+ constructor({ pingInterval: e, ...t }) {
1005
+ if (this.pingInterval = e, !this.pingInterval)
1006
+ throw Error(`Incorrect pingInterval is provided: ${e}`);
1007
+ if (t = Object.assign({}, fe, t), this.strategy = t.reconnectStrategy, !this.strategy)
1008
+ throw Error("Reconnect strategy must be provided");
1009
+ this.maxMissingPings = t.maxMissingPings, this.maxReconnectAttempts = t.maxReconnectAttempts, this.logger = t.logger || new z(), this.state = "pending_connect", this.attempts = 0, this.disconnectedAt = k();
1010
+ }
1011
+ watch(e) {
1012
+ this.target = e, this.initListeners();
1013
+ }
1014
+ reconnectNow() {
1015
+ return this.state === "connected" || this.state === "pending_connect" || this.state === "closed" ? !1 : (this.cancelReconnect(), this.state = "pending_connect", this.target.connect().catch((e) => {
1016
+ this.logger.info("Failed at reconnecting: " + e);
1017
+ }), !0);
1018
+ }
1019
+ initListeners() {
1020
+ this.unbind = [], this.unbind.push(
1021
+ this.target.on("connect", () => {
1022
+ this.attempts = 0, this.pingedAt = k(), this.state = "connected", this.cancelReconnect(), this.startPolling();
1023
+ })
1024
+ ), this.unbind.push(
1025
+ this.target.on("disconnect", () => {
1026
+ this.disconnectedAt = k(), this.state = "disconnected", this.stopPolling(), this.scheduleReconnect();
1027
+ })
1028
+ ), this.unbind.push(
1029
+ this.target.on("close", () => {
1030
+ this.disconnectedAt = k(), this.state = "closed", this.cancelReconnect(), this.stopPolling();
1031
+ })
1032
+ ), this.unbind.push(
1033
+ this.target.on("keepalive", () => {
1034
+ this.pingedAt = k();
1035
+ })
1036
+ ), this.unbind.push(() => {
1037
+ this.cancelReconnect(), this.stopPolling();
1038
+ });
1039
+ }
1040
+ dispose() {
1041
+ delete this.target, this.unbind && this.unbind.forEach((e) => e()), delete this.unbind;
1042
+ }
1043
+ startPolling() {
1044
+ this.pollId && clearTimeout(this.pollId);
1045
+ let e = this.pingInterval + (Math.random() - 0.5) * this.pingInterval * 0.5;
1046
+ this.pollId = setTimeout(() => {
1047
+ this.checkStale(), this.state === "connected" && this.startPolling();
1048
+ }, e);
1049
+ }
1050
+ stopPolling() {
1051
+ this.pollId && clearTimeout(this.pollId);
1052
+ }
1053
+ checkStale() {
1054
+ let e = k() - this.pingedAt;
1055
+ e > this.maxMissingPings * this.pingInterval && (this.logger.warn(`Stale connection: ${e}ms without pings`), this.state = "pending_disconnect", this.target.disconnected(new se()));
1056
+ }
1057
+ scheduleReconnect() {
1058
+ if (this.attempts >= this.maxReconnectAttempts) {
1059
+ this.target.close();
1060
+ return;
1061
+ }
1062
+ let e = this.strategy(this.attempts);
1063
+ this.attempts++, this.logger.info(`Reconnecting in ${e}ms (${this.attempts} attempt)`), this.state = "pending_reconnect", this.reconnnectId = setTimeout(() => this.reconnectNow(), e);
1064
+ }
1065
+ cancelReconnect() {
1066
+ this.reconnnectId && (clearTimeout(this.reconnnectId), delete this.reconnnectId);
1067
+ }
1068
+ };
1069
+ class be {
1070
+ constructor(e, t = {}) {
1071
+ this.transports = e, this.transport = null, this.emitter = j(), this.unbind = [], this.logger = t.logger || new z();
1072
+ }
1073
+ displayName() {
1074
+ return "fallbacked transport";
1075
+ }
1076
+ async open() {
1077
+ for (let e = 0; e < this.transports.length; e++) {
1078
+ let t = this.transports[e];
1079
+ try {
1080
+ this.transport = t, this.resetListeners(), this.logger.debug(`Trying to connect via ${t.displayName()}`), await t.open(), this.logger.debug(`Connected via ${t.displayName()}`);
1081
+ return;
1082
+ } catch (s) {
1083
+ this.logger.debug(
1084
+ `Failed to connect via ${t.displayName()}: ${s.message}`
1085
+ );
1086
+ }
1087
+ }
1088
+ throw this.transport = null, this.resetListeners(), new Error("Couldn't connect via any available transport");
1089
+ }
1090
+ send(e) {
1091
+ if (!this.transport)
1092
+ throw new Error("No transport is open");
1093
+ this.transport.send(e);
1094
+ }
1095
+ async close() {
1096
+ if (!this.transport)
1097
+ throw new Error("No transport is open");
1098
+ await this.transport.close(), this.transport = null;
1099
+ }
1100
+ setURL() {
1101
+ throw new Error("Not implemented. Set URL for each transport separately");
1102
+ }
1103
+ setParam(e, t) {
1104
+ this.transports.forEach((s) => {
1105
+ s.setParam(e, t);
1106
+ });
1107
+ }
1108
+ setToken(e, t) {
1109
+ this.transports.forEach((s) => {
1110
+ s.setToken(e, t);
1111
+ });
1112
+ }
1113
+ on(e, t) {
1114
+ return this.emitter.on(e, t);
1115
+ }
1116
+ once(e, t) {
1117
+ let s = this.emitter.on(e, (...i) => {
1118
+ s(), t(...i);
1119
+ });
1120
+ return s;
1121
+ }
1122
+ get url() {
1123
+ return this.transport ? this.transport.url : "";
1124
+ }
1125
+ resetListeners() {
1126
+ this.unbind.forEach((e) => e()), this.unbind.length = 0, this.transport && this.unbind.push(
1127
+ this.transport.on("open", () => {
1128
+ this.emitter.emit("open");
1129
+ }),
1130
+ this.transport.on("data", (e) => {
1131
+ this.emitter.emit("data", e);
1132
+ }),
1133
+ this.transport.on("close", (e) => {
1134
+ this.emitter.emit("close", e);
1135
+ }),
1136
+ this.transport.on("error", (e) => {
1137
+ this.emitter.emit("error", e);
1138
+ })
1139
+ );
1140
+ }
1141
+ }
1142
+ class ge {
1143
+ constructor(e, t = {}) {
1144
+ this.url = e;
1145
+ let s = t.websocketImplementation;
1146
+ if (s)
1147
+ this.Impl = s;
1148
+ else if (typeof WebSocket < "u")
1149
+ this.Impl = WebSocket;
1150
+ else
1151
+ throw new Error("No WebSocket support");
1152
+ this.connected = !1, this.emitter = j();
1153
+ let { format: i, subprotocol: r, authStrategy: o } = t;
1154
+ this.format = i || "text", this.connectionOptions = t.websocketOptions, this.authStrategy = o || "param", this.authProtocol = "", this.subprotocol = r;
1155
+ }
1156
+ displayName() {
1157
+ return "WebSocket(" + this.url + ")";
1158
+ }
1159
+ open() {
1160
+ let e = this.subprotocol;
1161
+ return this.authStrategy === "sub-protocol" && (e = [this.subprotocol, this.authProtocol]), this.connectionOptions ? this.ws = new this.Impl(this.url, e, this.connectionOptions) : this.ws = new this.Impl(this.url, e), this.ws.binaryType = "arraybuffer", this.initListeners(), new Promise((t, s) => {
1162
+ let i = [];
1163
+ i.push(
1164
+ this.once("open", () => {
1165
+ i.forEach((r) => r()), t();
1166
+ })
1167
+ ), i.push(
1168
+ this.once("close", () => {
1169
+ i.forEach((r) => r()), s(Error("WS connection closed"));
1170
+ })
1171
+ );
1172
+ });
1173
+ }
1174
+ setURL(e) {
1175
+ this.url = e;
1176
+ }
1177
+ setParam(e, t) {
1178
+ let s = new URL(this.url);
1179
+ s.searchParams.set(e, t);
1180
+ let i = `${s.protocol}//${s.host}${s.pathname}?${s.searchParams}`;
1181
+ this.setURL(i);
1182
+ }
1183
+ setToken(e, t = "jid") {
1184
+ if (this.authStrategy === "param")
1185
+ this.setParam(t, e);
1186
+ else if (this.authStrategy === "header") {
1187
+ this.connectionOptions = this.connectionOptions || {}, this.connectionOptions.headers = this.connectionOptions.headers || {};
1188
+ let s = `x-${t}`.toLowerCase();
1189
+ s = Object.keys(this.connectionOptions.headers).find(
1190
+ (r) => r.toLowerCase() === s
1191
+ ) || s, this.connectionOptions.headers[s] = e;
1192
+ } else if (this.authStrategy === "sub-protocol")
1193
+ this.authProtocol = `anycable-token.${e}`;
1194
+ else
1195
+ throw new Error("Unknown auth strategy: " + this.authStrategy);
1196
+ }
1197
+ send(e) {
1198
+ if (!this.ws || !this.connected)
1199
+ throw Error("WebSocket is not connected");
1200
+ this.ws.send(e);
1201
+ }
1202
+ close() {
1203
+ this.ws ? this.onclose() : this.connected = !1;
1204
+ }
1205
+ on(e, t) {
1206
+ return this.emitter.on(e, t);
1207
+ }
1208
+ once(e, t) {
1209
+ let s = this.emitter.on(e, (...i) => {
1210
+ s(), t(...i);
1211
+ });
1212
+ return s;
1213
+ }
1214
+ initListeners() {
1215
+ this.ws.onerror = (e) => {
1216
+ this.connected && this.emitter.emit("error", e.error || new Error("WS Error"));
1217
+ }, this.ws.onclose = () => {
1218
+ this.onclose();
1219
+ }, this.ws.onmessage = (e) => {
1220
+ let t = e.data;
1221
+ this.format === "binary" && (t = new Uint8Array(t)), this.emitter.emit("data", t);
1222
+ }, this.ws.onopen = () => {
1223
+ this.connected = !0, this.emitter.emit("open");
1224
+ };
1225
+ }
1226
+ onclose() {
1227
+ this.ws.onclose = void 0, this.ws.onmessage = void 0, this.ws.onopen = void 0, this.ws.close(), delete this.ws, this.connected = !1, this.emitter.emit("close");
1228
+ }
1229
+ }
1230
+ const Y = {
1231
+ protocol: "actioncable-v1-json",
1232
+ pingInterval: 3e3,
1233
+ maxReconnectAttempts: 1 / 0,
1234
+ maxMissingPings: 2,
1235
+ logLevel: "warn",
1236
+ lazy: !0
1237
+ };
1238
+ function me(n, e) {
1239
+ if (typeof n == "object" && typeof e > "u" && (e = n, n = void 0), e = e || {}, !n && !e.transport) throw Error("URL or transport must be specified");
1240
+ e = Object.assign({}, Y, e);
1241
+ let {
1242
+ protocol: t,
1243
+ websocketImplementation: s,
1244
+ websocketFormat: i,
1245
+ websocketOptions: r,
1246
+ websocketAuthStrategy: o,
1247
+ fallbacks: c,
1248
+ logLevel: d,
1249
+ logger: p,
1250
+ transport: y,
1251
+ encoder: _,
1252
+ lazy: I,
1253
+ monitor: S,
1254
+ pingInterval: L,
1255
+ reconnectStrategy: T,
1256
+ maxMissingPings: O,
1257
+ maxReconnectAttempts: R,
1258
+ subprotocol: P,
1259
+ tokenRefresher: a,
1260
+ historyTimestamp: h,
1261
+ protocolOptions: l,
1262
+ concurrentSubscribes: w,
1263
+ performFailures: g,
1264
+ transportConfigurator: m,
1265
+ auth: f
1266
+ } = e;
1267
+ if (p = p || new z(d), typeof t == "string") {
1268
+ P = P || t;
1269
+ let E = t.substring(0, t.lastIndexOf("-")), N = t.substring(t.lastIndexOf("-") + 1);
1270
+ if (l = l || {}, E === "actioncable-v1")
1271
+ t = new H({ logger: p, ...l });
1272
+ else if (E === "actioncable-v1-ext")
1273
+ t = new le({
1274
+ logger: p,
1275
+ historyTimestamp: h,
1276
+ ...l
1277
+ });
1278
+ else
1279
+ throw Error(`Protocol is not supported yet: ${t}`);
1280
+ if (N === "json")
1281
+ _ = _ || new ae(), i = i || "text";
1282
+ else if (N === "msgpack") {
1283
+ if (i = "binary", !_)
1284
+ throw Error(
1285
+ "Msgpack encoder must be specified explicitly. Use `@anycable/msgpack-encoder` package or build your own"
1286
+ );
1287
+ } else if (N === "protobuf") {
1288
+ if (i = i || "binary", !_)
1289
+ throw Error(
1290
+ "Protobuf encoder must be specified explicitly. Use `@anycable/protobuf-encoder` package or build your own"
1291
+ );
1292
+ } else
1293
+ throw Error(`Protocol is not supported yet: ${t}`);
1294
+ }
1295
+ if (!t) throw Error("Protocol must be specified");
1296
+ y = y || new ge(n, {
1297
+ websocketImplementation: s,
1298
+ websocketOptions: r,
1299
+ subprotocol: P,
1300
+ authStrategy: o,
1301
+ format: i
1302
+ }), c && (y = new be([y, ...c], { logger: p })), f && f.token && y.setToken(f.token, f.param || "jid"), T = T || K(L), S !== !1 && (S = S || new X({
1303
+ pingInterval: L,
1304
+ reconnectStrategy: T,
1305
+ maxMissingPings: O,
1306
+ maxReconnectAttempts: R,
1307
+ logger: p
1308
+ }));
1309
+ let u = { concurrentSubscribes: w }, b = new pe({
1310
+ protocol: t,
1311
+ transport: y,
1312
+ encoder: _,
1313
+ logger: p,
1314
+ lazy: I,
1315
+ hubOptions: u,
1316
+ performFailures: g,
1317
+ transportConfigurator: m
1318
+ });
1319
+ return S && (S.watch(b), b.monitor = S), a && ye(b, async () => {
1320
+ try {
1321
+ await a(y);
1322
+ } catch (E) {
1323
+ return p.error("Failed to refresh authentication token: " + E), !1;
1324
+ }
1325
+ return b.connect().catch(() => {
1326
+ }), !0;
1327
+ }), b;
1328
+ }
1329
+ function ye(n, e) {
1330
+ let t = !1;
1331
+ n.on("connect", () => t = !1), n.on("close", async (s) => {
1332
+ if (s) {
1333
+ if (t) {
1334
+ n.logger.warn("Token auto-refresh is disabled", s);
1335
+ return;
1336
+ }
1337
+ s.reason === "token_expired" && (t = !0, await e());
1338
+ }
1339
+ });
1340
+ }
1341
+ class we extends V {
1342
+ writeLogEntry(e, t, s) {
1343
+ s ? console[e](t, s) : console[e](t);
1344
+ }
1345
+ }
1346
+ class Se extends X {
1347
+ watch(e) {
1348
+ super.watch(e), this.initActivityListeners();
1349
+ }
1350
+ initActivityListeners() {
1351
+ if (typeof document < "u" && typeof window < "u" && document.addEventListener && window.addEventListener) {
1352
+ let e = () => {
1353
+ document.hidden || this.reconnectNow() && this.logger.debug("Trigger reconnect due to visibility change");
1354
+ }, t = (i) => {
1355
+ this.reconnectNow() && this.logger.debug("Trigger reconnect", { event: i });
1356
+ }, s = () => this.disconnect(new v("page_frozen"));
1357
+ document.addEventListener("visibilitychange", e, !1), window.addEventListener("focus", t, !1), window.addEventListener("online", t, !1), window.addEventListener("resume", t, !1), window.addEventListener("freeze", s, !1), this.unbind.push(() => {
1358
+ document.removeEventListener("visibilitychange", e, !1), window.removeEventListener("focus", t, !1), window.removeEventListener("online", t, !1), window.removeEventListener("resume", t, !1), window.removeEventListener("freeze", s, !1);
1359
+ });
1360
+ }
1361
+ }
1362
+ disconnect(e) {
1363
+ this.state === "disconnected" || this.state === "closed" || (this.logger.info("Disconnecting", { reason: e.message }), this.cancelReconnect(), this.stopPolling(), this.state = "pending_disconnect", this.target.disconnected(e));
1364
+ }
1365
+ }
1366
+ const ve = ["cable", "action-cable"], _e = "/cable", $ = (n, e) => {
1367
+ for (let t of ve) {
1368
+ let s = n.head.querySelector(`meta[name='${t}-${e}']`);
1369
+ if (s)
1370
+ return s.getAttribute("content");
1371
+ }
1372
+ }, D = (n) => n.match(/wss?:\/\//) ? n : typeof window < "u" ? `${window.location.protocol.replace("http", "ws")}//${window.location.host}${n}` : n, Ie = () => {
1373
+ if (typeof document < "u" && document.head) {
1374
+ let n = $(document, "url");
1375
+ if (n)
1376
+ return D(n);
1377
+ }
1378
+ return D(_e);
1379
+ }, Ee = () => {
1380
+ if (typeof document < "u" && document.head) {
1381
+ let n = $(document, "history-timestamp");
1382
+ if (n)
1383
+ return n | 0;
1384
+ }
1385
+ }, qe = () => {
1386
+ if (typeof document < "u" && document.head)
1387
+ return $(document, "token");
1388
+ }, Ce = () => {
1389
+ if (typeof document < "u" && document.head)
1390
+ return $(document, "token-param");
1391
+ };
1392
+ function Pe(n, e) {
1393
+ typeof n == "object" && typeof e > "u" && (e = n, n = void 0), n = n || Ie(), e = e || {}, e.historyTimestamp || (e.historyTimestamp = Ee());
1394
+ let t = qe();
1395
+ if (t) {
1396
+ let p = Ce();
1397
+ e.auth = Object.assign({ token: t, param: p }, e.auth || {});
1398
+ }
1399
+ e = Object.assign({}, Y, e);
1400
+ let {
1401
+ logLevel: s,
1402
+ logger: i,
1403
+ pingInterval: r,
1404
+ reconnectStrategy: o,
1405
+ maxMissingPings: c,
1406
+ maxReconnectAttempts: d
1407
+ } = e;
1408
+ return i = e.logger = e.logger || new we(s), o = e.reconnectStrategy = e.reconnectStrategy || K(r), e.monitor !== !1 && (e.monitor = e.monitor || new Se({
1409
+ pingInterval: r,
1410
+ reconnectStrategy: o,
1411
+ maxMissingPings: c,
1412
+ maxReconnectAttempts: d,
1413
+ logger: i
1414
+ })), me(n, e);
1415
+ }
1416
+ const ke = {
1417
+ answer: "/.netlify/functions/quiz-answer",
1418
+ sync: "/.netlify/functions/quiz-sync"
1419
+ };
1420
+ function Te(n) {
1421
+ if (typeof n != "object" || n === null) return !1;
1422
+ const e = n;
1423
+ return typeof e.sessionId == "string" && (e.activeQuizId === null || typeof e.activeQuizId == "string") && typeof e.results == "object" && e.results !== null;
1424
+ }
1425
+ function xe(n) {
1426
+ if (typeof n != "object" || n === null) return !1;
1427
+ const e = n;
1428
+ return typeof e.quizId == "string" && typeof e.answer == "string" && typeof e.sessionId == "string";
1429
+ }
1430
+ class ze {
1431
+ constructor(e) {
1432
+ this.resultsChannel = null, this.activeQuizId = null, this.results = {}, this.voters = {}, this.online = 0, this.submitted = {}, this.listeners = [], this.syncTimer = null, this.syncPending = !1, this.incomingSyncTimer = null, this.incomingSyncData = null, this.role = e.role, this.quizGroupId = e.quizGroupId, this.sessionId = e.sessionId || this.getOrCreateSessionId(), this.endpoints = { ...ke, ...e.endpoints };
1433
+ const t = e.role === "participant" ? 6e4 : 3e5;
1434
+ this.cable = Pe(e.wsUrl, {
1435
+ protocol: "actioncable-v1-ext-json",
1436
+ protocolOptions: {
1437
+ historyTimestamp: Math.floor((Date.now() - t) / 1e3)
1438
+ }
1439
+ }), this.syncChannel = this.cable.streamFrom(
1440
+ `quiz:${e.quizGroupId}:sync`
1441
+ ), this.syncChannel.on("message", this.onSyncMessage.bind(this));
1442
+ const s = this.syncChannel.presence;
1443
+ if (typeof s.stateFromInfo == "function") {
1444
+ const i = s.stateFromInfo.bind(s);
1445
+ s.stateFromInfo = (r) => {
1446
+ if (!(r != null && r.records)) {
1447
+ if (r && typeof r == "object") {
1448
+ const { type: o, ...c } = r;
1449
+ return c;
1450
+ }
1451
+ return {};
1452
+ }
1453
+ return i(r);
1454
+ };
1455
+ }
1456
+ this.syncChannel.on("presence", this.onPresence.bind(this)), e.role === "participant" && this.syncChannel.presence.join(this.sessionId, { id: this.sessionId }), this.syncChannel.presence.info().then((i) => {
1457
+ i && (this.online = Object.keys(i).length, this.notifyStateChange());
1458
+ }).catch(() => {
1459
+ }), e.role === "presenter" && (this.resultsChannel = this.cable.streamFrom(
1460
+ `quiz:${e.quizGroupId}:results`
1461
+ ), this.resultsChannel.on("message", this.onResultsMessage.bind(this)), this.restoreState(), this.activeQuizId && this.sendSync()), e.role === "participant" && this.restoreSubmitted();
1462
+ }
1463
+ // ── Public API ──
1464
+ subscribe(e) {
1465
+ return this.listeners.push(e), e(this.getState()), () => {
1466
+ const t = this.listeners.indexOf(e);
1467
+ t !== -1 && this.listeners.splice(t, 1);
1468
+ };
1469
+ }
1470
+ getState() {
1471
+ return {
1472
+ activeQuizId: this.activeQuizId,
1473
+ results: structuredClone(this.results),
1474
+ online: this.online,
1475
+ submitted: { ...this.submitted }
1476
+ };
1477
+ }
1478
+ getQuizState(e) {
1479
+ return this.results[e] || { votes: {}, total: 0 };
1480
+ }
1481
+ hasVoted(e) {
1482
+ return e in this.submitted;
1483
+ }
1484
+ getVotedAnswer(e) {
1485
+ return this.submitted[e] ?? null;
1486
+ }
1487
+ /** Presenter: set the active quiz (called when slide enters viewport) */
1488
+ setActiveQuiz(e) {
1489
+ this.role === "presenter" && this.activeQuizId !== e && (this.activeQuizId = e, this.saveState(), this.sendSync());
1490
+ }
1491
+ /** Participant: submit an answer */
1492
+ async submitAnswer(e, t) {
1493
+ if (this.hasVoted(e)) return !1;
1494
+ try {
1495
+ const s = await fetch(this.endpoints.answer, {
1496
+ method: "POST",
1497
+ headers: { "Content-Type": "application/json" },
1498
+ body: JSON.stringify({
1499
+ quizId: e,
1500
+ answer: t,
1501
+ sessionId: this.sessionId,
1502
+ quizGroupId: this.quizGroupId
1503
+ })
1504
+ });
1505
+ return s.ok && (this.submitted[e] = t, this.saveSubmitted(), this.notifyStateChange()), s.ok;
1506
+ } catch {
1507
+ return !1;
1508
+ }
1509
+ }
1510
+ disconnect() {
1511
+ this.role === "participant" && this.syncChannel.presence.leave(), this.cable.disconnect();
1512
+ }
1513
+ // ── Message Handlers ──
1514
+ onSyncMessage(e) {
1515
+ const t = this.parse(e);
1516
+ Te(t) && t.sessionId !== this.sessionId && this.role === "participant" && this.applySyncThrottled(t);
1517
+ }
1518
+ applySyncThrottled(e) {
1519
+ if (this.incomingSyncTimer) {
1520
+ this.incomingSyncData = e;
1521
+ return;
1522
+ }
1523
+ this.applySync(e), this.incomingSyncData = null, this.incomingSyncTimer = setTimeout(() => {
1524
+ this.incomingSyncTimer = null, this.incomingSyncData && (this.applySync(this.incomingSyncData), this.incomingSyncData = null);
1525
+ }, 200);
1526
+ }
1527
+ applySync(e) {
1528
+ var t;
1529
+ this.activeQuizId = e.activeQuizId, this.results = e.results;
1530
+ for (const s of Object.keys(this.submitted))
1531
+ (((t = e.results[s]) == null ? void 0 : t.total) ?? 0) === 0 && this.clearVotedAnswer(s);
1532
+ this.notifyStateChange();
1533
+ }
1534
+ onResultsMessage(e) {
1535
+ if (this.role !== "presenter") return;
1536
+ const t = this.parse(e);
1537
+ if (!xe(t) || t.sessionId === this.sessionId) return;
1538
+ const { quizId: s, answer: i, sessionId: r } = t;
1539
+ this.voters[s] || (this.voters[s] = /* @__PURE__ */ new Set()), !this.voters[s].has(r) && (this.voters[s].add(r), this.results[s] || (this.results[s] = { votes: {}, total: 0 }), this.results[s].votes[i] = (this.results[s].votes[i] || 0) + 1, this.results[s].total += 1, this.saveState(), this.notifyStateChange(), this.sendSyncThrottled());
1540
+ }
1541
+ async onPresence() {
1542
+ try {
1543
+ const e = await this.syncChannel.presence.info();
1544
+ e && (this.online = Object.keys(e).length, this.notifyStateChange(), this.role === "presenter" && this.activeQuizId && this.sendSyncThrottled());
1545
+ } catch {
1546
+ }
1547
+ }
1548
+ // ── Sync Broadcasting ──
1549
+ sendSyncThrottled() {
1550
+ if (this.syncTimer) {
1551
+ this.syncPending = !0;
1552
+ return;
1553
+ }
1554
+ this.sendSync(), this.syncTimer = setTimeout(() => {
1555
+ this.syncTimer = null, this.syncPending && (this.syncPending = !1, this.sendSync());
1556
+ }, 200);
1557
+ }
1558
+ async sendSync() {
1559
+ if (this.role === "presenter")
1560
+ try {
1561
+ await fetch(this.endpoints.sync, {
1562
+ method: "POST",
1563
+ headers: { "Content-Type": "application/json" },
1564
+ body: JSON.stringify({
1565
+ activeQuizId: this.activeQuizId,
1566
+ sessionId: this.sessionId,
1567
+ quizGroupId: this.quizGroupId,
1568
+ results: this.results
1569
+ })
1570
+ });
1571
+ } catch {
1572
+ }
1573
+ }
1574
+ // ── Persistence ──
1575
+ getOrCreateSessionId() {
1576
+ const e = `quiz-session-${this.quizGroupId}`;
1577
+ let t = sessionStorage.getItem(e);
1578
+ return t || (t = crypto.randomUUID(), sessionStorage.setItem(e, t)), t;
1579
+ }
1580
+ saveState() {
1581
+ if (this.role === "presenter")
1582
+ try {
1583
+ sessionStorage.setItem(
1584
+ `quiz-presenter-${this.quizGroupId}`,
1585
+ JSON.stringify({
1586
+ activeQuizId: this.activeQuizId,
1587
+ results: this.results,
1588
+ voters: Object.fromEntries(
1589
+ Object.entries(this.voters).map(([e, t]) => [e, [...t]])
1590
+ )
1591
+ })
1592
+ );
1593
+ } catch (e) {
1594
+ console.warn("[QuizManager] saveState failed:", e);
1595
+ }
1596
+ }
1597
+ restoreState() {
1598
+ try {
1599
+ const e = sessionStorage.getItem(
1600
+ `quiz-presenter-${this.quizGroupId}`
1601
+ );
1602
+ if (!e) return;
1603
+ const t = JSON.parse(e);
1604
+ if (t.activeQuizId && (this.activeQuizId = t.activeQuizId), t.results && (this.results = t.results), t.voters)
1605
+ for (const [s, i] of Object.entries(t.voters))
1606
+ this.voters[s] = new Set(i);
1607
+ } catch {
1608
+ }
1609
+ }
1610
+ saveSubmitted() {
1611
+ try {
1612
+ sessionStorage.setItem(
1613
+ `quiz-submitted-${this.quizGroupId}`,
1614
+ JSON.stringify(this.submitted)
1615
+ );
1616
+ } catch {
1617
+ }
1618
+ }
1619
+ restoreSubmitted() {
1620
+ try {
1621
+ const e = sessionStorage.getItem(
1622
+ `quiz-submitted-${this.quizGroupId}`
1623
+ );
1624
+ if (!e) return;
1625
+ this.submitted = JSON.parse(e);
1626
+ } catch {
1627
+ }
1628
+ }
1629
+ clearVotedAnswer(e) {
1630
+ delete this.submitted[e], this.saveSubmitted();
1631
+ }
1632
+ // ── Helpers ──
1633
+ notifyStateChange() {
1634
+ const e = this.getState();
1635
+ for (const t of this.listeners) t(e);
1636
+ }
1637
+ parse(e) {
1638
+ if (typeof e == "string")
1639
+ try {
1640
+ return JSON.parse(e);
1641
+ } catch {
1642
+ return {};
1643
+ }
1644
+ return e && typeof e == "object" ? e : {};
1645
+ }
1646
+ }
1647
+ const M = /* @__PURE__ */ new Map();
1648
+ function Le(n) {
1649
+ return M.has(n.quizGroupId) || M.set(
1650
+ n.quizGroupId,
1651
+ new ze({ ...n, role: "participant" })
1652
+ ), M.get(n.quizGroupId);
1653
+ }
1654
+ function Oe(n, e) {
1655
+ const t = document.querySelector(n);
1656
+ if (!t)
1657
+ throw new Error(`[live-quiz] Element not found: ${n}`);
1658
+ const { questions: s, brandText: i, footerText: r = "Powered by AnyCable" } = e;
1659
+ if (t.innerHTML = "", t.classList.add("lq-participant"), i) {
1660
+ const a = document.createElement("p");
1661
+ a.className = "lq-participant__brand", a.textContent = i, t.appendChild(a);
1662
+ }
1663
+ const o = document.createElement("div");
1664
+ o.className = "lq-participant__stats";
1665
+ const c = document.createElement("span");
1666
+ c.className = "lq-participant__online", c.textContent = "0";
1667
+ const d = document.createElement("span");
1668
+ d.className = "lq-participant__answered", d.textContent = "0", o.append(c, " online · ", d, " answered"), t.appendChild(o);
1669
+ const p = document.createElement("div");
1670
+ p.className = "lq-participant__waiting", p.textContent = "Waiting for the next question...", t.appendChild(p);
1671
+ const y = {};
1672
+ let _ = 0;
1673
+ for (const a of s) {
1674
+ const h = document.createElement("div");
1675
+ h.className = "lq-participant__section lq-participant__section--hidden", h.dataset.quizId = a.quizId;
1676
+ const l = document.createElement("p");
1677
+ l.className = "lq-participant__number", l.textContent = `Question ${_ + 1} of ${s.length}`, h.appendChild(l);
1678
+ const w = document.createElement("h2");
1679
+ w.className = "lq-participant__question", w.textContent = a.question, h.appendChild(w);
1680
+ const g = document.createElement("div");
1681
+ g.className = "lq-participant__options";
1682
+ for (const f of a.options) {
1683
+ const u = document.createElement("button");
1684
+ u.type = "button", u.className = "lq-participant__btn", u.dataset.answer = f.label;
1685
+ const b = document.createElement("span");
1686
+ b.className = "lq-participant__btn-label", b.textContent = f.label;
1687
+ const E = document.createElement("span");
1688
+ E.textContent = f.text, u.append(b, E), g.appendChild(u);
1689
+ }
1690
+ h.appendChild(g);
1691
+ const m = document.createElement("p");
1692
+ m.className = "lq-participant__status", m.setAttribute("role", "status"), m.setAttribute("aria-live", "polite"), h.appendChild(m), t.appendChild(h), y[a.quizId] = h, _++;
1693
+ }
1694
+ if (r) {
1695
+ const a = document.createElement("p");
1696
+ a.className = "lq-participant__footer", a.textContent = r, t.appendChild(a);
1697
+ }
1698
+ const I = Le({
1699
+ wsUrl: e.wsUrl,
1700
+ quizGroupId: e.quizGroupId,
1701
+ endpoints: e.endpoints
1702
+ });
1703
+ let S = null;
1704
+ function L(a) {
1705
+ S = a;
1706
+ for (const [h, l] of Object.entries(y))
1707
+ h === a ? l.classList.remove("lq-participant__section--hidden") : l.classList.add("lq-participant__section--hidden");
1708
+ a ? p.style.display = "none" : p.style.display = "";
1709
+ }
1710
+ function T(a, h) {
1711
+ var u;
1712
+ const l = y[a];
1713
+ if (!l) return;
1714
+ const w = l.querySelectorAll(".lq-participant__btn"), g = l.querySelector(".lq-participant__status");
1715
+ for (const b of w)
1716
+ b.disabled = !0, b.setAttribute("aria-disabled", "true"), b.dataset.answer === h ? b.classList.add("lq-participant__btn--selected") : b.classList.add("lq-participant__btn--faded");
1717
+ const m = ((u = l.querySelector(`[data-answer="${h}"] span:last-child`)) == null ? void 0 : u.textContent) || h;
1718
+ g.textContent = "";
1719
+ const f = document.createElement("strong");
1720
+ f.textContent = m, g.append(f, " — submitted!");
1721
+ }
1722
+ function O(a) {
1723
+ const h = y[a];
1724
+ if (!h) return;
1725
+ const l = h.querySelectorAll(".lq-participant__btn"), w = h.querySelector(".lq-participant__status");
1726
+ for (const g of l)
1727
+ g.disabled = !1, g.removeAttribute("aria-disabled"), g.classList.remove("lq-participant__btn--selected", "lq-participant__btn--faded");
1728
+ w.textContent = "";
1729
+ }
1730
+ const R = I.subscribe((a) => {
1731
+ a.activeQuizId !== void 0 && L(a.activeQuizId), c.textContent = String(a.online), S && a.results[S] && (d.textContent = String(
1732
+ a.results[S].total
1733
+ ));
1734
+ for (const h of s) {
1735
+ const l = a.submitted[h.quizId];
1736
+ l ? T(h.quizId, l) : O(h.quizId);
1737
+ }
1738
+ });
1739
+ for (const a of s) {
1740
+ const h = y[a.quizId];
1741
+ if (!h) continue;
1742
+ const l = h.querySelectorAll(".lq-participant__btn"), w = h.querySelector(".lq-participant__status");
1743
+ async function g(m) {
1744
+ for (const u of l)
1745
+ u.disabled = !0, u.setAttribute("aria-disabled", "true"), u.dataset.answer === m ? u.classList.add("lq-participant__btn--selected") : u.classList.add("lq-participant__btn--faded");
1746
+ if (w.textContent = "Sending...", !await I.submitAnswer(a.quizId, m) && !I.hasVoted(a.quizId)) {
1747
+ w.textContent = "Something went wrong. Try again!";
1748
+ for (const u of l)
1749
+ u.disabled = !1, u.removeAttribute("aria-disabled"), u.classList.remove(
1750
+ "lq-participant__btn--selected",
1751
+ "lq-participant__btn--faded"
1752
+ );
1753
+ }
1754
+ }
1755
+ for (const m of l)
1756
+ m.addEventListener("click", () => {
1757
+ const f = m.dataset.answer;
1758
+ f && !I.hasVoted(a.quizId) && g(f);
1759
+ });
1760
+ }
1761
+ function P() {
1762
+ I.disconnect();
1763
+ }
1764
+ return window.addEventListener("pagehide", P), {
1765
+ destroy() {
1766
+ R(), window.removeEventListener("pagehide", P), I.disconnect(), t.innerHTML = "", t.classList.remove("lq-participant");
1767
+ }
1768
+ };
1769
+ }
1770
+ export {
1771
+ Oe as createParticipantUI
1772
+ };