p2p-lockstep-kit-ui 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.
package/dist/index.js ADDED
@@ -0,0 +1,3953 @@
1
+ //#region \0rolldown/runtime.js
2
+ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescriptor, r = Object.getOwnPropertyNames, i = Object.getPrototypeOf, a = Object.prototype.hasOwnProperty, o = (e, t) => () => (t || e((t = { exports: {} }).exports, t), t.exports), s = (e, i, o, s) => {
3
+ if (i && typeof i == "object" || typeof i == "function") for (var c = r(i), l = 0, u = c.length, d; l < u; l++) d = c[l], !a.call(e, d) && d !== o && t(e, d, {
4
+ get: ((e) => i[e]).bind(null, d),
5
+ enumerable: !(s = n(i, d)) || s.enumerable
6
+ });
7
+ return e;
8
+ }, c = (n, r, a) => (a = n == null ? {} : e(i(n)), s(r || !n || !n.__esModule ? t(a, "default", {
9
+ value: n,
10
+ enumerable: !0
11
+ }) : a, n)), l = (e, t, n) => {
12
+ e.dispatchEvent(new CustomEvent(t, {
13
+ bubbles: !0,
14
+ composed: !0,
15
+ detail: n
16
+ }));
17
+ }, u = {
18
+ connected: !1,
19
+ readySelf: !1,
20
+ canReady: !1,
21
+ canStart: !1,
22
+ canUndo: !1,
23
+ canRestart: !1,
24
+ started: !1,
25
+ connectionState: "idle"
26
+ }, d = class extends HTMLElement {
27
+ #e = u;
28
+ #t = !1;
29
+ connectedCallback() {
30
+ this.#t || (this.#t = !0, this.addEventListener("click", this.#n), this.render());
31
+ }
32
+ disconnectedCallback() {
33
+ this.removeEventListener("click", this.#n);
34
+ }
35
+ set state(e) {
36
+ this.#e = e, this.#t && this.render();
37
+ }
38
+ get state() {
39
+ return this.#e;
40
+ }
41
+ render() {
42
+ let { canReady: e, canStart: t, canUndo: n, canRestart: r, connected: i, readySelf: a, started: o } = this.#e, s = t ? "start" : a || e ? "ready" : "", c = t ? "Start" : a ? "Unready" : e ? "Ready" : i ? "Waiting" : "Waiting for connection", l = !o || !!s, u = o ? "In game" : t ? "Start ready" : a ? "Ready" : "Setup";
43
+ this.className = "block", this.innerHTML = `
44
+ <section class="lock-panel rounded-[1.25rem] p-2.5 sm:rounded-[1.5rem] sm:p-3 lg:rounded-[1.75rem] lg:p-2.5">
45
+ <div class="flex flex-col gap-2 sm:gap-3">
46
+ <div class="hidden items-center justify-between gap-3 px-1 lg:flex">
47
+ <p class="text-[0.62rem] font-semibold uppercase tracking-[0.2em] text-[var(--lock-dim)]">Controls</p>
48
+ <span class="rounded-full border border-[var(--lock-border)] px-2.5 py-1 text-[0.65rem] text-[var(--lock-muted)]">${u}</span>
49
+ </div>
50
+
51
+ ${l ? `<button
52
+ type="button"
53
+ data-action="${s}"
54
+ class="lock-disabled inline-flex items-center justify-center rounded-full px-4 py-2.5 text-sm font-semibold transition sm:py-3 ${t ? "lock-primary" : e ? "bg-[var(--lock-teal)] text-[#08120f] shadow-[0_12px_32px_rgba(110,231,200,0.22)] hover:brightness-105" : "lock-secondary"}"
55
+ ${s ? "" : "disabled"}
56
+ >
57
+ ${c}
58
+ </button>` : ""}
59
+
60
+ <div class="grid grid-cols-2 gap-2 sm:gap-3">
61
+ <button
62
+ type="button"
63
+ data-action="undo"
64
+ class="lock-secondary lock-disabled inline-flex items-center justify-center rounded-full px-3 py-2.5 text-xs font-semibold transition sm:px-4 sm:py-3 sm:text-sm"
65
+ ${n ? "" : "disabled"}
66
+ >
67
+ Undo
68
+ </button>
69
+ <button
70
+ type="button"
71
+ data-action="restart"
72
+ class="lock-secondary lock-disabled inline-flex items-center justify-center rounded-full px-3 py-2.5 text-xs font-semibold transition sm:px-4 sm:py-3 sm:text-sm"
73
+ ${r ? "" : "disabled"}
74
+ >
75
+ Restart
76
+ </button>
77
+ </div>
78
+ </div>
79
+ </section>
80
+ `;
81
+ }
82
+ #n = (e) => {
83
+ let t = e.target?.closest("button[data-action]");
84
+ !t || t.disabled || l(this, `lockstep-${t.dataset.action}`);
85
+ };
86
+ }, f = (e) => String(e ?? ""), p = (e, t, n) => {
87
+ let r = e.querySelector(t);
88
+ return r && (r.textContent = f(n)), r;
89
+ }, m = (e, t, n) => {
90
+ let r = e.querySelector(t);
91
+ return r && r.value !== f(n) && (r.value = f(n)), r;
92
+ }, h = {
93
+ open: !1,
94
+ title: "",
95
+ description: "",
96
+ confirmLabel: "Confirm",
97
+ cancelLabel: "Cancel"
98
+ }, g = class extends HTMLElement {
99
+ #e = h;
100
+ #t = !1;
101
+ connectedCallback() {
102
+ this.#t || (this.#t = !0, this.addEventListener("click", this.#n), this.render());
103
+ }
104
+ disconnectedCallback() {
105
+ this.removeEventListener("click", this.#n);
106
+ }
107
+ set state(e) {
108
+ this.#e = e, this.#t && this.render();
109
+ }
110
+ get state() {
111
+ return this.#e;
112
+ }
113
+ render() {
114
+ let { open: e } = this.#e;
115
+ this.className = e ? "fixed inset-0 z-50 block" : "hidden", this.innerHTML = "\n <div data-overlay class=\"absolute inset-0 bg-[rgba(7,6,4,0.76)] backdrop-blur-sm\"></div>\n <div class=\"relative flex min-h-full items-end justify-center p-4 sm:items-center\">\n <section class=\"lock-panel w-full max-w-md rounded-[2rem] p-6\">\n <div class=\"space-y-3\">\n <p class=\"text-[0.72rem] uppercase tracking-[0.28em] text-[var(--lock-bronze-bright)]\">Action Required</p>\n <h3 data-title class=\"lock-title text-2xl font-semibold text-[var(--lock-paper)]\"></h3>\n <p data-description class=\"text-sm leading-6 text-[var(--lock-muted)]\"></p>\n </div>\n\n <div class=\"mt-6 grid gap-3 sm:grid-cols-2\">\n <button\n type=\"button\"\n data-action=\"confirm\"\n class=\"lock-primary inline-flex items-center justify-center rounded-full px-4 py-3 text-sm font-semibold transition\"\n >\n <span data-confirm-label></span>\n </button>\n <button\n type=\"button\"\n data-action=\"cancel\"\n class=\"lock-secondary inline-flex items-center justify-center rounded-full px-4 py-3 text-sm font-semibold transition\"\n >\n <span data-cancel-label></span>\n </button>\n </div>\n </section>\n </div>\n ", p(this, "[data-title]", this.#e.title), p(this, "[data-description]", this.#e.description), p(this, "[data-confirm-label]", this.#e.confirmLabel), p(this, "[data-cancel-label]", this.#e.cancelLabel);
116
+ }
117
+ #n = (e) => {
118
+ let t = e.target;
119
+ if (t) {
120
+ if (t.matches("[data-overlay]") || t.closest("[data-action='cancel']")) {
121
+ l(this, "lockstep-dialog-cancel");
122
+ return;
123
+ }
124
+ t.closest("[data-action='confirm']") && l(this, "lockstep-dialog-confirm");
125
+ }
126
+ };
127
+ }, _ = /* @__PURE__ */ o(((e, t) => {
128
+ t.exports = function() {
129
+ return typeof Promise == "function" && Promise.prototype && Promise.prototype.then;
130
+ };
131
+ })), v = /* @__PURE__ */ o(((e) => {
132
+ var t, n = [
133
+ 0,
134
+ 26,
135
+ 44,
136
+ 70,
137
+ 100,
138
+ 134,
139
+ 172,
140
+ 196,
141
+ 242,
142
+ 292,
143
+ 346,
144
+ 404,
145
+ 466,
146
+ 532,
147
+ 581,
148
+ 655,
149
+ 733,
150
+ 815,
151
+ 901,
152
+ 991,
153
+ 1085,
154
+ 1156,
155
+ 1258,
156
+ 1364,
157
+ 1474,
158
+ 1588,
159
+ 1706,
160
+ 1828,
161
+ 1921,
162
+ 2051,
163
+ 2185,
164
+ 2323,
165
+ 2465,
166
+ 2611,
167
+ 2761,
168
+ 2876,
169
+ 3034,
170
+ 3196,
171
+ 3362,
172
+ 3532,
173
+ 3706
174
+ ];
175
+ e.getSymbolSize = function(e) {
176
+ if (!e) throw Error("\"version\" cannot be null or undefined");
177
+ if (e < 1 || e > 40) throw Error("\"version\" should be in range from 1 to 40");
178
+ return e * 4 + 17;
179
+ }, e.getSymbolTotalCodewords = function(e) {
180
+ return n[e];
181
+ }, e.getBCHDigit = function(e) {
182
+ let t = 0;
183
+ for (; e !== 0;) t++, e >>>= 1;
184
+ return t;
185
+ }, e.setToSJISFunction = function(e) {
186
+ if (typeof e != "function") throw Error("\"toSJISFunc\" is not a valid function.");
187
+ t = e;
188
+ }, e.isKanjiModeEnabled = function() {
189
+ return t !== void 0;
190
+ }, e.toSJIS = function(e) {
191
+ return t(e);
192
+ };
193
+ })), y = /* @__PURE__ */ o(((e) => {
194
+ e.L = { bit: 1 }, e.M = { bit: 0 }, e.Q = { bit: 3 }, e.H = { bit: 2 };
195
+ function t(t) {
196
+ if (typeof t != "string") throw Error("Param is not a string");
197
+ switch (t.toLowerCase()) {
198
+ case "l":
199
+ case "low": return e.L;
200
+ case "m":
201
+ case "medium": return e.M;
202
+ case "q":
203
+ case "quartile": return e.Q;
204
+ case "h":
205
+ case "high": return e.H;
206
+ default: throw Error("Unknown EC Level: " + t);
207
+ }
208
+ }
209
+ e.isValid = function(e) {
210
+ return e && e.bit !== void 0 && e.bit >= 0 && e.bit < 4;
211
+ }, e.from = function(n, r) {
212
+ if (e.isValid(n)) return n;
213
+ try {
214
+ return t(n);
215
+ } catch {
216
+ return r;
217
+ }
218
+ };
219
+ })), b = /* @__PURE__ */ o(((e, t) => {
220
+ function n() {
221
+ this.buffer = [], this.length = 0;
222
+ }
223
+ n.prototype = {
224
+ get: function(e) {
225
+ let t = Math.floor(e / 8);
226
+ return (this.buffer[t] >>> 7 - e % 8 & 1) == 1;
227
+ },
228
+ put: function(e, t) {
229
+ for (let n = 0; n < t; n++) this.putBit((e >>> t - n - 1 & 1) == 1);
230
+ },
231
+ getLengthInBits: function() {
232
+ return this.length;
233
+ },
234
+ putBit: function(e) {
235
+ let t = Math.floor(this.length / 8);
236
+ this.buffer.length <= t && this.buffer.push(0), e && (this.buffer[t] |= 128 >>> this.length % 8), this.length++;
237
+ }
238
+ }, t.exports = n;
239
+ })), x = /* @__PURE__ */ o(((e, t) => {
240
+ function n(e) {
241
+ if (!e || e < 1) throw Error("BitMatrix size must be defined and greater than 0");
242
+ this.size = e, this.data = new Uint8Array(e * e), this.reservedBit = new Uint8Array(e * e);
243
+ }
244
+ n.prototype.set = function(e, t, n, r) {
245
+ let i = e * this.size + t;
246
+ this.data[i] = n, r && (this.reservedBit[i] = !0);
247
+ }, n.prototype.get = function(e, t) {
248
+ return this.data[e * this.size + t];
249
+ }, n.prototype.xor = function(e, t, n) {
250
+ this.data[e * this.size + t] ^= n;
251
+ }, n.prototype.isReserved = function(e, t) {
252
+ return this.reservedBit[e * this.size + t];
253
+ }, t.exports = n;
254
+ })), S = /* @__PURE__ */ o(((e) => {
255
+ var t = v().getSymbolSize;
256
+ e.getRowColCoords = function(e) {
257
+ if (e === 1) return [];
258
+ let n = Math.floor(e / 7) + 2, r = t(e), i = r === 145 ? 26 : Math.ceil((r - 13) / (2 * n - 2)) * 2, a = [r - 7];
259
+ for (let e = 1; e < n - 1; e++) a[e] = a[e - 1] - i;
260
+ return a.push(6), a.reverse();
261
+ }, e.getPositions = function(t) {
262
+ let n = [], r = e.getRowColCoords(t), i = r.length;
263
+ for (let e = 0; e < i; e++) for (let t = 0; t < i; t++) e === 0 && t === 0 || e === 0 && t === i - 1 || e === i - 1 && t === 0 || n.push([r[e], r[t]]);
264
+ return n;
265
+ };
266
+ })), C = /* @__PURE__ */ o(((e) => {
267
+ var t = v().getSymbolSize, n = 7;
268
+ e.getPositions = function(e) {
269
+ let r = t(e);
270
+ return [
271
+ [0, 0],
272
+ [r - n, 0],
273
+ [0, r - n]
274
+ ];
275
+ };
276
+ })), ee = /* @__PURE__ */ o(((e) => {
277
+ e.Patterns = {
278
+ PATTERN000: 0,
279
+ PATTERN001: 1,
280
+ PATTERN010: 2,
281
+ PATTERN011: 3,
282
+ PATTERN100: 4,
283
+ PATTERN101: 5,
284
+ PATTERN110: 6,
285
+ PATTERN111: 7
286
+ };
287
+ var t = {
288
+ N1: 3,
289
+ N2: 3,
290
+ N3: 40,
291
+ N4: 10
292
+ };
293
+ e.isValid = function(e) {
294
+ return e != null && e !== "" && !isNaN(e) && e >= 0 && e <= 7;
295
+ }, e.from = function(t) {
296
+ return e.isValid(t) ? parseInt(t, 10) : void 0;
297
+ }, e.getPenaltyN1 = function(e) {
298
+ let n = e.size, r = 0, i = 0, a = 0, o = null, s = null;
299
+ for (let c = 0; c < n; c++) {
300
+ i = a = 0, o = s = null;
301
+ for (let l = 0; l < n; l++) {
302
+ let n = e.get(c, l);
303
+ n === o ? i++ : (i >= 5 && (r += t.N1 + (i - 5)), o = n, i = 1), n = e.get(l, c), n === s ? a++ : (a >= 5 && (r += t.N1 + (a - 5)), s = n, a = 1);
304
+ }
305
+ i >= 5 && (r += t.N1 + (i - 5)), a >= 5 && (r += t.N1 + (a - 5));
306
+ }
307
+ return r;
308
+ }, e.getPenaltyN2 = function(e) {
309
+ let n = e.size, r = 0;
310
+ for (let t = 0; t < n - 1; t++) for (let i = 0; i < n - 1; i++) {
311
+ let n = e.get(t, i) + e.get(t, i + 1) + e.get(t + 1, i) + e.get(t + 1, i + 1);
312
+ (n === 4 || n === 0) && r++;
313
+ }
314
+ return r * t.N2;
315
+ }, e.getPenaltyN3 = function(e) {
316
+ let n = e.size, r = 0, i = 0, a = 0;
317
+ for (let t = 0; t < n; t++) {
318
+ i = a = 0;
319
+ for (let o = 0; o < n; o++) i = i << 1 & 2047 | e.get(t, o), o >= 10 && (i === 1488 || i === 93) && r++, a = a << 1 & 2047 | e.get(o, t), o >= 10 && (a === 1488 || a === 93) && r++;
320
+ }
321
+ return r * t.N3;
322
+ }, e.getPenaltyN4 = function(e) {
323
+ let n = 0, r = e.data.length;
324
+ for (let t = 0; t < r; t++) n += e.data[t];
325
+ return Math.abs(Math.ceil(n * 100 / r / 5) - 10) * t.N4;
326
+ };
327
+ function n(t, n, r) {
328
+ switch (t) {
329
+ case e.Patterns.PATTERN000: return (n + r) % 2 == 0;
330
+ case e.Patterns.PATTERN001: return n % 2 == 0;
331
+ case e.Patterns.PATTERN010: return r % 3 == 0;
332
+ case e.Patterns.PATTERN011: return (n + r) % 3 == 0;
333
+ case e.Patterns.PATTERN100: return (Math.floor(n / 2) + Math.floor(r / 3)) % 2 == 0;
334
+ case e.Patterns.PATTERN101: return n * r % 2 + n * r % 3 == 0;
335
+ case e.Patterns.PATTERN110: return (n * r % 2 + n * r % 3) % 2 == 0;
336
+ case e.Patterns.PATTERN111: return (n * r % 3 + (n + r) % 2) % 2 == 0;
337
+ default: throw Error("bad maskPattern:" + t);
338
+ }
339
+ }
340
+ e.applyMask = function(e, t) {
341
+ let r = t.size;
342
+ for (let i = 0; i < r; i++) for (let a = 0; a < r; a++) t.isReserved(a, i) || t.xor(a, i, n(e, a, i));
343
+ }, e.getBestMask = function(t, n) {
344
+ let r = Object.keys(e.Patterns).length, i = 0, a = Infinity;
345
+ for (let o = 0; o < r; o++) {
346
+ n(o), e.applyMask(o, t);
347
+ let r = e.getPenaltyN1(t) + e.getPenaltyN2(t) + e.getPenaltyN3(t) + e.getPenaltyN4(t);
348
+ e.applyMask(o, t), r < a && (a = r, i = o);
349
+ }
350
+ return i;
351
+ };
352
+ })), w = /* @__PURE__ */ o(((e) => {
353
+ var t = y(), n = [
354
+ 1,
355
+ 1,
356
+ 1,
357
+ 1,
358
+ 1,
359
+ 1,
360
+ 1,
361
+ 1,
362
+ 1,
363
+ 1,
364
+ 2,
365
+ 2,
366
+ 1,
367
+ 2,
368
+ 2,
369
+ 4,
370
+ 1,
371
+ 2,
372
+ 4,
373
+ 4,
374
+ 2,
375
+ 4,
376
+ 4,
377
+ 4,
378
+ 2,
379
+ 4,
380
+ 6,
381
+ 5,
382
+ 2,
383
+ 4,
384
+ 6,
385
+ 6,
386
+ 2,
387
+ 5,
388
+ 8,
389
+ 8,
390
+ 4,
391
+ 5,
392
+ 8,
393
+ 8,
394
+ 4,
395
+ 5,
396
+ 8,
397
+ 11,
398
+ 4,
399
+ 8,
400
+ 10,
401
+ 11,
402
+ 4,
403
+ 9,
404
+ 12,
405
+ 16,
406
+ 4,
407
+ 9,
408
+ 16,
409
+ 16,
410
+ 6,
411
+ 10,
412
+ 12,
413
+ 18,
414
+ 6,
415
+ 10,
416
+ 17,
417
+ 16,
418
+ 6,
419
+ 11,
420
+ 16,
421
+ 19,
422
+ 6,
423
+ 13,
424
+ 18,
425
+ 21,
426
+ 7,
427
+ 14,
428
+ 21,
429
+ 25,
430
+ 8,
431
+ 16,
432
+ 20,
433
+ 25,
434
+ 8,
435
+ 17,
436
+ 23,
437
+ 25,
438
+ 9,
439
+ 17,
440
+ 23,
441
+ 34,
442
+ 9,
443
+ 18,
444
+ 25,
445
+ 30,
446
+ 10,
447
+ 20,
448
+ 27,
449
+ 32,
450
+ 12,
451
+ 21,
452
+ 29,
453
+ 35,
454
+ 12,
455
+ 23,
456
+ 34,
457
+ 37,
458
+ 12,
459
+ 25,
460
+ 34,
461
+ 40,
462
+ 13,
463
+ 26,
464
+ 35,
465
+ 42,
466
+ 14,
467
+ 28,
468
+ 38,
469
+ 45,
470
+ 15,
471
+ 29,
472
+ 40,
473
+ 48,
474
+ 16,
475
+ 31,
476
+ 43,
477
+ 51,
478
+ 17,
479
+ 33,
480
+ 45,
481
+ 54,
482
+ 18,
483
+ 35,
484
+ 48,
485
+ 57,
486
+ 19,
487
+ 37,
488
+ 51,
489
+ 60,
490
+ 19,
491
+ 38,
492
+ 53,
493
+ 63,
494
+ 20,
495
+ 40,
496
+ 56,
497
+ 66,
498
+ 21,
499
+ 43,
500
+ 59,
501
+ 70,
502
+ 22,
503
+ 45,
504
+ 62,
505
+ 74,
506
+ 24,
507
+ 47,
508
+ 65,
509
+ 77,
510
+ 25,
511
+ 49,
512
+ 68,
513
+ 81
514
+ ], r = [
515
+ 7,
516
+ 10,
517
+ 13,
518
+ 17,
519
+ 10,
520
+ 16,
521
+ 22,
522
+ 28,
523
+ 15,
524
+ 26,
525
+ 36,
526
+ 44,
527
+ 20,
528
+ 36,
529
+ 52,
530
+ 64,
531
+ 26,
532
+ 48,
533
+ 72,
534
+ 88,
535
+ 36,
536
+ 64,
537
+ 96,
538
+ 112,
539
+ 40,
540
+ 72,
541
+ 108,
542
+ 130,
543
+ 48,
544
+ 88,
545
+ 132,
546
+ 156,
547
+ 60,
548
+ 110,
549
+ 160,
550
+ 192,
551
+ 72,
552
+ 130,
553
+ 192,
554
+ 224,
555
+ 80,
556
+ 150,
557
+ 224,
558
+ 264,
559
+ 96,
560
+ 176,
561
+ 260,
562
+ 308,
563
+ 104,
564
+ 198,
565
+ 288,
566
+ 352,
567
+ 120,
568
+ 216,
569
+ 320,
570
+ 384,
571
+ 132,
572
+ 240,
573
+ 360,
574
+ 432,
575
+ 144,
576
+ 280,
577
+ 408,
578
+ 480,
579
+ 168,
580
+ 308,
581
+ 448,
582
+ 532,
583
+ 180,
584
+ 338,
585
+ 504,
586
+ 588,
587
+ 196,
588
+ 364,
589
+ 546,
590
+ 650,
591
+ 224,
592
+ 416,
593
+ 600,
594
+ 700,
595
+ 224,
596
+ 442,
597
+ 644,
598
+ 750,
599
+ 252,
600
+ 476,
601
+ 690,
602
+ 816,
603
+ 270,
604
+ 504,
605
+ 750,
606
+ 900,
607
+ 300,
608
+ 560,
609
+ 810,
610
+ 960,
611
+ 312,
612
+ 588,
613
+ 870,
614
+ 1050,
615
+ 336,
616
+ 644,
617
+ 952,
618
+ 1110,
619
+ 360,
620
+ 700,
621
+ 1020,
622
+ 1200,
623
+ 390,
624
+ 728,
625
+ 1050,
626
+ 1260,
627
+ 420,
628
+ 784,
629
+ 1140,
630
+ 1350,
631
+ 450,
632
+ 812,
633
+ 1200,
634
+ 1440,
635
+ 480,
636
+ 868,
637
+ 1290,
638
+ 1530,
639
+ 510,
640
+ 924,
641
+ 1350,
642
+ 1620,
643
+ 540,
644
+ 980,
645
+ 1440,
646
+ 1710,
647
+ 570,
648
+ 1036,
649
+ 1530,
650
+ 1800,
651
+ 570,
652
+ 1064,
653
+ 1590,
654
+ 1890,
655
+ 600,
656
+ 1120,
657
+ 1680,
658
+ 1980,
659
+ 630,
660
+ 1204,
661
+ 1770,
662
+ 2100,
663
+ 660,
664
+ 1260,
665
+ 1860,
666
+ 2220,
667
+ 720,
668
+ 1316,
669
+ 1950,
670
+ 2310,
671
+ 750,
672
+ 1372,
673
+ 2040,
674
+ 2430
675
+ ];
676
+ e.getBlocksCount = function(e, r) {
677
+ switch (r) {
678
+ case t.L: return n[(e - 1) * 4 + 0];
679
+ case t.M: return n[(e - 1) * 4 + 1];
680
+ case t.Q: return n[(e - 1) * 4 + 2];
681
+ case t.H: return n[(e - 1) * 4 + 3];
682
+ default: return;
683
+ }
684
+ }, e.getTotalCodewordsCount = function(e, n) {
685
+ switch (n) {
686
+ case t.L: return r[(e - 1) * 4 + 0];
687
+ case t.M: return r[(e - 1) * 4 + 1];
688
+ case t.Q: return r[(e - 1) * 4 + 2];
689
+ case t.H: return r[(e - 1) * 4 + 3];
690
+ default: return;
691
+ }
692
+ };
693
+ })), T = /* @__PURE__ */ o(((e) => {
694
+ var t = new Uint8Array(512), n = new Uint8Array(256);
695
+ (function() {
696
+ let e = 1;
697
+ for (let r = 0; r < 255; r++) t[r] = e, n[e] = r, e <<= 1, e & 256 && (e ^= 285);
698
+ for (let e = 255; e < 512; e++) t[e] = t[e - 255];
699
+ })(), e.log = function(e) {
700
+ if (e < 1) throw Error("log(" + e + ")");
701
+ return n[e];
702
+ }, e.exp = function(e) {
703
+ return t[e];
704
+ }, e.mul = function(e, r) {
705
+ return e === 0 || r === 0 ? 0 : t[n[e] + n[r]];
706
+ };
707
+ })), te = /* @__PURE__ */ o(((e) => {
708
+ var t = T();
709
+ e.mul = function(e, n) {
710
+ let r = new Uint8Array(e.length + n.length - 1);
711
+ for (let i = 0; i < e.length; i++) for (let a = 0; a < n.length; a++) r[i + a] ^= t.mul(e[i], n[a]);
712
+ return r;
713
+ }, e.mod = function(e, n) {
714
+ let r = new Uint8Array(e);
715
+ for (; r.length - n.length >= 0;) {
716
+ let e = r[0];
717
+ for (let i = 0; i < n.length; i++) r[i] ^= t.mul(n[i], e);
718
+ let i = 0;
719
+ for (; i < r.length && r[i] === 0;) i++;
720
+ r = r.slice(i);
721
+ }
722
+ return r;
723
+ }, e.generateECPolynomial = function(n) {
724
+ let r = new Uint8Array([1]);
725
+ for (let i = 0; i < n; i++) r = e.mul(r, new Uint8Array([1, t.exp(i)]));
726
+ return r;
727
+ };
728
+ })), ne = /* @__PURE__ */ o(((e, t) => {
729
+ var n = te();
730
+ function r(e) {
731
+ this.genPoly = void 0, this.degree = e, this.degree && this.initialize(this.degree);
732
+ }
733
+ r.prototype.initialize = function(e) {
734
+ this.degree = e, this.genPoly = n.generateECPolynomial(this.degree);
735
+ }, r.prototype.encode = function(e) {
736
+ if (!this.genPoly) throw Error("Encoder not initialized");
737
+ let t = new Uint8Array(e.length + this.degree);
738
+ t.set(e);
739
+ let r = n.mod(t, this.genPoly), i = this.degree - r.length;
740
+ if (i > 0) {
741
+ let e = new Uint8Array(this.degree);
742
+ return e.set(r, i), e;
743
+ }
744
+ return r;
745
+ }, t.exports = r;
746
+ })), E = /* @__PURE__ */ o(((e) => {
747
+ e.isValid = function(e) {
748
+ return !isNaN(e) && e >= 1 && e <= 40;
749
+ };
750
+ })), D = /* @__PURE__ */ o(((e) => {
751
+ var t = "[0-9]+", n = "[A-Z $%*+\\-./:]+", r = "(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+";
752
+ r = r.replace(/u/g, "\\u");
753
+ var i = "(?:(?![A-Z0-9 $%*+\\-./:]|" + r + ")(?:.|[\r\n]))+";
754
+ e.KANJI = new RegExp(r, "g"), e.BYTE_KANJI = /* @__PURE__ */ RegExp("[^A-Z0-9 $%*+\\-./:]+", "g"), e.BYTE = new RegExp(i, "g"), e.NUMERIC = new RegExp(t, "g"), e.ALPHANUMERIC = new RegExp(n, "g");
755
+ var a = RegExp("^" + r + "$"), o = RegExp("^" + t + "$"), s = /* @__PURE__ */ RegExp("^[A-Z0-9 $%*+\\-./:]+$");
756
+ e.testKanji = function(e) {
757
+ return a.test(e);
758
+ }, e.testNumeric = function(e) {
759
+ return o.test(e);
760
+ }, e.testAlphanumeric = function(e) {
761
+ return s.test(e);
762
+ };
763
+ })), O = /* @__PURE__ */ o(((e) => {
764
+ var t = E(), n = D();
765
+ e.NUMERIC = {
766
+ id: "Numeric",
767
+ bit: 1,
768
+ ccBits: [
769
+ 10,
770
+ 12,
771
+ 14
772
+ ]
773
+ }, e.ALPHANUMERIC = {
774
+ id: "Alphanumeric",
775
+ bit: 2,
776
+ ccBits: [
777
+ 9,
778
+ 11,
779
+ 13
780
+ ]
781
+ }, e.BYTE = {
782
+ id: "Byte",
783
+ bit: 4,
784
+ ccBits: [
785
+ 8,
786
+ 16,
787
+ 16
788
+ ]
789
+ }, e.KANJI = {
790
+ id: "Kanji",
791
+ bit: 8,
792
+ ccBits: [
793
+ 8,
794
+ 10,
795
+ 12
796
+ ]
797
+ }, e.MIXED = { bit: -1 }, e.getCharCountIndicator = function(e, n) {
798
+ if (!e.ccBits) throw Error("Invalid mode: " + e);
799
+ if (!t.isValid(n)) throw Error("Invalid version: " + n);
800
+ return n >= 1 && n < 10 ? e.ccBits[0] : n < 27 ? e.ccBits[1] : e.ccBits[2];
801
+ }, e.getBestModeForData = function(t) {
802
+ return n.testNumeric(t) ? e.NUMERIC : n.testAlphanumeric(t) ? e.ALPHANUMERIC : n.testKanji(t) ? e.KANJI : e.BYTE;
803
+ }, e.toString = function(e) {
804
+ if (e && e.id) return e.id;
805
+ throw Error("Invalid mode");
806
+ }, e.isValid = function(e) {
807
+ return e && e.bit && e.ccBits;
808
+ };
809
+ function r(t) {
810
+ if (typeof t != "string") throw Error("Param is not a string");
811
+ switch (t.toLowerCase()) {
812
+ case "numeric": return e.NUMERIC;
813
+ case "alphanumeric": return e.ALPHANUMERIC;
814
+ case "kanji": return e.KANJI;
815
+ case "byte": return e.BYTE;
816
+ default: throw Error("Unknown mode: " + t);
817
+ }
818
+ }
819
+ e.from = function(t, n) {
820
+ if (e.isValid(t)) return t;
821
+ try {
822
+ return r(t);
823
+ } catch {
824
+ return n;
825
+ }
826
+ };
827
+ })), re = /* @__PURE__ */ o(((e) => {
828
+ var t = v(), n = w(), r = y(), i = O(), a = E(), o = 7973, s = t.getBCHDigit(o);
829
+ function c(t, n, r) {
830
+ for (let i = 1; i <= 40; i++) if (n <= e.getCapacity(i, r, t)) return i;
831
+ }
832
+ function l(e, t) {
833
+ return i.getCharCountIndicator(e, t) + 4;
834
+ }
835
+ function u(e, t) {
836
+ let n = 0;
837
+ return e.forEach(function(e) {
838
+ let r = l(e.mode, t);
839
+ n += r + e.getBitsLength();
840
+ }), n;
841
+ }
842
+ function d(t, n) {
843
+ for (let r = 1; r <= 40; r++) if (u(t, r) <= e.getCapacity(r, n, i.MIXED)) return r;
844
+ }
845
+ e.from = function(e, t) {
846
+ return a.isValid(e) ? parseInt(e, 10) : t;
847
+ }, e.getCapacity = function(e, r, o) {
848
+ if (!a.isValid(e)) throw Error("Invalid QR Code version");
849
+ o === void 0 && (o = i.BYTE);
850
+ let s = (t.getSymbolTotalCodewords(e) - n.getTotalCodewordsCount(e, r)) * 8;
851
+ if (o === i.MIXED) return s;
852
+ let c = s - l(o, e);
853
+ switch (o) {
854
+ case i.NUMERIC: return Math.floor(c / 10 * 3);
855
+ case i.ALPHANUMERIC: return Math.floor(c / 11 * 2);
856
+ case i.KANJI: return Math.floor(c / 13);
857
+ case i.BYTE:
858
+ default: return Math.floor(c / 8);
859
+ }
860
+ }, e.getBestVersionForData = function(e, t) {
861
+ let n, i = r.from(t, r.M);
862
+ if (Array.isArray(e)) {
863
+ if (e.length > 1) return d(e, i);
864
+ if (e.length === 0) return 1;
865
+ n = e[0];
866
+ } else n = e;
867
+ return c(n.mode, n.getLength(), i);
868
+ }, e.getEncodedBits = function(e) {
869
+ if (!a.isValid(e) || e < 7) throw Error("Invalid QR Code version");
870
+ let n = e << 12;
871
+ for (; t.getBCHDigit(n) - s >= 0;) n ^= o << t.getBCHDigit(n) - s;
872
+ return e << 12 | n;
873
+ };
874
+ })), ie = /* @__PURE__ */ o(((e) => {
875
+ var t = v(), n = 1335, r = 21522, i = t.getBCHDigit(n);
876
+ e.getEncodedBits = function(e, a) {
877
+ let o = e.bit << 3 | a, s = o << 10;
878
+ for (; t.getBCHDigit(s) - i >= 0;) s ^= n << t.getBCHDigit(s) - i;
879
+ return (o << 10 | s) ^ r;
880
+ };
881
+ })), ae = /* @__PURE__ */ o(((e, t) => {
882
+ var n = O();
883
+ function r(e) {
884
+ this.mode = n.NUMERIC, this.data = e.toString();
885
+ }
886
+ r.getBitsLength = function(e) {
887
+ return 10 * Math.floor(e / 3) + (e % 3 ? e % 3 * 3 + 1 : 0);
888
+ }, r.prototype.getLength = function() {
889
+ return this.data.length;
890
+ }, r.prototype.getBitsLength = function() {
891
+ return r.getBitsLength(this.data.length);
892
+ }, r.prototype.write = function(e) {
893
+ let t, n, r;
894
+ for (t = 0; t + 3 <= this.data.length; t += 3) n = this.data.substr(t, 3), r = parseInt(n, 10), e.put(r, 10);
895
+ let i = this.data.length - t;
896
+ i > 0 && (n = this.data.substr(t), r = parseInt(n, 10), e.put(r, i * 3 + 1));
897
+ }, t.exports = r;
898
+ })), oe = /* @__PURE__ */ o(((e, t) => {
899
+ var n = O(), r = /* @__PURE__ */ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".split("");
900
+ function i(e) {
901
+ this.mode = n.ALPHANUMERIC, this.data = e;
902
+ }
903
+ i.getBitsLength = function(e) {
904
+ return 11 * Math.floor(e / 2) + e % 2 * 6;
905
+ }, i.prototype.getLength = function() {
906
+ return this.data.length;
907
+ }, i.prototype.getBitsLength = function() {
908
+ return i.getBitsLength(this.data.length);
909
+ }, i.prototype.write = function(e) {
910
+ let t;
911
+ for (t = 0; t + 2 <= this.data.length; t += 2) {
912
+ let n = r.indexOf(this.data[t]) * 45;
913
+ n += r.indexOf(this.data[t + 1]), e.put(n, 11);
914
+ }
915
+ this.data.length % 2 && e.put(r.indexOf(this.data[t]), 6);
916
+ }, t.exports = i;
917
+ })), se = /* @__PURE__ */ o(((e, t) => {
918
+ var n = O();
919
+ function r(e) {
920
+ this.mode = n.BYTE, typeof e == "string" ? this.data = new TextEncoder().encode(e) : this.data = new Uint8Array(e);
921
+ }
922
+ r.getBitsLength = function(e) {
923
+ return e * 8;
924
+ }, r.prototype.getLength = function() {
925
+ return this.data.length;
926
+ }, r.prototype.getBitsLength = function() {
927
+ return r.getBitsLength(this.data.length);
928
+ }, r.prototype.write = function(e) {
929
+ for (let t = 0, n = this.data.length; t < n; t++) e.put(this.data[t], 8);
930
+ }, t.exports = r;
931
+ })), ce = /* @__PURE__ */ o(((e, t) => {
932
+ var n = O(), r = v();
933
+ function i(e) {
934
+ this.mode = n.KANJI, this.data = e;
935
+ }
936
+ i.getBitsLength = function(e) {
937
+ return e * 13;
938
+ }, i.prototype.getLength = function() {
939
+ return this.data.length;
940
+ }, i.prototype.getBitsLength = function() {
941
+ return i.getBitsLength(this.data.length);
942
+ }, i.prototype.write = function(e) {
943
+ let t;
944
+ for (t = 0; t < this.data.length; t++) {
945
+ let n = r.toSJIS(this.data[t]);
946
+ if (n >= 33088 && n <= 40956) n -= 33088;
947
+ else if (n >= 57408 && n <= 60351) n -= 49472;
948
+ else throw Error("Invalid SJIS character: " + this.data[t] + "\nMake sure your charset is UTF-8");
949
+ n = (n >>> 8 & 255) * 192 + (n & 255), e.put(n, 13);
950
+ }
951
+ }, t.exports = i;
952
+ })), le = /* @__PURE__ */ o(((e, t) => {
953
+ var n = {
954
+ single_source_shortest_paths: function(e, t, r) {
955
+ var i = {}, a = {};
956
+ a[t] = 0;
957
+ var o = n.PriorityQueue.make();
958
+ o.push(t, 0);
959
+ for (var s, c, l, u, d, f, p, m, h; !o.empty();) for (l in s = o.pop(), c = s.value, u = s.cost, d = e[c] || {}, d) d.hasOwnProperty(l) && (f = d[l], p = u + f, m = a[l], h = a[l] === void 0, (h || m > p) && (a[l] = p, o.push(l, p), i[l] = c));
960
+ if (r !== void 0 && a[r] === void 0) {
961
+ var g = [
962
+ "Could not find a path from ",
963
+ t,
964
+ " to ",
965
+ r,
966
+ "."
967
+ ].join("");
968
+ throw Error(g);
969
+ }
970
+ return i;
971
+ },
972
+ extract_shortest_path_from_predecessor_list: function(e, t) {
973
+ for (var n = [], r = t; r;) n.push(r), e[r], r = e[r];
974
+ return n.reverse(), n;
975
+ },
976
+ find_path: function(e, t, r) {
977
+ var i = n.single_source_shortest_paths(e, t, r);
978
+ return n.extract_shortest_path_from_predecessor_list(i, r);
979
+ },
980
+ PriorityQueue: {
981
+ make: function(e) {
982
+ var t = n.PriorityQueue, r = {}, i;
983
+ for (i in e ||= {}, t) t.hasOwnProperty(i) && (r[i] = t[i]);
984
+ return r.queue = [], r.sorter = e.sorter || t.default_sorter, r;
985
+ },
986
+ default_sorter: function(e, t) {
987
+ return e.cost - t.cost;
988
+ },
989
+ push: function(e, t) {
990
+ var n = {
991
+ value: e,
992
+ cost: t
993
+ };
994
+ this.queue.push(n), this.queue.sort(this.sorter);
995
+ },
996
+ pop: function() {
997
+ return this.queue.shift();
998
+ },
999
+ empty: function() {
1000
+ return this.queue.length === 0;
1001
+ }
1002
+ }
1003
+ };
1004
+ t !== void 0 && (t.exports = n);
1005
+ })), ue = /* @__PURE__ */ o(((e) => {
1006
+ var t = O(), n = ae(), r = oe(), i = se(), a = ce(), o = D(), s = v(), c = le();
1007
+ function l(e) {
1008
+ return unescape(encodeURIComponent(e)).length;
1009
+ }
1010
+ function u(e, t, n) {
1011
+ let r = [], i;
1012
+ for (; (i = e.exec(n)) !== null;) r.push({
1013
+ data: i[0],
1014
+ index: i.index,
1015
+ mode: t,
1016
+ length: i[0].length
1017
+ });
1018
+ return r;
1019
+ }
1020
+ function d(e) {
1021
+ let n = u(o.NUMERIC, t.NUMERIC, e), r = u(o.ALPHANUMERIC, t.ALPHANUMERIC, e), i, a;
1022
+ return s.isKanjiModeEnabled() ? (i = u(o.BYTE, t.BYTE, e), a = u(o.KANJI, t.KANJI, e)) : (i = u(o.BYTE_KANJI, t.BYTE, e), a = []), n.concat(r, i, a).sort(function(e, t) {
1023
+ return e.index - t.index;
1024
+ }).map(function(e) {
1025
+ return {
1026
+ data: e.data,
1027
+ mode: e.mode,
1028
+ length: e.length
1029
+ };
1030
+ });
1031
+ }
1032
+ function f(e, o) {
1033
+ switch (o) {
1034
+ case t.NUMERIC: return n.getBitsLength(e);
1035
+ case t.ALPHANUMERIC: return r.getBitsLength(e);
1036
+ case t.KANJI: return a.getBitsLength(e);
1037
+ case t.BYTE: return i.getBitsLength(e);
1038
+ }
1039
+ }
1040
+ function p(e) {
1041
+ return e.reduce(function(e, t) {
1042
+ let n = e.length - 1 >= 0 ? e[e.length - 1] : null;
1043
+ return n && n.mode === t.mode ? (e[e.length - 1].data += t.data, e) : (e.push(t), e);
1044
+ }, []);
1045
+ }
1046
+ function m(e) {
1047
+ let n = [];
1048
+ for (let r = 0; r < e.length; r++) {
1049
+ let i = e[r];
1050
+ switch (i.mode) {
1051
+ case t.NUMERIC:
1052
+ n.push([
1053
+ i,
1054
+ {
1055
+ data: i.data,
1056
+ mode: t.ALPHANUMERIC,
1057
+ length: i.length
1058
+ },
1059
+ {
1060
+ data: i.data,
1061
+ mode: t.BYTE,
1062
+ length: i.length
1063
+ }
1064
+ ]);
1065
+ break;
1066
+ case t.ALPHANUMERIC:
1067
+ n.push([i, {
1068
+ data: i.data,
1069
+ mode: t.BYTE,
1070
+ length: i.length
1071
+ }]);
1072
+ break;
1073
+ case t.KANJI:
1074
+ n.push([i, {
1075
+ data: i.data,
1076
+ mode: t.BYTE,
1077
+ length: l(i.data)
1078
+ }]);
1079
+ break;
1080
+ case t.BYTE: n.push([{
1081
+ data: i.data,
1082
+ mode: t.BYTE,
1083
+ length: l(i.data)
1084
+ }]);
1085
+ }
1086
+ }
1087
+ return n;
1088
+ }
1089
+ function h(e, n) {
1090
+ let r = {}, i = { start: {} }, a = ["start"];
1091
+ for (let o = 0; o < e.length; o++) {
1092
+ let s = e[o], c = [];
1093
+ for (let e = 0; e < s.length; e++) {
1094
+ let l = s[e], u = "" + o + e;
1095
+ c.push(u), r[u] = {
1096
+ node: l,
1097
+ lastCount: 0
1098
+ }, i[u] = {};
1099
+ for (let e = 0; e < a.length; e++) {
1100
+ let o = a[e];
1101
+ r[o] && r[o].node.mode === l.mode ? (i[o][u] = f(r[o].lastCount + l.length, l.mode) - f(r[o].lastCount, l.mode), r[o].lastCount += l.length) : (r[o] && (r[o].lastCount = l.length), i[o][u] = f(l.length, l.mode) + 4 + t.getCharCountIndicator(l.mode, n));
1102
+ }
1103
+ }
1104
+ a = c;
1105
+ }
1106
+ for (let e = 0; e < a.length; e++) i[a[e]].end = 0;
1107
+ return {
1108
+ map: i,
1109
+ table: r
1110
+ };
1111
+ }
1112
+ function g(e, o) {
1113
+ let c, l = t.getBestModeForData(e);
1114
+ if (c = t.from(o, l), c !== t.BYTE && c.bit < l.bit) throw Error("\"" + e + "\" cannot be encoded with mode " + t.toString(c) + ".\n Suggested mode is: " + t.toString(l));
1115
+ switch (c === t.KANJI && !s.isKanjiModeEnabled() && (c = t.BYTE), c) {
1116
+ case t.NUMERIC: return new n(e);
1117
+ case t.ALPHANUMERIC: return new r(e);
1118
+ case t.KANJI: return new a(e);
1119
+ case t.BYTE: return new i(e);
1120
+ }
1121
+ }
1122
+ e.fromArray = function(e) {
1123
+ return e.reduce(function(e, t) {
1124
+ return typeof t == "string" ? e.push(g(t, null)) : t.data && e.push(g(t.data, t.mode)), e;
1125
+ }, []);
1126
+ }, e.fromString = function(t, n) {
1127
+ let r = h(m(d(t, s.isKanjiModeEnabled())), n), i = c.find_path(r.map, "start", "end"), a = [];
1128
+ for (let e = 1; e < i.length - 1; e++) a.push(r.table[i[e]].node);
1129
+ return e.fromArray(p(a));
1130
+ }, e.rawSplit = function(t) {
1131
+ return e.fromArray(d(t, s.isKanjiModeEnabled()));
1132
+ };
1133
+ })), de = /* @__PURE__ */ o(((e) => {
1134
+ var t = v(), n = y(), r = b(), i = x(), a = S(), o = C(), s = ee(), c = w(), l = ne(), u = re(), d = ie(), f = O(), p = ue();
1135
+ function m(e, t) {
1136
+ let n = e.size, r = o.getPositions(t);
1137
+ for (let t = 0; t < r.length; t++) {
1138
+ let i = r[t][0], a = r[t][1];
1139
+ for (let t = -1; t <= 7; t++) if (!(i + t <= -1 || n <= i + t)) for (let r = -1; r <= 7; r++) a + r <= -1 || n <= a + r || (t >= 0 && t <= 6 && (r === 0 || r === 6) || r >= 0 && r <= 6 && (t === 0 || t === 6) || t >= 2 && t <= 4 && r >= 2 && r <= 4 ? e.set(i + t, a + r, !0, !0) : e.set(i + t, a + r, !1, !0));
1140
+ }
1141
+ }
1142
+ function h(e) {
1143
+ let t = e.size;
1144
+ for (let n = 8; n < t - 8; n++) {
1145
+ let t = n % 2 == 0;
1146
+ e.set(n, 6, t, !0), e.set(6, n, t, !0);
1147
+ }
1148
+ }
1149
+ function g(e, t) {
1150
+ let n = a.getPositions(t);
1151
+ for (let t = 0; t < n.length; t++) {
1152
+ let r = n[t][0], i = n[t][1];
1153
+ for (let t = -2; t <= 2; t++) for (let n = -2; n <= 2; n++) t === -2 || t === 2 || n === -2 || n === 2 || t === 0 && n === 0 ? e.set(r + t, i + n, !0, !0) : e.set(r + t, i + n, !1, !0);
1154
+ }
1155
+ }
1156
+ function _(e, t) {
1157
+ let n = e.size, r = u.getEncodedBits(t), i, a, o;
1158
+ for (let t = 0; t < 18; t++) i = Math.floor(t / 3), a = t % 3 + n - 8 - 3, o = (r >> t & 1) == 1, e.set(i, a, o, !0), e.set(a, i, o, !0);
1159
+ }
1160
+ function T(e, t, n) {
1161
+ let r = e.size, i = d.getEncodedBits(t, n), a, o;
1162
+ for (a = 0; a < 15; a++) o = (i >> a & 1) == 1, a < 6 ? e.set(a, 8, o, !0) : a < 8 ? e.set(a + 1, 8, o, !0) : e.set(r - 15 + a, 8, o, !0), a < 8 ? e.set(8, r - a - 1, o, !0) : a < 9 ? e.set(8, 15 - a - 1 + 1, o, !0) : e.set(8, 15 - a - 1, o, !0);
1163
+ e.set(r - 8, 8, 1, !0);
1164
+ }
1165
+ function te(e, t) {
1166
+ let n = e.size, r = -1, i = n - 1, a = 7, o = 0;
1167
+ for (let s = n - 1; s > 0; s -= 2) for (s === 6 && s--;;) {
1168
+ for (let n = 0; n < 2; n++) if (!e.isReserved(i, s - n)) {
1169
+ let r = !1;
1170
+ o < t.length && (r = (t[o] >>> a & 1) == 1), e.set(i, s - n, r), a--, a === -1 && (o++, a = 7);
1171
+ }
1172
+ if (i += r, i < 0 || n <= i) {
1173
+ i -= r, r = -r;
1174
+ break;
1175
+ }
1176
+ }
1177
+ }
1178
+ function E(e, n, i) {
1179
+ let a = new r();
1180
+ i.forEach(function(t) {
1181
+ a.put(t.mode.bit, 4), a.put(t.getLength(), f.getCharCountIndicator(t.mode, e)), t.write(a);
1182
+ });
1183
+ let o = (t.getSymbolTotalCodewords(e) - c.getTotalCodewordsCount(e, n)) * 8;
1184
+ for (a.getLengthInBits() + 4 <= o && a.put(0, 4); a.getLengthInBits() % 8 != 0;) a.putBit(0);
1185
+ let s = (o - a.getLengthInBits()) / 8;
1186
+ for (let e = 0; e < s; e++) a.put(e % 2 ? 17 : 236, 8);
1187
+ return D(a, e, n);
1188
+ }
1189
+ function D(e, n, r) {
1190
+ let i = t.getSymbolTotalCodewords(n), a = i - c.getTotalCodewordsCount(n, r), o = c.getBlocksCount(n, r), s = o - i % o, u = Math.floor(i / o), d = Math.floor(a / o), f = d + 1, p = u - d, m = new l(p), h = 0, g = Array(o), _ = Array(o), v = 0, y = new Uint8Array(e.buffer);
1191
+ for (let e = 0; e < o; e++) {
1192
+ let t = e < s ? d : f;
1193
+ g[e] = y.slice(h, h + t), _[e] = m.encode(g[e]), h += t, v = Math.max(v, t);
1194
+ }
1195
+ let b = new Uint8Array(i), x = 0, S, C;
1196
+ for (S = 0; S < v; S++) for (C = 0; C < o; C++) S < g[C].length && (b[x++] = g[C][S]);
1197
+ for (S = 0; S < p; S++) for (C = 0; C < o; C++) b[x++] = _[C][S];
1198
+ return b;
1199
+ }
1200
+ function ae(e, n, r, a) {
1201
+ let o;
1202
+ if (Array.isArray(e)) o = p.fromArray(e);
1203
+ else if (typeof e == "string") {
1204
+ let t = n;
1205
+ if (!t) {
1206
+ let n = p.rawSplit(e);
1207
+ t = u.getBestVersionForData(n, r);
1208
+ }
1209
+ o = p.fromString(e, t || 40);
1210
+ } else throw Error("Invalid data");
1211
+ let c = u.getBestVersionForData(o, r);
1212
+ if (!c) throw Error("The amount of data is too big to be stored in a QR Code");
1213
+ if (!n) n = c;
1214
+ else if (n < c) throw Error("\nThe chosen QR Code version cannot contain this amount of data.\nMinimum version required to store current data is: " + c + ".\n");
1215
+ let l = E(n, r, o), d = new i(t.getSymbolSize(n));
1216
+ return m(d, n), h(d), g(d, n), T(d, r, 0), n >= 7 && _(d, n), te(d, l), isNaN(a) && (a = s.getBestMask(d, T.bind(null, d, r))), s.applyMask(a, d), T(d, r, a), {
1217
+ modules: d,
1218
+ version: n,
1219
+ errorCorrectionLevel: r,
1220
+ maskPattern: a,
1221
+ segments: o
1222
+ };
1223
+ }
1224
+ e.create = function(e, r) {
1225
+ if (e === void 0 || e === "") throw Error("No input text");
1226
+ let i = n.M, a, o;
1227
+ return r !== void 0 && (i = n.from(r.errorCorrectionLevel, n.M), a = u.from(r.version), o = s.from(r.maskPattern), r.toSJISFunc && t.setToSJISFunction(r.toSJISFunc)), ae(e, a, i, o);
1228
+ };
1229
+ })), fe = /* @__PURE__ */ o(((e) => {
1230
+ function t(e) {
1231
+ if (typeof e == "number" && (e = e.toString()), typeof e != "string") throw Error("Color should be defined as hex string");
1232
+ let t = e.slice().replace("#", "").split("");
1233
+ if (t.length < 3 || t.length === 5 || t.length > 8) throw Error("Invalid hex color: " + e);
1234
+ (t.length === 3 || t.length === 4) && (t = Array.prototype.concat.apply([], t.map(function(e) {
1235
+ return [e, e];
1236
+ }))), t.length === 6 && t.push("F", "F");
1237
+ let n = parseInt(t.join(""), 16);
1238
+ return {
1239
+ r: n >> 24 & 255,
1240
+ g: n >> 16 & 255,
1241
+ b: n >> 8 & 255,
1242
+ a: n & 255,
1243
+ hex: "#" + t.slice(0, 6).join("")
1244
+ };
1245
+ }
1246
+ e.getOptions = function(e) {
1247
+ e ||= {}, e.color ||= {};
1248
+ let n = e.margin === void 0 || e.margin === null || e.margin < 0 ? 4 : e.margin, r = e.width && e.width >= 21 ? e.width : void 0, i = e.scale || 4;
1249
+ return {
1250
+ width: r,
1251
+ scale: r ? 4 : i,
1252
+ margin: n,
1253
+ color: {
1254
+ dark: t(e.color.dark || "#000000ff"),
1255
+ light: t(e.color.light || "#ffffffff")
1256
+ },
1257
+ type: e.type,
1258
+ rendererOpts: e.rendererOpts || {}
1259
+ };
1260
+ }, e.getScale = function(e, t) {
1261
+ return t.width && t.width >= e + t.margin * 2 ? t.width / (e + t.margin * 2) : t.scale;
1262
+ }, e.getImageWidth = function(t, n) {
1263
+ let r = e.getScale(t, n);
1264
+ return Math.floor((t + n.margin * 2) * r);
1265
+ }, e.qrToImageData = function(t, n, r) {
1266
+ let i = n.modules.size, a = n.modules.data, o = e.getScale(i, r), s = Math.floor((i + r.margin * 2) * o), c = r.margin * o, l = [r.color.light, r.color.dark];
1267
+ for (let e = 0; e < s; e++) for (let n = 0; n < s; n++) {
1268
+ let u = (e * s + n) * 4, d = r.color.light;
1269
+ if (e >= c && n >= c && e < s - c && n < s - c) {
1270
+ let t = Math.floor((e - c) / o), r = Math.floor((n - c) / o);
1271
+ d = l[+!!a[t * i + r]];
1272
+ }
1273
+ t[u++] = d.r, t[u++] = d.g, t[u++] = d.b, t[u] = d.a;
1274
+ }
1275
+ };
1276
+ })), pe = /* @__PURE__ */ o(((e) => {
1277
+ var t = fe();
1278
+ function n(e, t, n) {
1279
+ e.clearRect(0, 0, t.width, t.height), t.style ||= {}, t.height = n, t.width = n, t.style.height = n + "px", t.style.width = n + "px";
1280
+ }
1281
+ function r() {
1282
+ try {
1283
+ return document.createElement("canvas");
1284
+ } catch {
1285
+ throw Error("You need to specify a canvas element");
1286
+ }
1287
+ }
1288
+ e.render = function(e, i, a) {
1289
+ let o = a, s = i;
1290
+ o === void 0 && (!i || !i.getContext) && (o = i, i = void 0), i || (s = r()), o = t.getOptions(o);
1291
+ let c = t.getImageWidth(e.modules.size, o), l = s.getContext("2d"), u = l.createImageData(c, c);
1292
+ return t.qrToImageData(u.data, e, o), n(l, s, c), l.putImageData(u, 0, 0), s;
1293
+ }, e.renderToDataURL = function(t, n, r) {
1294
+ let i = r;
1295
+ i === void 0 && (!n || !n.getContext) && (i = n, n = void 0), i ||= {};
1296
+ let a = e.render(t, n, i), o = i.type || "image/png", s = i.rendererOpts || {};
1297
+ return a.toDataURL(o, s.quality);
1298
+ };
1299
+ })), me = /* @__PURE__ */ o(((e) => {
1300
+ var t = fe();
1301
+ function n(e, t) {
1302
+ let n = e.a / 255, r = t + "=\"" + e.hex + "\"";
1303
+ return n < 1 ? r + " " + t + "-opacity=\"" + n.toFixed(2).slice(1) + "\"" : r;
1304
+ }
1305
+ function r(e, t, n) {
1306
+ let r = e + t;
1307
+ return n !== void 0 && (r += " " + n), r;
1308
+ }
1309
+ function i(e, t, n) {
1310
+ let i = "", a = 0, o = !1, s = 0;
1311
+ for (let c = 0; c < e.length; c++) {
1312
+ let l = Math.floor(c % t), u = Math.floor(c / t);
1313
+ !l && !o && (o = !0), e[c] ? (s++, c > 0 && l > 0 && e[c - 1] || (i += o ? r("M", l + n, .5 + u + n) : r("m", a, 0), a = 0, o = !1), l + 1 < t && e[c + 1] || (i += r("h", s), s = 0)) : a++;
1314
+ }
1315
+ return i;
1316
+ }
1317
+ e.render = function(e, r, a) {
1318
+ let o = t.getOptions(r), s = e.modules.size, c = e.modules.data, l = s + o.margin * 2, u = o.color.light.a ? "<path " + n(o.color.light, "fill") + " d=\"M0 0h" + l + "v" + l + "H0z\"/>" : "", d = "<path " + n(o.color.dark, "stroke") + " d=\"" + i(c, s, o.margin) + "\"/>", f = "viewBox=\"0 0 " + l + " " + l + "\"", p = "<svg xmlns=\"http://www.w3.org/2000/svg\" " + (o.width ? "width=\"" + o.width + "\" height=\"" + o.width + "\" " : "") + f + " shape-rendering=\"crispEdges\">" + u + d + "</svg>\n";
1319
+ return typeof a == "function" && a(null, p), p;
1320
+ };
1321
+ })), he = /* @__PURE__ */ c((/* @__PURE__ */ o(((e) => {
1322
+ var t = _(), n = de(), r = pe(), i = me();
1323
+ function a(e, r, i, a, o) {
1324
+ let s = [].slice.call(arguments, 1), c = s.length, l = typeof s[c - 1] == "function";
1325
+ if (!l && !t()) throw Error("Callback required as last argument");
1326
+ if (l) {
1327
+ if (c < 2) throw Error("Too few arguments provided");
1328
+ c === 2 ? (o = i, i = r, r = a = void 0) : c === 3 && (r.getContext && o === void 0 ? (o = a, a = void 0) : (o = a, a = i, i = r, r = void 0));
1329
+ } else {
1330
+ if (c < 1) throw Error("Too few arguments provided");
1331
+ return c === 1 ? (i = r, r = a = void 0) : c === 2 && !r.getContext && (a = i, i = r, r = void 0), new Promise(function(t, o) {
1332
+ try {
1333
+ t(e(n.create(i, a), r, a));
1334
+ } catch (e) {
1335
+ o(e);
1336
+ }
1337
+ });
1338
+ }
1339
+ try {
1340
+ let t = n.create(i, a);
1341
+ o(null, e(t, r, a));
1342
+ } catch (e) {
1343
+ o(e);
1344
+ }
1345
+ }
1346
+ e.create = n.create, e.toCanvas = a.bind(null, r.render), e.toDataURL = a.bind(null, r.renderToDataURL), e.toString = a.bind(null, function(e, t, n) {
1347
+ return i.render(e, n);
1348
+ });
1349
+ })))(), 1), ge = {
1350
+ peerId: "",
1351
+ signalUrl: "",
1352
+ shareUrl: ""
1353
+ }, k = class extends HTMLElement {
1354
+ #e = ge;
1355
+ #t = !1;
1356
+ connectedCallback() {
1357
+ this.#t || (this.#t = !0, this.addEventListener("click", this.#n), this.render());
1358
+ }
1359
+ disconnectedCallback() {
1360
+ this.removeEventListener("click", this.#n);
1361
+ }
1362
+ set state(e) {
1363
+ this.#e = e, this.#t && this.render();
1364
+ }
1365
+ get state() {
1366
+ return this.#e;
1367
+ }
1368
+ async render() {
1369
+ let { shareUrl: e } = this.#e;
1370
+ this.className = "block", this.innerHTML = `
1371
+ <section class="lock-panel flex h-full flex-col justify-between gap-3 rounded-[1.4rem] p-3.5 sm:gap-4 sm:rounded-[2rem] sm:p-5">
1372
+ <div class="flex items-center justify-between gap-3">
1373
+ <p class="text-[0.62rem] font-semibold uppercase tracking-[0.18em] text-[var(--lock-dim)] sm:text-[0.7rem]">Share</p>
1374
+ <span data-share-state class="rounded-full border border-[var(--lock-border)] bg-[rgba(255,255,252,0.62)] px-2.5 py-0.5 text-[0.65rem] uppercase tracking-[0.12em] text-[var(--lock-muted)] sm:px-3 sm:py-1 sm:text-xs"></span>
1375
+ </div>
1376
+
1377
+ <div class="flex flex-1 items-center justify-center">
1378
+ <div class="rounded-[1.1rem] border border-[var(--lock-border)] bg-white p-2.5 shadow-sm sm:rounded-[1.7rem] sm:p-4">
1379
+ <canvas class="h-40 w-40 rounded-xl bg-white sm:h-52 sm:w-52 sm:rounded-2xl"></canvas>
1380
+ </div>
1381
+ </div>
1382
+
1383
+ <button
1384
+ type="button"
1385
+ data-action="copy-share"
1386
+ class="lock-primary lock-disabled inline-flex w-full items-center justify-center rounded-full px-4 py-3 text-sm font-semibold transition sm:py-4"
1387
+ ${e ? "" : "disabled"}
1388
+ >
1389
+ Share
1390
+ </button>
1391
+ </section>
1392
+ `, p(this, "[data-share-state]", e ? "ready" : "waiting");
1393
+ let t = this.querySelector("canvas");
1394
+ if (!t) return;
1395
+ let n = t.getContext("2d");
1396
+ if (!e) {
1397
+ n?.clearRect(0, 0, t.width, t.height);
1398
+ return;
1399
+ }
1400
+ try {
1401
+ await he.toCanvas(t, e, {
1402
+ width: 208,
1403
+ margin: 1,
1404
+ color: {
1405
+ dark: "#1f1f1d",
1406
+ light: "#ffffff"
1407
+ }
1408
+ });
1409
+ } catch {
1410
+ n?.clearRect(0, 0, t.width, t.height);
1411
+ }
1412
+ }
1413
+ #n = (e) => {
1414
+ e.target?.closest("[data-action='copy-share']") && l(this, "lockstep-copy-share", { value: this.#e.shareUrl });
1415
+ };
1416
+ }, _e = {
1417
+ gameTitle: "P2P Lockstep",
1418
+ peerId: "",
1419
+ remotePeerId: "",
1420
+ connected: !1,
1421
+ connectionState: "idle",
1422
+ currentTurn: 1,
1423
+ turnOwner: null,
1424
+ localState: "idle",
1425
+ remoteState: "idle",
1426
+ readySelf: !1,
1427
+ readyPeer: !1,
1428
+ pendingAction: null,
1429
+ sessionId: "default-session"
1430
+ }, A = (e) => e === "me" ? "Your turn" : e === "peer" ? "Peer turn" : "Waiting", ve = (e, t) => t === "ready" ? `${e} ready` : t === "could_start" ? e === "Me" ? "You can start" : "Peer can start" : `${e} idle`, j = (e, t) => {
1431
+ let n = e === "Local" ? "You" : "Peer";
1432
+ return t === "idle" ? `${n} idle` : t === "ready" ? `${n} ready` : t === "could_start" ? `${n} can start` : `${n} ${t.replaceAll("_", " ")}`;
1433
+ }, ye = (e, t) => e || t === "connected" ? {
1434
+ label: "Live",
1435
+ detail: "connected",
1436
+ tone: "bg-[var(--lock-teal)]"
1437
+ } : t === "registering" ? {
1438
+ label: "Registering",
1439
+ detail: "signal server",
1440
+ tone: "bg-[var(--lock-bronze)]"
1441
+ } : t === "registered" ? {
1442
+ label: "Registered",
1443
+ detail: "ready to share",
1444
+ tone: "bg-[var(--lock-bronze-bright)]"
1445
+ } : t === "connecting" ? {
1446
+ label: "Connecting",
1447
+ detail: "peer handshake",
1448
+ tone: "bg-[var(--lock-bronze-bright)]"
1449
+ } : t === "offline" ? {
1450
+ label: "Offline",
1451
+ detail: "waiting reconnect",
1452
+ tone: "bg-[var(--lock-dim)]"
1453
+ } : t === "error" ? {
1454
+ label: "Error",
1455
+ detail: "check signal",
1456
+ tone: "bg-[var(--lock-rose)]"
1457
+ } : {
1458
+ label: "Standby",
1459
+ detail: "not registered",
1460
+ tone: "bg-[var(--lock-dim)]"
1461
+ }, M = class extends HTMLElement {
1462
+ #e = _e;
1463
+ #t = !1;
1464
+ connectedCallback() {
1465
+ this.#t || (this.#t = !0, this.render());
1466
+ }
1467
+ set state(e) {
1468
+ this.#e = e, this.#t && this.render();
1469
+ }
1470
+ get state() {
1471
+ return this.#e;
1472
+ }
1473
+ render() {
1474
+ let { connected: e, pendingAction: t } = this.#e, n = ye(e, this.#e.connectionState), r = ve("Me", this.#e.localState), i = ve("Peer", this.#e.remoteState), a = j("Local", this.#e.localState), o = j("Remote", this.#e.remoteState), s = `${r} / ${i}`;
1475
+ this.className = "block", this.innerHTML = `
1476
+ <section class="lock-panel relative rounded-[1.25rem] p-2.5 text-sm text-[var(--lock-muted)] sm:rounded-[1.5rem] sm:p-3 lg:rounded-[1.75rem] lg:p-2.5">
1477
+ <div class="flex items-center gap-2 lg:hidden">
1478
+ <div class="min-w-0 flex-1">
1479
+ <p data-mobile-title class="truncate text-sm font-semibold leading-tight text-[var(--lock-paper)]"></p>
1480
+ <div class="mt-1 flex min-w-0 items-center gap-1.5 text-[0.68rem] leading-none text-[var(--lock-muted)]">
1481
+ <span class="h-2 w-2 shrink-0 rounded-full ${n.tone}"></span>
1482
+ <span data-mobile-connection class="shrink-0 font-medium"></span>
1483
+ <span class="text-[var(--lock-dim)]">/</span>
1484
+ <span data-mobile-turn class="min-w-0 truncate"></span>
1485
+ </div>
1486
+ </div>
1487
+
1488
+ <div class="hidden shrink-0 rounded-full border border-[var(--lock-border)] px-2.5 py-1 text-[0.65rem] text-[var(--lock-muted)] min-[390px]:block">
1489
+ <span data-mobile-ready></span>
1490
+ </div>
1491
+
1492
+ <details class="group shrink-0">
1493
+ <summary
1494
+ aria-label="Match details"
1495
+ class="flex h-9 w-9 cursor-pointer list-none items-center justify-center rounded-full border border-[var(--lock-border)] bg-[rgba(255,255,252,0.7)] text-base font-semibold leading-none text-[var(--lock-muted)] transition hover:border-[var(--lock-border-strong)] hover:bg-white [&::-webkit-details-marker]:hidden"
1496
+ >
1497
+ ...
1498
+ </summary>
1499
+ <div class="absolute inset-x-0 top-full z-50 mt-2 max-h-[calc(100svh-6rem)] overflow-auto rounded-[1.35rem] border border-[var(--lock-border-strong)] bg-[rgba(255,255,252,0.96)] p-3.5 shadow-2xl shadow-black/15 backdrop-blur-xl lg:inset-auto lg:right-0 lg:w-[min(22rem,calc(100vw-1.5rem))]">
1500
+ <div class="grid grid-cols-2 gap-2">
1501
+ <article class="rounded-[1rem] border border-[var(--lock-border)] bg-[rgba(255,255,252,0.54)] p-3">
1502
+ <p class="text-[0.6rem] uppercase tracking-[0.18em] text-[var(--lock-dim)]">Connection</p>
1503
+ <p data-detail-connection class="mt-1.5 text-sm font-semibold text-[var(--lock-paper)]"></p>
1504
+ </article>
1505
+ <article class="rounded-[1rem] border border-[var(--lock-border)] bg-[rgba(255,255,252,0.54)] p-3">
1506
+ <p class="text-[0.6rem] uppercase tracking-[0.18em] text-[var(--lock-dim)]">Turn</p>
1507
+ <p data-detail-turn class="mt-1.5 text-sm font-semibold text-[var(--lock-paper)]"></p>
1508
+ </article>
1509
+ </div>
1510
+
1511
+ <div class="mt-2 rounded-[1rem] border border-[var(--lock-border)] bg-[rgba(255,255,252,0.54)] p-3">
1512
+ <p class="text-[0.6rem] uppercase tracking-[0.18em] text-[var(--lock-dim)]">Identity</p>
1513
+ <p class="lock-mono mt-1.5 break-all text-xs text-[var(--lock-muted)]">Session: <span data-detail-session class="text-[var(--lock-paper)]"></span></p>
1514
+ <p class="lock-mono mt-1.5 break-all text-xs text-[var(--lock-muted)]">Me: <span data-detail-peer class="text-[var(--lock-paper)]"></span></p>
1515
+ <p class="lock-mono mt-1.5 break-all text-xs text-[var(--lock-muted)]">Peer: <span data-detail-remote class="text-[var(--lock-paper)]"></span></p>
1516
+ </div>
1517
+
1518
+ <div class="mt-2 flex flex-wrap gap-1.5">
1519
+ <span data-detail-ready-self class="rounded-full border border-[var(--lock-border)] px-2.5 py-1 text-[0.68rem] text-[var(--lock-muted)]"></span>
1520
+ <span data-detail-ready-peer class="rounded-full border border-[var(--lock-border)] px-2.5 py-1 text-[0.68rem] text-[var(--lock-muted)]"></span>
1521
+ <span data-detail-local-state class="rounded-full border border-[var(--lock-border)] px-2.5 py-1 text-[0.68rem] text-[var(--lock-muted)]"></span>
1522
+ <span data-detail-remote-state class="rounded-full border border-[var(--lock-border)] px-2.5 py-1 text-[0.68rem] text-[var(--lock-muted)]"></span>
1523
+ ${t ? `<span class="rounded-full border border-[var(--lock-border-strong)] bg-[rgba(201,149,67,0.14)] px-2.5 py-1 text-[0.68rem] text-[var(--lock-bronze-bright)]">Pending ${t}</span>` : ""}
1524
+ </div>
1525
+ </div>
1526
+ </details>
1527
+ </div>
1528
+
1529
+ <div class="hidden gap-2 lg:grid">
1530
+ <article class="rounded-[1.15rem] border border-[var(--lock-border)] bg-[rgba(255,255,252,0.52)] p-2.5">
1531
+ <div class="flex items-start justify-between gap-3">
1532
+ <div class="min-w-0">
1533
+ <p class="text-[0.62rem] uppercase tracking-[0.2em] text-[var(--lock-dim)]">Match</p>
1534
+ <p data-title class="mt-1.5 truncate text-xl font-semibold leading-none tracking-[-0.035em] text-[var(--lock-paper)]"></p>
1535
+ </div>
1536
+ <span class="mt-0.5 h-2.5 w-2.5 shrink-0 rounded-full ${n.tone}"></span>
1537
+ </div>
1538
+ </article>
1539
+
1540
+ <div class="grid grid-cols-2 gap-2">
1541
+ <article class="rounded-[1rem] border border-[var(--lock-border)] bg-[rgba(255,255,252,0.52)] p-2.5">
1542
+ <p class="text-[0.58rem] uppercase tracking-[0.2em] text-[var(--lock-dim)]">Connection</p>
1543
+ <p class="mt-1.5 text-sm font-semibold text-[var(--lock-paper)]">${n.label}</p>
1544
+ <p data-connection-state class="mt-0.5 truncate text-xs text-[var(--lock-muted)]"></p>
1545
+ </article>
1546
+
1547
+ <article class="rounded-[1rem] border border-[var(--lock-border)] bg-[rgba(255,255,252,0.52)] p-2.5">
1548
+ <p class="text-[0.58rem] uppercase tracking-[0.2em] text-[var(--lock-dim)]">Turn</p>
1549
+ <p data-current-turn class="mt-1.5 text-sm font-semibold text-[var(--lock-paper)]"></p>
1550
+ <p data-turn-owner class="mt-0.5 truncate text-xs text-[var(--lock-muted)]"></p>
1551
+ </article>
1552
+ </div>
1553
+
1554
+ <article class="min-w-0 overflow-hidden rounded-[1.15rem] border border-[var(--lock-border)] bg-[rgba(255,255,252,0.52)] p-2.5">
1555
+ <p class="text-[0.62rem] uppercase tracking-[0.2em] text-[var(--lock-dim)]">Identity</p>
1556
+ <div class="mt-2 grid gap-1.5 text-xs">
1557
+ <p class="grid min-w-0 grid-cols-[3.25rem_minmax(0,1fr)] items-center gap-2 text-[var(--lock-muted)]">
1558
+ <span>Session</span>
1559
+ <span data-session-id class="lock-mono block min-w-0 truncate text-right text-[var(--lock-paper)]"></span>
1560
+ </p>
1561
+ <p class="grid min-w-0 grid-cols-[3.25rem_minmax(0,1fr)] items-start gap-2 text-[var(--lock-muted)]">
1562
+ <span>Me</span>
1563
+ <span data-peer-id class="lock-mono block min-w-0 break-all text-right text-[var(--lock-paper)]"></span>
1564
+ </p>
1565
+ <p class="grid min-w-0 grid-cols-[3.25rem_minmax(0,1fr)] items-start gap-2 text-[var(--lock-muted)]">
1566
+ <span>Peer</span>
1567
+ <span data-remote-peer-id class="lock-mono block min-w-0 break-all text-right text-[var(--lock-paper)]"></span>
1568
+ </p>
1569
+ </div>
1570
+ </article>
1571
+
1572
+ <article class="rounded-[1.15rem] border border-[var(--lock-border)] bg-[rgba(255,255,252,0.52)] p-2.5">
1573
+ <p class="text-[0.62rem] uppercase tracking-[0.2em] text-[var(--lock-dim)]">State</p>
1574
+ <div class="mt-2 flex flex-wrap gap-1.5">
1575
+ <span data-ready-self class="rounded-full border border-[var(--lock-border)] px-2 py-0.5 text-[0.64rem] text-[var(--lock-muted)]"></span>
1576
+ <span data-ready-peer class="rounded-full border border-[var(--lock-border)] px-2 py-0.5 text-[0.64rem] text-[var(--lock-muted)]"></span>
1577
+ <span data-local-state class="rounded-full border border-[var(--lock-border)] px-2 py-0.5 text-[0.64rem] text-[var(--lock-muted)]"></span>
1578
+ <span data-remote-state class="rounded-full border border-[var(--lock-border)] px-2 py-0.5 text-[0.64rem] text-[var(--lock-muted)]"></span>
1579
+ ${t ? `<span class="rounded-full border border-[var(--lock-border-strong)] bg-[rgba(201,149,67,0.14)] px-2 py-0.5 text-[0.64rem] text-[var(--lock-bronze-bright)]">Pending ${t}</span>` : ""}
1580
+ </div>
1581
+ </article>
1582
+ </div>
1583
+ </section>
1584
+ `, p(this, "[data-mobile-title]", this.#e.gameTitle), p(this, "[data-mobile-connection]", n.label), p(this, "[data-mobile-turn]", `#${this.#e.currentTurn} ${A(this.#e.turnOwner)}`), p(this, "[data-mobile-ready]", s), p(this, "[data-detail-connection]", n.label), p(this, "[data-detail-turn]", `#${this.#e.currentTurn} / ${A(this.#e.turnOwner)}`), p(this, "[data-detail-session]", this.#e.sessionId), p(this, "[data-detail-peer]", this.#e.peerId || "not set"), p(this, "[data-detail-remote]", this.#e.remotePeerId || "not set"), p(this, "[data-detail-ready-self]", r), p(this, "[data-detail-ready-peer]", i), p(this, "[data-detail-local-state]", a), p(this, "[data-detail-remote-state]", o), p(this, "[data-title]", this.#e.gameTitle), p(this, "[data-connection-state]", n.detail), p(this, "[data-current-turn]", `#${this.#e.currentTurn}`), p(this, "[data-turn-owner]", A(this.#e.turnOwner)), p(this, "[data-session-id]", this.#e.sessionId), p(this, "[data-peer-id]", this.#e.peerId || "Local peer ID will appear after register.")?.setAttribute("title", this.#e.peerId), p(this, "[data-remote-peer-id]", this.#e.remotePeerId || "Remote peer not connected yet.")?.setAttribute("title", this.#e.remotePeerId), p(this, "[data-ready-self]", r), p(this, "[data-ready-peer]", i), p(this, "[data-local-state]", a), p(this, "[data-remote-state]", o);
1585
+ }
1586
+ }, be = {
1587
+ open: !1,
1588
+ message: ""
1589
+ }, N = class extends HTMLElement {
1590
+ #e = be;
1591
+ #t = !1;
1592
+ connectedCallback() {
1593
+ this.#t || (this.#t = !0, this.render());
1594
+ }
1595
+ set state(e) {
1596
+ this.#e = e, this.#t && this.render();
1597
+ }
1598
+ get state() {
1599
+ return this.#e;
1600
+ }
1601
+ render() {
1602
+ let { open: e } = this.#e;
1603
+ this.className = "pointer-events-none fixed inset-x-4 bottom-4 z-50 flex justify-center sm:justify-end", this.innerHTML = `
1604
+ <div
1605
+ class="max-w-sm rounded-full border border-[var(--lock-border-strong)] bg-[rgba(255,255,252,0.96)] px-4 py-3 text-sm font-medium text-[var(--lock-paper)] shadow-lg shadow-black/15 backdrop-blur-xl transition duration-200 ${e ? "translate-y-0 opacity-100" : "translate-y-2 opacity-0"}"
1606
+ >
1607
+ <span data-message></span>
1608
+ </div>
1609
+ `, p(this, "[data-message]", this.#e.message);
1610
+ }
1611
+ }, P = class extends HTMLElement {
1612
+ #e = !1;
1613
+ #t = null;
1614
+ #n = null;
1615
+ connectedCallback() {
1616
+ if (this.#e) return;
1617
+ this.#e = !0, this.render();
1618
+ let e = this.getMount(), t = this.querySelector("[data-placeholder]");
1619
+ if (!e || !t) return;
1620
+ let n = () => {
1621
+ t.style.display = e.childElementCount > 0 ? "none" : "flex";
1622
+ };
1623
+ n(), this.#t = new MutationObserver(n), this.#t.observe(e, { childList: !0 });
1624
+ }
1625
+ disconnectedCallback() {
1626
+ this.#t?.disconnect(), this.#t = null;
1627
+ }
1628
+ getMount() {
1629
+ return this.#e || this.connectedCallback(), this.#n;
1630
+ }
1631
+ render() {
1632
+ this.className = "block h-full", this.innerHTML = "\n <section class=\"relative h-full min-h-[15rem] overflow-visible rounded-[1.4rem] bg-transparent sm:min-h-[22rem] sm:rounded-[2.2rem] lg:min-h-[32rem] lg:rounded-[2rem]\">\n <div data-board-mount class=\"relative z-10 h-full\"></div>\n <div\n data-placeholder\n class=\"pointer-events-none absolute inset-0 z-20 flex items-center justify-center px-6 text-center text-sm leading-6 text-[var(--lock-muted)]\"\n >\n Board host ready\n </div>\n </section>\n ", this.#n = this.querySelector("[data-board-mount]");
1633
+ }
1634
+ }, F = (e) => {
1635
+ let t = e.hash.replace(/^#/, "");
1636
+ return new URLSearchParams(t || e.search);
1637
+ }, xe = (e, t, n) => {
1638
+ if (!e) return "";
1639
+ let r = new URL(n ?? window.location.href), i = new URLSearchParams();
1640
+ return i.set("id", e), t && i.set("url", t), r.hash = i.toString(), r.toString();
1641
+ }, Se = (e) => {
1642
+ let t = e.trim();
1643
+ if (!t || !t.includes("://")) return null;
1644
+ try {
1645
+ let e = F(new URL(t)), n = e.get("id");
1646
+ return n ? {
1647
+ peerId: n,
1648
+ signalUrl: e.get("url") ?? ""
1649
+ } : null;
1650
+ } catch {
1651
+ return null;
1652
+ }
1653
+ }, Ce = () => {
1654
+ let e = F(new URL(window.location.href));
1655
+ return {
1656
+ peerId: e.get("id") ?? "",
1657
+ signalUrl: e.get("url") ?? ""
1658
+ };
1659
+ }, we = {
1660
+ gameTitle: "P2P Lockstep",
1661
+ signalUrl: "",
1662
+ targetId: "",
1663
+ peerId: "",
1664
+ remotePeerId: "",
1665
+ connectionState: "idle",
1666
+ registering: !1,
1667
+ connecting: !1
1668
+ }, I = class extends HTMLElement {
1669
+ #e = we;
1670
+ #t = !1;
1671
+ #n = !1;
1672
+ connectedCallback() {
1673
+ this.#t || (this.#t = !0, this.addEventListener("click", this.#i), this.addEventListener("input", this.#a), this.render());
1674
+ }
1675
+ disconnectedCallback() {
1676
+ this.removeEventListener("click", this.#i), this.removeEventListener("input", this.#a);
1677
+ }
1678
+ set state(e) {
1679
+ let t = this.#n;
1680
+ this.#e = e, this.#t && !t && this.render(), this.#t && t && this.#r();
1681
+ }
1682
+ get state() {
1683
+ return this.#e;
1684
+ }
1685
+ render() {
1686
+ this.className = "block", this.innerHTML = "\n <section class=\"mx-auto grid min-h-full max-w-5xl gap-3 sm:gap-5 lg:grid-cols-[minmax(0,1fr)_22rem]\">\n <div class=\"lock-panel rounded-[1.4rem] p-3.5 sm:rounded-[2rem] sm:p-6 lg:p-7\">\n <div class=\"flex items-start justify-between gap-4\">\n <div class=\"min-w-0\">\n <p class=\"text-[0.62rem] font-semibold uppercase tracking-[0.18em] text-[var(--lock-dim)] sm:text-[0.68rem]\">Lobby</p>\n <h1 data-game-title class=\"mt-1.5 break-words text-3xl font-semibold leading-none tracking-[-0.04em] text-[var(--lock-paper)] sm:mt-3 sm:text-5xl lg:text-6xl\"></h1>\n </div>\n\n <details class=\"group relative shrink-0\">\n <summary\n aria-label=\"Server settings\"\n class=\"flex h-9 w-9 cursor-pointer list-none items-center justify-center rounded-full border border-[var(--lock-border)] bg-[rgba(255,255,252,0.7)] text-base font-semibold leading-none text-[var(--lock-muted)] transition hover:border-[var(--lock-border-strong)] hover:bg-white sm:h-10 sm:w-10 sm:text-lg [&::-webkit-details-marker]:hidden\"\n >\n ...\n </summary>\n <div class=\"absolute right-0 z-20 mt-2 w-[min(21rem,calc(100vw-2rem))] rounded-[1.2rem] border border-[var(--lock-border-strong)] bg-[var(--lock-surface-strong)] p-3.5 shadow-xl shadow-black/10 backdrop-blur-xl sm:mt-3 sm:rounded-[1.6rem] sm:p-4\">\n <label class=\"block\">\n <span class=\"mb-2 block text-xs uppercase tracking-[0.22em] text-[var(--lock-dim)]\">Signaling server</span>\n <input\n data-field=\"signal-url\"\n placeholder=\"wss://host\"\n class=\"lock-input lock-mono w-full rounded-2xl px-4 py-3 text-sm transition\"\n />\n </label>\n\n <button\n type=\"button\"\n data-action=\"register\"\n class=\"lock-primary lock-disabled mt-3 inline-flex w-full items-center justify-center rounded-full px-4 py-3 text-sm font-semibold transition\"\n >\n <span data-register-label></span>\n </button>\n </div>\n </details>\n </div>\n\n <div class=\"mt-4 grid grid-cols-2 gap-2 sm:mt-7 sm:gap-4\">\n <section class=\"rounded-[1rem] border border-[var(--lock-border)] bg-[rgba(255,255,252,0.58)] p-3 sm:rounded-[1.4rem] sm:p-4\">\n <p class=\"text-[0.58rem] uppercase tracking-[0.2em] text-[var(--lock-dim)] sm:text-[0.68rem]\">Server</p>\n <div class=\"mt-2 flex items-center gap-2 sm:mt-3 sm:gap-3\">\n <span data-status-dot class=\"h-2.5 w-2.5 rounded-full bg-slate-600\"></span>\n <span data-connection-state class=\"text-xs font-semibold uppercase tracking-[0.14em] text-[var(--lock-paper)] sm:text-sm\"></span>\n </div>\n </section>\n\n <section class=\"rounded-[1rem] border border-[var(--lock-border)] bg-[rgba(255,255,252,0.58)] p-3 sm:rounded-[1.4rem] sm:p-4\">\n <p class=\"text-[0.58rem] uppercase tracking-[0.2em] text-[var(--lock-dim)] sm:text-[0.68rem]\">Your ID</p>\n <p data-peer-id class=\"lock-mono mt-2 max-h-9 min-h-4 overflow-hidden break-all text-[0.68rem] leading-[1.35] text-[var(--lock-paper)] sm:mt-3 sm:max-h-none sm:text-sm\"></p>\n </section>\n </div>\n\n <section class=\"mt-3 rounded-[1.1rem] border border-[var(--lock-border)] bg-[rgba(255,255,252,0.58)] p-3 sm:mt-5 sm:rounded-[1.8rem] sm:p-5\">\n <label class=\"block\">\n <span class=\"mb-1.5 block text-xs font-semibold text-[var(--lock-muted)] sm:mb-2 sm:text-sm\">Peer ID or share link</span>\n <input\n data-field=\"target-id\"\n placeholder=\"Paste peer id\"\n class=\"lock-input lock-mono w-full rounded-xl px-3 py-3 text-sm transition sm:rounded-2xl sm:px-4 sm:py-4 sm:text-base\"\n />\n </label>\n\n <button\n type=\"button\"\n data-action=\"connect\"\n class=\"lock-primary lock-disabled mt-3 inline-flex w-full items-center justify-center rounded-full px-4 py-3 text-sm font-semibold transition sm:mt-4 sm:py-4\"\n >\n <span data-connect-label></span>\n </button>\n </section>\n </div>\n\n <p2p-lockstep-share-panel></p2p-lockstep-share-panel>\n </section>\n ", this.#n = !0, this.#r();
1687
+ }
1688
+ #r() {
1689
+ p(this, "[data-game-title]", this.#e.gameTitle), p(this, "[data-connection-state]", this.#e.connectionState), p(this, "[data-register-label]", this.#e.registering ? "Registering..." : "Register peer"), p(this, "[data-connect-label]", this.#e.connecting ? "Connecting..." : "Connect"), p(this, "[data-peer-id]", this.#e.peerId || "Register first to get your peer ID."), m(this, "[data-field='signal-url']", this.#e.signalUrl), m(this, "[data-field='target-id']", this.#e.targetId);
1690
+ let e = this.querySelector("[data-action='register']");
1691
+ e && (e.disabled = this.#e.registering || !this.#e.signalUrl.trim());
1692
+ let t = this.querySelector("[data-status-dot]");
1693
+ t && (t.className = `h-3 w-3 rounded-full ${this.#e.connectionState === "registered" || this.#e.connectionState === "connected" ? "bg-[var(--lock-teal)]" : this.#e.connectionState === "registering" || this.#e.connectionState === "connecting" ? "bg-[#c08a25]" : this.#e.connectionState === "error" || this.#e.connectionState === "offline" ? "bg-[var(--lock-rose)]" : "bg-[var(--lock-dim)]"}`);
1694
+ let n = this.querySelector("[data-action='connect']");
1695
+ n && (n.disabled = this.#e.connecting || !this.#e.targetId.trim());
1696
+ let r = this.querySelector("p2p-lockstep-share-panel");
1697
+ r && (r.state = {
1698
+ peerId: this.#e.peerId,
1699
+ signalUrl: this.#e.signalUrl,
1700
+ shareUrl: xe(this.#e.peerId, this.#e.signalUrl)
1701
+ });
1702
+ }
1703
+ #i = (e) => {
1704
+ let t = e.target?.closest("button[data-action]");
1705
+ !t || t.disabled || (t.dataset.action === "register" && l(this, "lockstep-register", { signalUrl: this.#e.signalUrl.trim() }), t.dataset.action === "connect" && l(this, "lockstep-connect", { targetId: this.#e.targetId.trim() }));
1706
+ };
1707
+ #a = (e) => {
1708
+ let t = e.target;
1709
+ if (t?.dataset.field) {
1710
+ if (t.dataset.field === "signal-url") {
1711
+ l(this, "lockstep-signal-change", { signalUrl: t.value });
1712
+ return;
1713
+ }
1714
+ if (t.dataset.field === "target-id") {
1715
+ let e = Se(t.value);
1716
+ if (e) {
1717
+ l(this, "lockstep-share-detected", e);
1718
+ return;
1719
+ }
1720
+ l(this, "lockstep-target-change", { targetId: t.value });
1721
+ }
1722
+ }
1723
+ };
1724
+ }, Te = {
1725
+ gameTitle: "P2P Lockstep",
1726
+ peerId: "",
1727
+ remotePeerId: "",
1728
+ connected: !1,
1729
+ connectionState: "idle",
1730
+ readySelf: !1,
1731
+ readyPeer: !1,
1732
+ canReady: !1,
1733
+ canStart: !1,
1734
+ canUndo: !1,
1735
+ canRestart: !1,
1736
+ started: !1,
1737
+ currentTurn: 1,
1738
+ turnOwner: null,
1739
+ localState: "idle",
1740
+ remoteState: "idle",
1741
+ pendingAction: null,
1742
+ sessionId: "default-session"
1743
+ }, L = class extends HTMLElement {
1744
+ #e = Te;
1745
+ #t = !1;
1746
+ #n = null;
1747
+ #r = null;
1748
+ #i = null;
1749
+ connectedCallback() {
1750
+ this.#t || (this.#t = !0, this.render(), this.#a());
1751
+ }
1752
+ set state(e) {
1753
+ this.#e = e, this.#t && this.#a();
1754
+ }
1755
+ get state() {
1756
+ return this.#e;
1757
+ }
1758
+ render() {
1759
+ this.className = "block h-full", this.innerHTML = "\n <section class=\"flex h-[calc(100svh-1.5rem)] flex-col items-center gap-2.5 overflow-visible sm:h-auto sm:min-h-[calc(100svh-3rem)] sm:gap-4 lg:grid lg:h-full lg:min-h-[32rem] lg:grid-cols-[minmax(0,1fr)_20rem] lg:items-start lg:gap-5\">\n <aside class=\"contents lg:relative lg:z-40 lg:col-start-2 lg:row-start-1 lg:flex lg:w-full lg:flex-col lg:gap-3\">\n <div class=\"relative z-40 order-1 w-full max-w-[45rem] lg:order-none lg:max-w-none\">\n <p2p-lockstep-status-panel></p2p-lockstep-status-panel>\n </div>\n\n <div class=\"order-3 w-full max-w-[45rem] shrink-0 lg:order-none lg:max-w-none\">\n <p2p-lockstep-action-bar></p2p-lockstep-action-bar>\n </div>\n </aside>\n\n <div class=\"order-2 min-h-0 w-full max-w-[45rem] flex-1 lg:order-none lg:col-start-1 lg:row-start-1 lg:h-full lg:max-w-none\">\n <p2p-lockstep-board-host></p2p-lockstep-board-host>\n </div>\n </section>\n ", this.#n = this.querySelector("p2p-lockstep-status-panel"), this.#r = this.querySelector("p2p-lockstep-action-bar"), this.#i = this.querySelector("p2p-lockstep-board-host");
1760
+ }
1761
+ getBoardHost() {
1762
+ return this.#i?.getMount() ?? null;
1763
+ }
1764
+ #a() {
1765
+ !this.#n || !this.#r || (this.#n.state = {
1766
+ gameTitle: this.#e.gameTitle,
1767
+ peerId: this.#e.peerId,
1768
+ remotePeerId: this.#e.remotePeerId,
1769
+ connected: this.#e.connected,
1770
+ connectionState: this.#e.connectionState,
1771
+ currentTurn: this.#e.currentTurn,
1772
+ turnOwner: this.#e.turnOwner,
1773
+ localState: this.#e.localState,
1774
+ remoteState: this.#e.remoteState,
1775
+ readySelf: this.#e.readySelf,
1776
+ readyPeer: this.#e.readyPeer,
1777
+ pendingAction: this.#e.pendingAction,
1778
+ sessionId: this.#e.sessionId
1779
+ }, this.#r.state = {
1780
+ connected: this.#e.connected,
1781
+ readySelf: this.#e.readySelf,
1782
+ canReady: this.#e.canReady,
1783
+ canStart: this.#e.canStart,
1784
+ canUndo: this.#e.canUndo,
1785
+ canRestart: this.#e.canRestart,
1786
+ started: this.#e.started,
1787
+ connectionState: this.#e.connectionState
1788
+ });
1789
+ }
1790
+ }, R = (e) => JSON.stringify(e), Ee = (e) => {
1791
+ if (typeof e != "string") throw TypeError("decode expects a serialized string");
1792
+ return JSON.parse(e);
1793
+ }, De = (e) => {
1794
+ if (typeof e != "string") return {
1795
+ ok: !1,
1796
+ error: /* @__PURE__ */ TypeError("decodeSafe expects a serialized string")
1797
+ };
1798
+ try {
1799
+ return {
1800
+ ok: !0,
1801
+ value: JSON.parse(e)
1802
+ };
1803
+ } catch (e) {
1804
+ return {
1805
+ ok: !1,
1806
+ error: e
1807
+ };
1808
+ }
1809
+ }, z = (e, t) => {
1810
+ t === void 0 ? console.log(e) : console.log(e, t);
1811
+ let n = globalThis.__p2p_debug;
1812
+ if (typeof n == "function") try {
1813
+ n(t === void 0 ? e : `${e} ${JSON.stringify(t)}`);
1814
+ } catch {
1815
+ n(e);
1816
+ }
1817
+ }, Oe = class {
1818
+ constructor() {
1819
+ this.ws = null, this.peerId = null, this.ready = !1, this.signalHandlers = /* @__PURE__ */ new Set(), this.pendingRegistration = null, this.connect = (e) => new Promise((t, n) => {
1820
+ this.ws?.close(), z("[signaling] ws connect", e), this.ws = new WebSocket(e);
1821
+ let r = window.setTimeout(() => {
1822
+ try {
1823
+ this.ws?.close();
1824
+ } catch {}
1825
+ z("[signaling] ws open timeout"), n(/* @__PURE__ */ Error("ws open timeout"));
1826
+ }, 5e3);
1827
+ this.ws.addEventListener("open", () => {
1828
+ this.ready = !0, this.registeredPayload = void 0, window.clearTimeout(r), z("[signaling] ws open"), t();
1829
+ }), this.ws.addEventListener("error", (e) => {
1830
+ window.clearTimeout(r), z("[signaling] ws error", e), n(/* @__PURE__ */ Error("ws error"));
1831
+ }), this.ws.addEventListener("close", (e) => {
1832
+ this.ready = !1, this.peerId = null, this.registeredPayload = void 0, this.rejectPendingRegistration(/* @__PURE__ */ Error("ws closed")), window.clearTimeout(r), z("[signaling] ws close", {
1833
+ code: e.code,
1834
+ reason: e.reason
1835
+ });
1836
+ }), this.ws.addEventListener("message", (e) => {
1837
+ let t = String(e.data), n = De(t);
1838
+ if (!n.ok) {
1839
+ z("[signaling] ws message decode error", t), this.rejectPendingRegistration(/* @__PURE__ */ Error("signaling decode error"));
1840
+ return;
1841
+ }
1842
+ let r = n.value;
1843
+ if (z("[signaling] ws message", r), r.type === "ERROR") {
1844
+ z("[signaling] error", r), this.rejectPendingRegistration(/* @__PURE__ */ Error("signaling error"));
1845
+ return;
1846
+ }
1847
+ if ((r.type === "REGISTERED" || r.type === "RESUMED") && (this.peerId = r.to ?? null, this.registeredPayload = r.payload, this.peerId)) {
1848
+ let e = this.resolveRegisteredPayload();
1849
+ z("[signaling] registered", {
1850
+ peerId: this.peerId,
1851
+ resumeToken: e.resumeToken
1852
+ }), this.resolvePendingRegistration({
1853
+ peerId: this.peerId,
1854
+ iceServers: e.iceServers,
1855
+ resumeToken: e.resumeToken
1856
+ });
1857
+ }
1858
+ if (r.type === "RELAY" && r.payload?.id) {
1859
+ let e = r.payload;
1860
+ this.emitSignal({
1861
+ from: r.from ?? "",
1862
+ to: r.to ?? "",
1863
+ type: e.id,
1864
+ payload: e.data
1865
+ });
1866
+ }
1867
+ });
1868
+ }), this.register = async () => {
1869
+ this.assertConnected();
1870
+ let e = { type: "REGISTER" };
1871
+ z("[signaling] send REGISTER");
1872
+ let t = this.awaitRegistration("register");
1873
+ this.ws?.send(R(e));
1874
+ try {
1875
+ let e = await t;
1876
+ return z("[signaling] register ok", e.peerId), e;
1877
+ } catch (e) {
1878
+ throw z("[signaling] register error", e), e;
1879
+ }
1880
+ }, this.resume = async (e) => {
1881
+ this.assertConnected();
1882
+ let t = {
1883
+ type: "RESUME",
1884
+ payload: {
1885
+ id: "resume",
1886
+ data: e
1887
+ }
1888
+ };
1889
+ z("[signaling] send RESUME", e.peerId);
1890
+ let n = this.awaitRegistration("resume");
1891
+ this.ws?.send(R(t));
1892
+ try {
1893
+ let e = await n;
1894
+ return z("[signaling] resume ok", e.peerId), e;
1895
+ } catch (e) {
1896
+ throw z("[signaling] resume error", e), e;
1897
+ }
1898
+ }, this.relay = (e) => {
1899
+ if (!this.ws || !this.ready) return;
1900
+ let t = {
1901
+ id: e.type,
1902
+ data: e.payload
1903
+ }, n = {
1904
+ type: "RELAY",
1905
+ from: this.peerId ?? e.from,
1906
+ to: e.to,
1907
+ payload: t
1908
+ };
1909
+ this.ws.send(R(n));
1910
+ };
1911
+ }
1912
+ onSignal(e) {
1913
+ this.signalHandlers.add(e);
1914
+ }
1915
+ offSignal(e) {
1916
+ this.signalHandlers.delete(e);
1917
+ }
1918
+ resolveRegisteredPayload() {
1919
+ let e = [], t = "";
1920
+ if (this.registeredPayload?.id === "iceServers" && (e = this.registeredPayload.data), this.registeredPayload?.id === "session") {
1921
+ let n = this.registeredPayload.data;
1922
+ e = n.iceServers ?? [], t = n.resumeToken ?? "";
1923
+ }
1924
+ return {
1925
+ iceServers: e,
1926
+ resumeToken: t
1927
+ };
1928
+ }
1929
+ assertConnected() {
1930
+ if (!this.ws || !this.ready) throw Error("not connected");
1931
+ }
1932
+ awaitRegistration(e) {
1933
+ return this.pendingRegistration ? Promise.reject(/* @__PURE__ */ Error("registration already pending")) : new Promise((t, n) => {
1934
+ this.pendingRegistration = {
1935
+ resolve: t,
1936
+ reject: n,
1937
+ timeoutId: window.setTimeout(() => {
1938
+ this.pendingRegistration = null, z(`[signaling] ${e} timeout`), n(/* @__PURE__ */ Error(`${e} timeout`));
1939
+ }, 5e3)
1940
+ };
1941
+ });
1942
+ }
1943
+ resolvePendingRegistration(e) {
1944
+ let t = this.pendingRegistration;
1945
+ t && (this.pendingRegistration = null, window.clearTimeout(t.timeoutId), t.resolve(e));
1946
+ }
1947
+ rejectPendingRegistration(e) {
1948
+ let t = this.pendingRegistration;
1949
+ t && (this.pendingRegistration = null, window.clearTimeout(t.timeoutId), t.reject(e));
1950
+ }
1951
+ emitSignal(e) {
1952
+ for (let t of [...this.signalHandlers]) t(e);
1953
+ }
1954
+ }, ke = [
1955
+ {
1956
+ from: "passive",
1957
+ event: "CONNECT",
1958
+ to: "requesting"
1959
+ },
1960
+ {
1961
+ from: "passive",
1962
+ event: "REMOTE_CONNECT",
1963
+ to: "requesting"
1964
+ },
1965
+ {
1966
+ from: "requesting",
1967
+ event: "CONNECTED",
1968
+ to: "connected"
1969
+ },
1970
+ {
1971
+ from: "connected",
1972
+ event: "DISCONNECT",
1973
+ to: "passive"
1974
+ },
1975
+ {
1976
+ from: "requesting",
1977
+ event: "DISCONNECT",
1978
+ to: "passive"
1979
+ },
1980
+ {
1981
+ from: "connected",
1982
+ event: "CONNECT",
1983
+ to: "requesting"
1984
+ }
1985
+ ], Ae = (e, t) => {
1986
+ let n = ke.find((n) => n.from === e && n.event === t);
1987
+ return n ? n.to : e;
1988
+ }, je = [
1989
+ {
1990
+ from: "idle",
1991
+ event: "REQUEST",
1992
+ to: "starting"
1993
+ },
1994
+ {
1995
+ from: "starting",
1996
+ event: "READY",
1997
+ to: "active"
1998
+ },
1999
+ {
2000
+ from: "starting",
2001
+ event: "STOP",
2002
+ to: "idle"
2003
+ },
2004
+ {
2005
+ from: "starting",
2006
+ event: "DISCONNECT",
2007
+ to: "idle"
2008
+ },
2009
+ {
2010
+ from: "active",
2011
+ event: "STOP",
2012
+ to: "idle"
2013
+ },
2014
+ {
2015
+ from: "active",
2016
+ event: "DISCONNECT",
2017
+ to: "idle"
2018
+ },
2019
+ {
2020
+ from: "active",
2021
+ event: "REQUEST",
2022
+ to: "starting"
2023
+ },
2024
+ {
2025
+ from: "idle",
2026
+ event: "DISCONNECT",
2027
+ to: "idle"
2028
+ },
2029
+ {
2030
+ from: "idle",
2031
+ event: "STOP",
2032
+ to: "idle"
2033
+ }
2034
+ ], Me = (e, t) => {
2035
+ let n = je.find((n) => n.from === e && n.event === t);
2036
+ return n ? n.to : e;
2037
+ }, Ne = class {
2038
+ constructor(e, t, n, r, i, a, o) {
2039
+ this.dc = null, this.pendingSends = [], this.remoteId = null, this.requestedId = null, this.state = "passive", this.localStream = null, this.remoteStream = null, this.onRemoteStreamHandler = null, this.senders = [], this.mediaState = "idle", this.negotiating = !1, this.renegotiateQueued = !1, this.onStateChangeHandler = null, this.onMediaChangeHandler = null, this.handleConnectionStateChange = () => {
2040
+ if (this.pc.connectionState === "connected") {
2041
+ this.markConnectedIfReady();
2042
+ return;
2043
+ }
2044
+ (this.pc.connectionState === "closed" || this.pc.connectionState === "disconnected" || this.pc.connectionState === "failed") && this.dispatch("DISCONNECT");
2045
+ }, this.handleIceCandidate = (e) => {
2046
+ if (!e.candidate || !this.remoteId) return;
2047
+ let t = {
2048
+ from: this.id,
2049
+ to: this.remoteId,
2050
+ type: "ice",
2051
+ payload: e.candidate.toJSON()
2052
+ };
2053
+ this.signaling.relay(t);
2054
+ }, this.handleDataChannel = (e) => {
2055
+ this.dc = e.channel, this.bindDataChannel();
2056
+ }, this.handleTrackEvent = (e) => {
2057
+ this.handleRemoteTrack(e);
2058
+ }, this.handleNegotiationNeeded = () => {
2059
+ this.canNegotiate() && this.runTask(this.negotiate(), "negotiate");
2060
+ }, this.connect = async (e) => {
2061
+ if (this.state !== "passive") {
2062
+ this.requestedId = e, this.disconnect();
2063
+ return;
2064
+ }
2065
+ this.remoteId = e, this.requestedId = null, this.dispatch("CONNECT");
2066
+ }, this.disconnect = () => {
2067
+ this.dispatch("DISCONNECT");
2068
+ }, this.dispose = () => {
2069
+ this.signaling.offSignal(this.onSignalHandler), this.pc.removeEventListener("connectionstatechange", this.handleConnectionStateChange), this.pc.removeEventListener("icecandidate", this.handleIceCandidate), this.pc.removeEventListener("track", this.handleTrackEvent), this.pc.removeEventListener("negotiationneeded", this.handleNegotiationNeeded), this.pc.ondatachannel = null, this.requestedId = null, this.closeConnection(), this.setPeerState("passive"), this.pc.signalingState !== "closed" && this.pc.close();
2070
+ }, this.send = (e) => {
2071
+ if (!this.dc || this.dc.readyState !== "open") {
2072
+ this.state === "requesting" && this.pendingSends.push(e);
2073
+ return;
2074
+ }
2075
+ this.dc.send(e);
2076
+ }, this.getPeerId = () => this.id, this.getRemoteId = () => this.remoteId, this.getPeerState = () => this.state, this.getMediaState = () => this.mediaState, this.startMedia = (e) => {
2077
+ this.localStream = e, this.dispatchMedia("REQUEST");
2078
+ }, this.stopMedia = () => {
2079
+ this.localStream = null, this.dispatchMedia("STOP");
2080
+ }, this.onRemoteStream = (e) => {
2081
+ this.onRemoteStreamHandler = e, e?.(this.remoteStream);
2082
+ }, this.bindDataChannel = () => {
2083
+ this.dc && (this.dc.onmessage = (e) => {
2084
+ this.onMessageHandler?.(String(e.data));
2085
+ }, this.dc.onopen = () => {
2086
+ this.flushPendingSends(), this.markConnectedIfReady(), this.attemptActivateMedia();
2087
+ }, this.dc.onclose = () => {
2088
+ this.dispatchMedia("DISCONNECT"), this.dispatch("DISCONNECT");
2089
+ }, this.dc.readyState === "open" && (this.flushPendingSends(), this.markConnectedIfReady(), this.attemptActivateMedia()));
2090
+ }, this.markConnectedIfReady = () => {
2091
+ !this.dc || this.dc.readyState !== "open" || this.dispatch("CONNECTED");
2092
+ }, this.flushPendingSends = () => {
2093
+ if (!(!this.dc || this.dc.readyState !== "open")) for (; this.pendingSends.length > 0;) {
2094
+ let e = this.pendingSends.shift();
2095
+ e !== void 0 && this.dc.send(e);
2096
+ }
2097
+ }, this.handleSignal = async (e) => {
2098
+ this.shouldHandleSignal(e) && await {
2099
+ offer: async () => {
2100
+ this.remoteId = e.from, this.state === "passive" && this.dispatch("REMOTE_CONNECT"), await this.pc.setRemoteDescription(e.payload);
2101
+ let t = await this.pc.createAnswer();
2102
+ await this.pc.setLocalDescription(t);
2103
+ let n = {
2104
+ from: this.id,
2105
+ to: e.from,
2106
+ type: "answer",
2107
+ payload: t
2108
+ };
2109
+ this.signaling.relay(n);
2110
+ },
2111
+ answer: async () => {
2112
+ await this.pc.setRemoteDescription(e.payload);
2113
+ },
2114
+ ice: async () => {
2115
+ await this.pc.addIceCandidate(e.payload);
2116
+ }
2117
+ }[e.type]();
2118
+ }, this.dispatch = (e) => {
2119
+ let t = Ae(this.state, e);
2120
+ if (this.setPeerState(t)) {
2121
+ if (t === "requesting" && e === "CONNECT") {
2122
+ this.requestedId &&= (this.remoteId = this.requestedId, null), this.runTask(this.startOffer(), "startOffer");
2123
+ return;
2124
+ }
2125
+ t === "passive" && (this.closeConnection(), this.requestedId && (this.remoteId = this.requestedId, this.requestedId = null, this.dispatch("CONNECT")));
2126
+ }
2127
+ }, this.startOffer = async () => {
2128
+ if (!this.remoteId) return;
2129
+ this.dc = this.pc.createDataChannel("game", { ordered: !0 }), this.bindDataChannel();
2130
+ let e = await this.pc.createOffer();
2131
+ await this.pc.setLocalDescription(e);
2132
+ let t = {
2133
+ from: this.id,
2134
+ to: this.remoteId,
2135
+ type: "offer",
2136
+ payload: e
2137
+ };
2138
+ this.signaling.relay(t);
2139
+ }, this.closeConnection = () => {
2140
+ let e = this.dc;
2141
+ this.dc = null, this.pendingSends.length = 0, this.negotiating = !1, this.renegotiateQueued = !1, e && (e.onmessage = null, e.onopen = null, e.onclose = null, e.readyState !== "closed" && e.close()), this.dispatchMedia("DISCONNECT"), this.remoteId = null;
2142
+ }, this.detachLocalMedia = () => {
2143
+ if (this.senders.length) {
2144
+ for (let e of this.senders) try {
2145
+ this.pc.removeTrack(e);
2146
+ } catch {}
2147
+ this.senders = [];
2148
+ }
2149
+ }, this.ensureRemoteStream = () => (this.remoteStream ||= new MediaStream(), this.remoteStream), this.handleRemoteTrack = (e) => {
2150
+ let [t] = e.streams;
2151
+ if (t) this.remoteStream = t;
2152
+ else {
2153
+ let t = this.ensureRemoteStream();
2154
+ t.addTrack(e.track), this.remoteStream = t;
2155
+ }
2156
+ e.track.addEventListener("ended", () => {
2157
+ this.handleRemoteTrackEnded();
2158
+ }), this.onRemoteStreamHandler && this.remoteStream && this.onRemoteStreamHandler(this.remoteStream);
2159
+ }, this.handleRemoteTrackEnded = () => {
2160
+ this.remoteStream && (this.remoteStream.getTracks().some((e) => e.readyState !== "ended") || this.clearRemoteStream());
2161
+ }, this.clearRemoteStream = () => {
2162
+ if (this.remoteStream) {
2163
+ for (let e of this.remoteStream.getTracks()) try {
2164
+ e.stop();
2165
+ } catch {}
2166
+ this.remoteStream = null, this.onRemoteStreamHandler?.(null);
2167
+ }
2168
+ }, this.isMediaReady = () => this.dc?.readyState === "open", this.dispatchMedia = (e) => {
2169
+ let t = Me(this.mediaState, e);
2170
+ if (!this.setMediaState(t)) {
2171
+ e === "REQUEST" && t === "starting" && this.attemptActivateMedia();
2172
+ return;
2173
+ }
2174
+ if (t === "starting") {
2175
+ this.detachLocalMedia(), this.attemptActivateMedia();
2176
+ return;
2177
+ }
2178
+ t === "idle" && (this.detachLocalMedia(), this.clearRemoteStream());
2179
+ }, this.attemptActivateMedia = () => {
2180
+ if (this.mediaState === "starting" && !(!this.localStream || !this.isMediaReady())) {
2181
+ for (let e of this.localStream.getTracks()) {
2182
+ let t = this.pc.addTrack(e, this.localStream);
2183
+ this.senders.push(t);
2184
+ }
2185
+ this.dispatchMedia("READY");
2186
+ }
2187
+ }, this.canNegotiate = () => !!(this.remoteId && this.isMediaReady()), this.shouldHandleSignal = (e) => e.type === "offer" && this.state === "passive" || this.remoteId === e.from, this.setPeerState = (e) => this.state === e ? !1 : (this.state = e, this.onStateChangeHandler?.(this.state), !0), this.setMediaState = (e) => this.mediaState === e ? !1 : (this.mediaState = e, this.onMediaChangeHandler?.(this.mediaState), !0), this.negotiate = async () => {
2188
+ if (this.remoteId) {
2189
+ if (this.negotiating) {
2190
+ this.renegotiateQueued = !0;
2191
+ return;
2192
+ }
2193
+ this.negotiating = !0;
2194
+ try {
2195
+ let e = await this.pc.createOffer();
2196
+ await this.pc.setLocalDescription(e);
2197
+ let t = {
2198
+ from: this.id,
2199
+ to: this.remoteId,
2200
+ type: "offer",
2201
+ payload: e
2202
+ };
2203
+ this.signaling.relay(t);
2204
+ } finally {
2205
+ this.negotiating = !1, this.renegotiateQueued && (this.renegotiateQueued = !1, this.runTask(this.negotiate(), "negotiate"));
2206
+ }
2207
+ }
2208
+ }, this.id = e, this.pc = t, this.signaling = n, r && (this.onMessageHandler = r), i && (this.onRemoteStreamHandler = i), a && (this.onStateChangeHandler = a), o && (this.onMediaChangeHandler = o), this.onSignalHandler = (e) => {
2209
+ this.runTask(this.handleSignal(e), `signal:${e.type}`);
2210
+ }, this.signaling.onSignal(this.onSignalHandler), this.pc.addEventListener("connectionstatechange", this.handleConnectionStateChange), this.pc.addEventListener("icecandidate", this.handleIceCandidate), this.pc.ondatachannel = this.handleDataChannel, this.pc.addEventListener("track", this.handleTrackEvent), this.pc.addEventListener("negotiationneeded", this.handleNegotiationNeeded);
2211
+ }
2212
+ runTask(e, t) {
2213
+ e.catch((e) => {
2214
+ console.error(`[rtc-peer] ${t} failed`, e), this.dispatchMedia("DISCONNECT"), this.dispatch("DISCONNECT");
2215
+ });
2216
+ }
2217
+ }, B = "p2p-lockstep-kit:signal-session", Pe = () => {
2218
+ if (typeof window > "u") return null;
2219
+ try {
2220
+ return window.localStorage;
2221
+ } catch {
2222
+ return null;
2223
+ }
2224
+ }, Fe = () => {
2225
+ let e = Pe();
2226
+ if (!e) return null;
2227
+ let t = e.getItem(B);
2228
+ if (!t) return null;
2229
+ try {
2230
+ let e = JSON.parse(t);
2231
+ return !e?.peerId || !e?.resumeToken ? null : e;
2232
+ } catch {
2233
+ return null;
2234
+ }
2235
+ }, Ie = (e) => {
2236
+ let t = Pe();
2237
+ if (t) {
2238
+ if (!e) {
2239
+ t.removeItem(B);
2240
+ return;
2241
+ }
2242
+ t.setItem(B, JSON.stringify(e));
2243
+ }
2244
+ }, Le = () => {
2245
+ Ie(null);
2246
+ }, Re = class {
2247
+ constructor(e = new Oe()) {
2248
+ this.peer = null, this.onMessageHandler = null, this.onRemoteStreamHandler = null, this.pendingMediaStream = null, this.onStateChangeHandler = null, this.onMediaChangeHandler = null, this.getLocalPeerId = () => this.peer?.getPeerId() ?? null, this.getRemotePeerId = () => this.peer?.getRemoteId() ?? null, this.peerState = () => this.peer?.getPeerState() ?? "passive", this.mediaState = () => this.peer?.getMediaState() ?? "idle", this.signaling = e;
2249
+ }
2250
+ async register(e) {
2251
+ this.peer?.dispose(), this.peer = null, await this.signaling.connect(e);
2252
+ let t = Fe(), n = null;
2253
+ if (t) try {
2254
+ n = await this.signaling.resume({
2255
+ peerId: t.peerId,
2256
+ resumeToken: t.resumeToken
2257
+ });
2258
+ } catch {
2259
+ Le();
2260
+ }
2261
+ n ||= await this.signaling.register(), n.resumeToken && Ie({
2262
+ peerId: n.peerId,
2263
+ resumeToken: n.resumeToken,
2264
+ updatedAt: Date.now()
2265
+ });
2266
+ let r = new RTCPeerConnection({ iceServers: n.iceServers });
2267
+ return this.peer = new Ne(n.peerId, r, this.signaling, (e) => {
2268
+ try {
2269
+ let t = Ee(String(e));
2270
+ this.onMessageHandler?.(t);
2271
+ } catch {
2272
+ this.onMessageHandler?.(e);
2273
+ }
2274
+ }, (e) => {
2275
+ this.onRemoteStreamHandler?.(e);
2276
+ }, (e) => {
2277
+ this.onStateChangeHandler?.(e);
2278
+ }, (e) => {
2279
+ this.onMediaChangeHandler?.(e);
2280
+ }), this.onRemoteStreamHandler && this.peer.onRemoteStream(this.onRemoteStreamHandler), this.onStateChangeHandler && this.onStateChangeHandler(this.peer.getPeerState()), this.onMediaChangeHandler && this.onMediaChangeHandler(this.peer.getMediaState()), this.pendingMediaStream && this.peer.startMedia(this.pendingMediaStream), { peerId: n.peerId };
2281
+ }
2282
+ async connect(e) {
2283
+ this.peer && await this.peer.connect(e);
2284
+ }
2285
+ send(e) {
2286
+ let t = R(e);
2287
+ this.peer?.send(t);
2288
+ }
2289
+ disconnect() {
2290
+ this.peer?.disconnect();
2291
+ }
2292
+ onMessage(e) {
2293
+ this.onMessageHandler = e;
2294
+ }
2295
+ startMedia(e) {
2296
+ this.pendingMediaStream = e, this.peer?.startMedia(e);
2297
+ }
2298
+ stopMedia() {
2299
+ this.pendingMediaStream = null, this.peer?.stopMedia();
2300
+ }
2301
+ onRemoteStream(e) {
2302
+ this.onRemoteStreamHandler = e, this.peer?.onRemoteStream(e);
2303
+ }
2304
+ onStateChange(e) {
2305
+ this.onStateChangeHandler = e, e(this.peer?.getPeerState() ?? "passive");
2306
+ }
2307
+ onMediaChange(e) {
2308
+ this.onMediaChangeHandler = e, e(this.peer?.getMediaState() ?? "idle");
2309
+ }
2310
+ }, V = (e) => (t, n) => {
2311
+ let r = e === "debug" ? console.info : console[e];
2312
+ if (n !== void 0) {
2313
+ r(t, n);
2314
+ return;
2315
+ }
2316
+ r(t);
2317
+ }, H = {
2318
+ debug: V("debug"),
2319
+ info: V("info"),
2320
+ warn: V("warn"),
2321
+ error: V("error")
2322
+ }, ze = (e) => {
2323
+ if (typeof e != "string") return {
2324
+ ok: !1,
2325
+ error: /* @__PURE__ */ TypeError("decodeSafe expects a serialized string")
2326
+ };
2327
+ try {
2328
+ return {
2329
+ ok: !0,
2330
+ value: JSON.parse(e)
2331
+ };
2332
+ } catch (e) {
2333
+ return {
2334
+ ok: !1,
2335
+ error: e
2336
+ };
2337
+ }
2338
+ }, Be = (e) => {
2339
+ if (typeof e != "string") return !e || typeof e != "object" ? null : e;
2340
+ let t = ze(e);
2341
+ return !t.ok || !t.value || typeof t.value != "object" ? null : t.value;
2342
+ }, Ve = class {
2343
+ handlers = {};
2344
+ processingQueue = Promise.resolve();
2345
+ emit(e, t, n = "local") {
2346
+ this.dispatch({
2347
+ type: e,
2348
+ payload: t,
2349
+ from: n
2350
+ });
2351
+ }
2352
+ register(e, t) {
2353
+ this.handlers[e] = t, H.debug(`[session:bus] registered ${e}`);
2354
+ }
2355
+ dispatch(e) {
2356
+ this.processingQueue = this.processingQueue.then(async () => {
2357
+ H.debug(`[session:bus] dispatch ${e.type}`, {
2358
+ from: e.from,
2359
+ payload: e.payload,
2360
+ turn: e.turn,
2361
+ sid: e.sid
2362
+ });
2363
+ let t = this.handlers[e.type];
2364
+ if (t) {
2365
+ try {
2366
+ await t(e), H.debug(`[session:bus] handled ${e.type}`, { from: e.from });
2367
+ } catch (t) {
2368
+ console.error(`[CommandBus] Error in ${e.type}:`, t);
2369
+ }
2370
+ return;
2371
+ }
2372
+ H.debug(`[session:bus] no handler for ${e.type}`, { from: e.from });
2373
+ });
2374
+ }
2375
+ }, U = [
2376
+ {
2377
+ from: "idle",
2378
+ event: "READY",
2379
+ to: "ready"
2380
+ },
2381
+ {
2382
+ from: "ready",
2383
+ event: "READY",
2384
+ to: "idle"
2385
+ },
2386
+ {
2387
+ from: "idle",
2388
+ event: "REMOTE_READY",
2389
+ to: "could_start"
2390
+ },
2391
+ {
2392
+ from: "could_start",
2393
+ event: "REMOTE_READY",
2394
+ to: "idle"
2395
+ },
2396
+ {
2397
+ from: "ready",
2398
+ event: "REJECT",
2399
+ to: "idle"
2400
+ },
2401
+ {
2402
+ from: "could_start",
2403
+ event: "REJECT",
2404
+ to: "idle"
2405
+ },
2406
+ {
2407
+ from: "ready",
2408
+ event: "REMOTE_START",
2409
+ to: "turn"
2410
+ },
2411
+ {
2412
+ from: "ready",
2413
+ event: "REMOTE_START",
2414
+ to: "remote_turn"
2415
+ },
2416
+ {
2417
+ from: "could_start",
2418
+ event: "START",
2419
+ to: "turn"
2420
+ },
2421
+ {
2422
+ from: "could_start",
2423
+ event: "START",
2424
+ to: "remote_turn"
2425
+ },
2426
+ {
2427
+ from: "turn",
2428
+ event: "MOVE",
2429
+ to: "remote_turn"
2430
+ },
2431
+ {
2432
+ from: "remote_turn",
2433
+ event: "REMOTE_MOVE",
2434
+ to: "turn"
2435
+ },
2436
+ {
2437
+ from: "turn",
2438
+ event: "REJECT",
2439
+ to: "turn"
2440
+ },
2441
+ {
2442
+ from: "remote_turn",
2443
+ event: "REJECT",
2444
+ to: "remote_turn"
2445
+ },
2446
+ {
2447
+ from: "turn",
2448
+ event: "UNDO",
2449
+ to: "waiting_approval"
2450
+ },
2451
+ {
2452
+ from: "remote_turn",
2453
+ event: "UNDO",
2454
+ to: "waiting_approval"
2455
+ },
2456
+ {
2457
+ from: "turn",
2458
+ event: "RESTART",
2459
+ to: "waiting_approval"
2460
+ },
2461
+ {
2462
+ from: "remote_turn",
2463
+ event: "RESTART",
2464
+ to: "waiting_approval"
2465
+ },
2466
+ {
2467
+ from: "turn",
2468
+ event: "REMOTE_UNDO",
2469
+ to: "approving"
2470
+ },
2471
+ {
2472
+ from: "remote_turn",
2473
+ event: "REMOTE_UNDO",
2474
+ to: "approving"
2475
+ },
2476
+ {
2477
+ from: "turn",
2478
+ event: "REMOTE_RESTART",
2479
+ to: "approving"
2480
+ },
2481
+ {
2482
+ from: "remote_turn",
2483
+ event: "REMOTE_RESTART",
2484
+ to: "approving"
2485
+ },
2486
+ {
2487
+ from: "waiting_approval",
2488
+ event: "APPROVE",
2489
+ to: "turn"
2490
+ },
2491
+ {
2492
+ from: "waiting_approval",
2493
+ event: "REJECT",
2494
+ to: "turn"
2495
+ },
2496
+ {
2497
+ from: "waiting_approval",
2498
+ event: "REJECT",
2499
+ to: "remote_turn"
2500
+ },
2501
+ {
2502
+ from: "approving",
2503
+ event: "APPROVE",
2504
+ to: "remote_turn"
2505
+ },
2506
+ {
2507
+ from: "approving",
2508
+ event: "REJECT",
2509
+ to: "remote_turn"
2510
+ },
2511
+ {
2512
+ from: "approving",
2513
+ event: "REJECT",
2514
+ to: "turn"
2515
+ },
2516
+ {
2517
+ from: "turn",
2518
+ event: "GAME_OVER",
2519
+ to: "idle"
2520
+ },
2521
+ {
2522
+ from: "remote_turn",
2523
+ event: "GAME_OVER",
2524
+ to: "idle"
2525
+ },
2526
+ {
2527
+ from: "turn",
2528
+ event: "SYNC",
2529
+ to: "syncing"
2530
+ },
2531
+ {
2532
+ from: "remote_turn",
2533
+ event: "SYNC",
2534
+ to: "syncing"
2535
+ },
2536
+ {
2537
+ from: "waiting_approval",
2538
+ event: "SYNC",
2539
+ to: "syncing"
2540
+ },
2541
+ {
2542
+ from: "approving",
2543
+ event: "SYNC",
2544
+ to: "syncing"
2545
+ },
2546
+ {
2547
+ from: "idle",
2548
+ event: "SYNC",
2549
+ to: "syncing"
2550
+ },
2551
+ {
2552
+ from: "ready",
2553
+ event: "SYNC",
2554
+ to: "syncing"
2555
+ },
2556
+ {
2557
+ from: "could_start",
2558
+ event: "SYNC",
2559
+ to: "syncing"
2560
+ },
2561
+ {
2562
+ from: "syncing",
2563
+ event: "SYNC_COMPLETE",
2564
+ to: "turn"
2565
+ },
2566
+ {
2567
+ from: "syncing",
2568
+ event: "SYNC_COMPLETE",
2569
+ to: "remote_turn"
2570
+ },
2571
+ {
2572
+ from: "idle",
2573
+ event: "OFFLINE",
2574
+ to: "offline"
2575
+ },
2576
+ {
2577
+ from: "ready",
2578
+ event: "OFFLINE",
2579
+ to: "offline"
2580
+ },
2581
+ {
2582
+ from: "could_start",
2583
+ event: "OFFLINE",
2584
+ to: "offline"
2585
+ },
2586
+ {
2587
+ from: "turn",
2588
+ event: "OFFLINE",
2589
+ to: "offline"
2590
+ },
2591
+ {
2592
+ from: "remote_turn",
2593
+ event: "OFFLINE",
2594
+ to: "offline"
2595
+ },
2596
+ {
2597
+ from: "waiting_approval",
2598
+ event: "OFFLINE",
2599
+ to: "offline"
2600
+ },
2601
+ {
2602
+ from: "approving",
2603
+ event: "OFFLINE",
2604
+ to: "offline"
2605
+ },
2606
+ {
2607
+ from: "syncing",
2608
+ event: "OFFLINE",
2609
+ to: "offline"
2610
+ },
2611
+ {
2612
+ from: "offline",
2613
+ event: "ONLINE",
2614
+ to: "syncing"
2615
+ }
2616
+ ], He = (e, t, n) => {
2617
+ if (n) return U.find((r) => r.from === e && r.event === t && r.to === n) ? n : e;
2618
+ {
2619
+ let n = U.find((n) => n.from === e && n.event === t);
2620
+ return n ? n.to : e;
2621
+ }
2622
+ }, Ue = (e, t, n) => n ? !!U.find((r) => r.from === e && r.event === t && r.to === n) : !!U.find((n) => n.from === e && n.event === t), W = class {
2623
+ state;
2624
+ constructor(e = "idle") {
2625
+ this.state = e;
2626
+ }
2627
+ getState() {
2628
+ return this.state;
2629
+ }
2630
+ hasNextState(e, t) {
2631
+ return Ue(this.state, e, t);
2632
+ }
2633
+ dispatch(e, t) {
2634
+ this.state = He(this.state, e, t);
2635
+ }
2636
+ }, We = class {
2637
+ validateMove() {
2638
+ return { valid: !0 };
2639
+ }
2640
+ checkWin() {
2641
+ return null;
2642
+ }
2643
+ }, Ge = class {
2644
+ observers = /* @__PURE__ */ new Set();
2645
+ subscribe(e) {
2646
+ this.observers.add(e);
2647
+ }
2648
+ unsubscribe(e) {
2649
+ this.observers.delete(e);
2650
+ }
2651
+ notifyStateChanged() {
2652
+ for (let e of this.observers) try {
2653
+ e.onStateChanged?.();
2654
+ } catch (e) {
2655
+ console.error("[StateObserver]", e);
2656
+ }
2657
+ }
2658
+ notifyHistoryChanged() {
2659
+ for (let e of this.observers) try {
2660
+ e.onHistoryChanged?.();
2661
+ } catch (e) {
2662
+ console.error("[StateObserver]", e);
2663
+ }
2664
+ }
2665
+ notifyGameReset() {
2666
+ for (let e of this.observers) try {
2667
+ e.onGameReset?.();
2668
+ } catch (e) {
2669
+ console.error("[StateObserver]", e);
2670
+ }
2671
+ }
2672
+ }, Ke = class {
2673
+ observers = /* @__PURE__ */ new Set();
2674
+ currentSnapshot = null;
2675
+ subscribe(e) {
2676
+ return this.observers.add(e), () => {
2677
+ this.observers.delete(e);
2678
+ };
2679
+ }
2680
+ unsubscribe(e) {
2681
+ this.observers.delete(e);
2682
+ }
2683
+ notifyStateChange(e) {
2684
+ this.currentSnapshot = e;
2685
+ for (let t of this.observers) try {
2686
+ t.onStateChange(e);
2687
+ } catch (e) {
2688
+ console.error("[GameStateObserver]", e);
2689
+ }
2690
+ }
2691
+ notifyGameEvent(e) {
2692
+ e.timestamp = Date.now();
2693
+ for (let t of this.observers) try {
2694
+ t.onGameEvent(e);
2695
+ } catch (e) {
2696
+ console.error("[GameStateObserver]", e);
2697
+ }
2698
+ }
2699
+ notifyConnectionChange(e) {
2700
+ for (let t of this.observers) try {
2701
+ t.onConnectionChange?.(e);
2702
+ } catch (e) {
2703
+ console.error("[GameStateObserver]", e);
2704
+ }
2705
+ }
2706
+ notifyError(e) {
2707
+ for (let t of this.observers) try {
2708
+ t.onError?.(e);
2709
+ } catch (e) {
2710
+ console.error("[GameStateObserver]", e);
2711
+ }
2712
+ }
2713
+ getSnapshot() {
2714
+ return this.currentSnapshot;
2715
+ }
2716
+ getObserverCount() {
2717
+ return this.observers.size;
2718
+ }
2719
+ };
2720
+ function qe(e, t = !1) {
2721
+ return {
2722
+ localState: e.getState("local"),
2723
+ remoteState: e.getState("remote"),
2724
+ turn: e.getTurnCount(),
2725
+ history: e.getHistory(),
2726
+ lastStart: e.getLastStart(),
2727
+ pendingAction: e.getPendingAction(),
2728
+ connected: t
2729
+ };
2730
+ }
2731
+ var Je = class {
2732
+ lastNotificationTime = 0;
2733
+ notificationThrottleMs = 0;
2734
+ constructor(e, t, n = () => !1) {
2735
+ this.stateRef = e, this.uiObserver = t, this.getConnected = n;
2736
+ }
2737
+ onStateChanged() {
2738
+ let e = Date.now();
2739
+ if (this.lastNotificationTime + this.notificationThrottleMs > e) return;
2740
+ this.lastNotificationTime = e;
2741
+ let t = qe(this.stateRef, this.getConnected());
2742
+ H.debug("[session:observer] state snapshot", {
2743
+ local: t.localState,
2744
+ remote: t.remoteState,
2745
+ turn: t.turn,
2746
+ history: t.history.length,
2747
+ pending: t.pendingAction,
2748
+ connected: t.connected
2749
+ }), this.uiObserver.notifyStateChange(t);
2750
+ }
2751
+ onHistoryChanged() {
2752
+ this.onStateChanged();
2753
+ }
2754
+ onGameReset() {
2755
+ this.onStateChanged();
2756
+ }
2757
+ emitEvent(e) {
2758
+ this.uiObserver.notifyGameEvent(e);
2759
+ }
2760
+ }, Ye = class {
2761
+ local = new W("idle");
2762
+ remote = new W("idle");
2763
+ localId = null;
2764
+ remoteId = null;
2765
+ history = [];
2766
+ pendingAction = null;
2767
+ pendingUndoCount = null;
2768
+ resumeTurn = null;
2769
+ lastStart = null;
2770
+ gamePlugin = new We();
2771
+ stateObserverManager = new Ge();
2772
+ constructor(e, t) {
2773
+ e && (this.localId = e), t && (this.remoteId = t), H.debug("[session:state] created", {
2774
+ localId: e,
2775
+ remoteId: t
2776
+ });
2777
+ }
2778
+ subscribeStateObserver(e) {
2779
+ this.stateObserverManager.subscribe(e);
2780
+ }
2781
+ getId() {
2782
+ return this.localId;
2783
+ }
2784
+ getremoteId() {
2785
+ return this.remoteId;
2786
+ }
2787
+ setremoteId(e) {
2788
+ this.remoteId = e, H.debug("[session:state] remote id set", { remoteId: e });
2789
+ }
2790
+ getState(e) {
2791
+ return this.getPlayerFsm(e).getState();
2792
+ }
2793
+ getTurnCount() {
2794
+ return this.history.length + 1;
2795
+ }
2796
+ getHistory() {
2797
+ return this.history.slice();
2798
+ }
2799
+ replaceHistory(e) {
2800
+ H.debug("[session:history] replace", { count: e.length }), this.clearHistory(), e.forEach((e) => {
2801
+ this.pushHistory({
2802
+ turn: e.turn,
2803
+ player: e.player,
2804
+ move: e.move
2805
+ });
2806
+ });
2807
+ }
2808
+ clearHistory() {
2809
+ let e = this.history.length;
2810
+ this.history.splice(0, this.history.length), H.debug("[session:history] clear", { count: e }), this.notifyHistoryChanged();
2811
+ }
2812
+ pushHistory(e) {
2813
+ this.history.push(e), H.debug("[session:history] push", {
2814
+ turn: e.turn,
2815
+ player: e.player,
2816
+ move: e.move,
2817
+ count: this.history.length
2818
+ }), this.notifyHistoryChanged();
2819
+ }
2820
+ popHistory() {
2821
+ let e = this.history.pop() ?? null;
2822
+ return e && (H.debug("[session:history] pop", {
2823
+ turn: e.turn,
2824
+ player: e.player,
2825
+ move: e.move,
2826
+ count: this.history.length
2827
+ }), this.notifyHistoryChanged()), e;
2828
+ }
2829
+ canAction(e, t) {
2830
+ return this.getPlayerFsm(e).hasNextState(t);
2831
+ }
2832
+ dispatch(e, t, n) {
2833
+ let r = this.getState(e);
2834
+ this.getPlayerFsm(e).dispatch(t, n);
2835
+ let i = this.getState(e);
2836
+ H.debug(`[session:fsm] ${e} ${t}`, {
2837
+ from: r,
2838
+ to: i,
2839
+ requested: n,
2840
+ local: this.getState("local"),
2841
+ remote: this.getState("remote"),
2842
+ turn: this.getTurnCount(),
2843
+ history: this.history.length,
2844
+ pending: this.pendingAction
2845
+ }), this.notifyStateChanged();
2846
+ }
2847
+ setPendingAction(e) {
2848
+ H.debug("[session:state] pending action set", {
2849
+ from: this.pendingAction,
2850
+ to: e
2851
+ }), this.pendingAction = e;
2852
+ }
2853
+ getPendingAction() {
2854
+ return this.pendingAction;
2855
+ }
2856
+ setPendingUndoCount(e) {
2857
+ H.debug("[session:state] pending undo count set", {
2858
+ from: this.pendingUndoCount,
2859
+ to: e
2860
+ }), this.pendingUndoCount = e;
2861
+ }
2862
+ getPendingUndoCount() {
2863
+ return this.pendingUndoCount;
2864
+ }
2865
+ setLastStart(e) {
2866
+ H.debug("[session:state] last start set", {
2867
+ from: this.lastStart,
2868
+ to: e
2869
+ }), this.lastStart = e;
2870
+ }
2871
+ getLastStart() {
2872
+ return this.lastStart;
2873
+ }
2874
+ setResumeTurn(e) {
2875
+ H.debug("[session:state] resume turn set", {
2876
+ from: this.resumeTurn,
2877
+ to: e
2878
+ }), this.resumeTurn = e;
2879
+ }
2880
+ getResumeTurn() {
2881
+ return this.resumeTurn;
2882
+ }
2883
+ getPlayerFsm(e) {
2884
+ return e === "local" ? this.local : this.remote;
2885
+ }
2886
+ notifyStateChanged() {
2887
+ H.debug("[session:state] notify state changed", {
2888
+ local: this.getState("local"),
2889
+ remote: this.getState("remote"),
2890
+ turn: this.getTurnCount(),
2891
+ history: this.history.length,
2892
+ pending: this.pendingAction
2893
+ }), this.stateObserverManager.notifyStateChanged();
2894
+ }
2895
+ notifyHistoryChanged() {
2896
+ H.debug("[session:state] notify history changed", {
2897
+ turn: this.getTurnCount(),
2898
+ history: this.history.length,
2899
+ pending: this.pendingAction
2900
+ }), this.stateObserverManager.notifyHistoryChanged();
2901
+ }
2902
+ notifyGameReset() {
2903
+ H.debug("[session:state] notify game reset"), this.stateObserverManager.notifyGameReset();
2904
+ }
2905
+ dispatchPair(e, t, n, r) {
2906
+ let i = {
2907
+ local: this.local.getState(),
2908
+ remote: this.remote.getState()
2909
+ };
2910
+ this.local.dispatch(e, t), this.remote.dispatch(n, r), H.debug("[session:fsm] pair dispatch", {
2911
+ before: i,
2912
+ after: {
2913
+ local: this.local.getState(),
2914
+ remote: this.remote.getState()
2915
+ },
2916
+ localAction: e,
2917
+ localTo: t,
2918
+ remoteAction: n,
2919
+ remoteTo: r,
2920
+ turn: this.getTurnCount(),
2921
+ history: this.history.length,
2922
+ pending: this.pendingAction
2923
+ }), this.notifyStateChanged();
2924
+ }
2925
+ gameSnapshot = null;
2926
+ saveGameSnapshot(e) {
2927
+ this.gameSnapshot = e, H.debug("[session:state] game snapshot saved", { snapshot: e });
2928
+ }
2929
+ getGameSnapshot() {
2930
+ return this.gameSnapshot;
2931
+ }
2932
+ clearGameSnapshot() {
2933
+ this.gameSnapshot = null, H.debug("[session:state] game snapshot cleared");
2934
+ }
2935
+ hasPendingAction() {
2936
+ return this.pendingAction !== null;
2937
+ }
2938
+ clearPendingStates() {
2939
+ H.debug("[session:state] pending states cleared", {
2940
+ pending: this.pendingAction,
2941
+ pendingUndoCount: this.pendingUndoCount,
2942
+ resumeTurn: this.resumeTurn
2943
+ }), this.pendingAction = null, this.pendingUndoCount = null, this.resumeTurn = null, this.notifyStateChanged();
2944
+ }
2945
+ initializeUndoRequest(e, t) {
2946
+ this.pendingAction = "undo", this.pendingUndoCount = e, this.resumeTurn = t, H.debug("[session:state] undo request initialized", {
2947
+ undoCount: e,
2948
+ resumeTurn: t
2949
+ });
2950
+ }
2951
+ initializeRestartRequest(e) {
2952
+ this.pendingAction = "restart", this.resumeTurn = e, H.debug("[session:state] restart request initialized", { resumeTurn: e });
2953
+ }
2954
+ isPendingUndo() {
2955
+ return this.pendingAction === "undo";
2956
+ }
2957
+ isPendingRestart() {
2958
+ return this.pendingAction === "restart";
2959
+ }
2960
+ applyUndo(e = 1) {
2961
+ H.debug("[session:history] apply undo", { count: e });
2962
+ for (let t = 0; t < e; t++) this.popHistory();
2963
+ }
2964
+ resetGame() {
2965
+ H.debug("[session:state] reset game", {
2966
+ local: this.getState("local"),
2967
+ remote: this.getState("remote"),
2968
+ history: this.history.length,
2969
+ lastStart: this.lastStart,
2970
+ pending: this.pendingAction
2971
+ }), this.clearHistory(), this.local = new W("idle"), this.remote = new W("idle"), this.lastStart = null, this.pendingAction = null, this.pendingUndoCount = null, this.resumeTurn = null, this.notifyGameReset(), this.notifyStateChanged();
2972
+ }
2973
+ recordStartPlayer(e) {
2974
+ this.lastStart = e, H.debug("[session:state] start player recorded", { player: e });
2975
+ }
2976
+ getLastMove() {
2977
+ return this.history.length > 0 ? this.history[this.history.length - 1] : null;
2978
+ }
2979
+ dispatchApprove() {
2980
+ let e = this.local.getState();
2981
+ e === "waiting_approval" ? this.dispatchPair("APPROVE", "turn", "APPROVE", "remote_turn") : e === "approving" && this.dispatchPair("APPROVE", "remote_turn", "APPROVE", "turn");
2982
+ }
2983
+ dispatchReject() {
2984
+ let e = this.local.getState();
2985
+ if (e === "waiting_approval" || e === "approving") {
2986
+ let e = this.resumeTurn === "local" ? "turn" : "remote_turn", t = this.resumeTurn === "local" ? "remote_turn" : "turn";
2987
+ this.dispatchPair("REJECT", e, "REJECT", t);
2988
+ }
2989
+ }
2990
+ dispatchStart(e) {
2991
+ let t = {
2992
+ local: this.local.getState(),
2993
+ remote: this.remote.getState(),
2994
+ lastStart: this.lastStart
2995
+ };
2996
+ e === "local" ? (this.local.dispatch("START", "turn"), this.remote.dispatch("START", "remote_turn"), this.lastStart = "local") : (this.local.dispatch("START", "remote_turn"), this.remote.dispatch("START", "turn"), this.lastStart = "remote"), H.debug("[session:fsm] start dispatch", {
2997
+ before: t,
2998
+ firstPlayer: e,
2999
+ after: {
3000
+ local: this.local.getState(),
3001
+ remote: this.remote.getState(),
3002
+ lastStart: this.lastStart
3003
+ }
3004
+ }), this.notifyStateChanged();
3005
+ }
3006
+ dispatchSyncComplete(e) {
3007
+ e === "local" ? this.dispatchPair("SYNC_COMPLETE", "turn", "SYNC_COMPLETE", "remote_turn") : this.dispatchPair("SYNC_COMPLETE", "remote_turn", "SYNC_COMPLETE", "turn"), this.resumeTurn = null;
3008
+ }
3009
+ setGamePlugin(e) {
3010
+ this.gamePlugin = e, H.debug("[session:plugin] game plugin set", {
3011
+ hasInitialize: !!e.initialize,
3012
+ hasCleanup: !!e.cleanup
3013
+ }), e.initialize && e.initialize();
3014
+ }
3015
+ getGamePlugin() {
3016
+ return this.gamePlugin;
3017
+ }
3018
+ validateMove(e) {
3019
+ let t = this.buildGameState(), n = this.gamePlugin.validateMove(e, t);
3020
+ return H.debug("[session:plugin] validate move", {
3021
+ move: e,
3022
+ result: n,
3023
+ local: t.localState,
3024
+ remote: t.remoteState,
3025
+ turn: t.turn,
3026
+ history: t.history.length
3027
+ }), n;
3028
+ }
3029
+ checkWin() {
3030
+ let e = this.buildGameState(), t = this.gamePlugin.checkWin(e, this.getHistory());
3031
+ return H.debug("[session:plugin] check win", {
3032
+ winner: t,
3033
+ turn: e.turn,
3034
+ history: e.history.length
3035
+ }), t;
3036
+ }
3037
+ cleanupGame() {
3038
+ this.gamePlugin.cleanup && this.gamePlugin.cleanup(), H.debug("[session:plugin] cleanup game");
3039
+ }
3040
+ buildGameState() {
3041
+ return {
3042
+ history: this.getHistory(),
3043
+ localState: this.getState("local"),
3044
+ remoteState: this.getState("remote"),
3045
+ turn: this.getTurnCount(),
3046
+ lastStart: this.getLastStart()
3047
+ };
3048
+ }
3049
+ }, Xe = class {
3050
+ localPeerId;
3051
+ remotePeerId;
3052
+ isConnected = !1;
3053
+ connectionChangeListener = () => {};
3054
+ mediaStateListener = () => {};
3055
+ constructor(e, t, n) {
3056
+ this.client = e, this.bus = t, this.localPeerId = n ?? null, this.remotePeerId = null, this.client.onMessage((e) => {
3057
+ let t = Be(e);
3058
+ !t || typeof t != "object" || !t.type || this.bus.dispatch({
3059
+ ...t,
3060
+ type: t.type,
3061
+ from: "remote"
3062
+ });
3063
+ }), this.client.onStateChange((e) => {
3064
+ let t = this.isConnected;
3065
+ this.isConnected = e === "connected", this.connectionChangeListener(this.isConnected), this.isConnected && !t ? this.bus.emit("ONLINE", void 0, "local") : !this.isConnected && t && this.bus.emit("OFFLINE", void 0, "local");
3066
+ }), this.client.onRemoteStream((e) => {
3067
+ let t = !!e && e.getTracks().some((e) => e.readyState === "live");
3068
+ this.mediaStateListener(t);
3069
+ });
3070
+ }
3071
+ send(e) {
3072
+ if (!this.isConnected) {
3073
+ console.warn("[NetClient] Cannot send message: not connected", e.type);
3074
+ return;
3075
+ }
3076
+ let t = {
3077
+ ...e,
3078
+ from: e.from ?? this.localPeerId ?? ""
3079
+ };
3080
+ this.client.send(t);
3081
+ }
3082
+ setPeerIds(e) {
3083
+ e.local !== void 0 && (this.localPeerId = e.local), e.remote !== void 0 && (this.remotePeerId = e.remote);
3084
+ }
3085
+ getPeerIds() {
3086
+ return {
3087
+ local: this.localPeerId,
3088
+ remote: this.remotePeerId
3089
+ };
3090
+ }
3091
+ getIsConnected() {
3092
+ return this.isConnected;
3093
+ }
3094
+ onConnectionChange(e) {
3095
+ this.connectionChangeListener = e, e(this.isConnected);
3096
+ }
3097
+ onMediaStateChange(e) {
3098
+ this.mediaStateListener = e;
3099
+ }
3100
+ }, Ze = (e, t, n) => new Xe(e, t, n), Qe = class {
3101
+ state;
3102
+ bus;
3103
+ net;
3104
+ sid;
3105
+ constructor(e, t, n, r) {
3106
+ this.state = e, this.bus = t, this.net = n, this.sid = r;
3107
+ }
3108
+ getState() {
3109
+ return this.state;
3110
+ }
3111
+ getBus() {
3112
+ return this.bus;
3113
+ }
3114
+ getNet() {
3115
+ return this.net;
3116
+ }
3117
+ getSid() {
3118
+ return this.sid;
3119
+ }
3120
+ }, G = null, $e = (e, t, n, r) => {
3121
+ G = new Qe(e, t, n, r);
3122
+ }, K = () => {
3123
+ if (!G) throw Error("[SessionContext] Not initialized. Call initializeContext() first.");
3124
+ return G;
3125
+ }, q = () => K().getState(), J = () => K().getBus(), et = () => K().getSid(), Y = (e) => K().getNet().send(e), tt = (e) => {
3126
+ let t = q(), n = J(), r = et();
3127
+ if (H.debug("[session:ready] received", {
3128
+ from: e.from,
3129
+ sid: e.sid,
3130
+ localSid: r,
3131
+ local: t.getState("local"),
3132
+ remote: t.getState("remote")
3133
+ }), e.from === "local") {
3134
+ if (!t.canAction("local", "READY")) {
3135
+ console.warn("[Ready] Cannot dispatch READY from current state", { state: t.getState("local") });
3136
+ return;
3137
+ }
3138
+ t.dispatch("local", "READY"), t.dispatch("remote", "REMOTE_READY"), Y({
3139
+ type: "READY",
3140
+ sid: r
3141
+ }), H.debug("[session:ready] local toggled", {
3142
+ local: t.getState("local"),
3143
+ remote: t.getState("remote")
3144
+ });
3145
+ return;
3146
+ }
3147
+ let i = e.sid;
3148
+ if (!i || r !== i) {
3149
+ console.warn("[Ready] Session ID mismatch", {
3150
+ local: r,
3151
+ remote: i
3152
+ }), n.emit("REJECT", { reason: "sid-mismatch" }, "local");
3153
+ return;
3154
+ }
3155
+ if (!t.canAction("remote", "READY")) {
3156
+ console.warn("[Ready] Cannot dispatch READY for remote peer", { state: t.getState("remote") });
3157
+ return;
3158
+ }
3159
+ t.dispatch("remote", "READY"), t.dispatch("local", "REMOTE_READY"), H.debug("[session:ready] remote toggled", {
3160
+ local: t.getState("local"),
3161
+ remote: t.getState("remote")
3162
+ });
3163
+ }, nt = (e) => e ? e === "local" ? "remote" : "local" : Math.random() < .5 ? "local" : "remote", rt = (e) => {
3164
+ let t = q();
3165
+ if (H.debug("[session:start] received", {
3166
+ from: e.from,
3167
+ payload: e.payload,
3168
+ local: t.getState("local"),
3169
+ remote: t.getState("remote"),
3170
+ lastStart: t.getLastStart()
3171
+ }), e.from === "local") {
3172
+ if (!t.canAction("local", "START") || !t.canAction("remote", "REMOTE_START")) {
3173
+ console.warn("[Start] Cannot START from current state", {
3174
+ localState: t.getState("local"),
3175
+ remoteState: t.getState("remote")
3176
+ });
3177
+ return;
3178
+ }
3179
+ let e = nt(t.getLastStart()), n = e === "local" ? "turn" : "remote_turn", r = e === "local" ? "remote_turn" : "turn";
3180
+ t.getHistory().length > 0 && (t.clearHistory(), H.debug("[session:start] cleared previous match history")), t.setLastStart(e), t.dispatch("local", "START", n), t.dispatch("remote", "REMOTE_START", r), Y({
3181
+ type: "START",
3182
+ payload: { starter: e === "local" ? "sender" : "receiver" }
3183
+ }), H.debug("[session:start] local started", { nextStarter: e });
3184
+ return;
3185
+ }
3186
+ let n = e.payload?.starter;
3187
+ if (!n) {
3188
+ console.warn("[Start] Invalid START message format", { payload: e });
3189
+ return;
3190
+ }
3191
+ if (!t.canAction("local", "REMOTE_START") || !t.canAction("remote", "START")) {
3192
+ console.warn("[Start] Cannot START from current state", {
3193
+ localState: t.getState("local"),
3194
+ remoteState: t.getState("remote")
3195
+ });
3196
+ return;
3197
+ }
3198
+ let r = n === "sender" ? "remote" : "local", i = r === "local" ? "turn" : "remote_turn", a = r === "local" ? "remote_turn" : "turn";
3199
+ t.getHistory().length > 0 && (t.clearHistory(), H.debug("[session:start] cleared previous match history")), t.setLastStart(r), t.dispatch("local", "REMOTE_START", i), t.dispatch("remote", "START", a), H.debug("[session:start] remote started", { starter: r });
3200
+ }, it = (e) => {
3201
+ let t = q(), n = e.payload;
3202
+ if (H.debug("[session:move] received", {
3203
+ from: e.from,
3204
+ payload: n,
3205
+ local: t.getState("local"),
3206
+ remote: t.getState("remote"),
3207
+ turn: t.getTurnCount(),
3208
+ history: t.getHistory().length
3209
+ }), e.from === "local") {
3210
+ if (!t.canAction("local", "MOVE")) {
3211
+ console.warn("[Move] Cannot MOVE from current state", { state: t.getState("local") });
3212
+ return;
3213
+ }
3214
+ let e = t.validateMove(n);
3215
+ if (!e.valid) {
3216
+ console.warn("[Move] Move validation failed", {
3217
+ reason: e.reason,
3218
+ move: n
3219
+ });
3220
+ return;
3221
+ }
3222
+ t.dispatch("local", "MOVE"), t.dispatch("remote", "REMOTE_MOVE");
3223
+ let r = t.getTurnCount();
3224
+ t.pushHistory({
3225
+ turn: r,
3226
+ player: "local",
3227
+ move: n
3228
+ }), Y({
3229
+ type: "MOVE",
3230
+ turn: r,
3231
+ payload: n
3232
+ }), H.debug("[session:move] local move sent", {
3233
+ turn: r,
3234
+ payload: n
3235
+ });
3236
+ let i = t.checkWin();
3237
+ if (i) {
3238
+ H.debug("[session:move] game over detected", {
3239
+ winner: i,
3240
+ turn: r
3241
+ }), t.dispatch("local", "GAME_OVER"), t.dispatch("remote", "GAME_OVER"), t.cleanupGame(), H.debug("[session:move] local game over applied", {
3242
+ winner: i,
3243
+ turn: r
3244
+ });
3245
+ return;
3246
+ }
3247
+ return;
3248
+ }
3249
+ if (!t.canAction("remote", "MOVE")) {
3250
+ console.warn("[Move] Cannot MOVE for remote player", { state: t.getState("remote") });
3251
+ return;
3252
+ }
3253
+ let r = t.validateMove(n);
3254
+ if (!r.valid) {
3255
+ console.warn("[Move] Remote move validation failed", {
3256
+ reason: r.reason,
3257
+ move: n
3258
+ });
3259
+ return;
3260
+ }
3261
+ t.dispatch("remote", "MOVE"), t.dispatch("local", "REMOTE_MOVE");
3262
+ let i = t.getTurnCount();
3263
+ t.pushHistory({
3264
+ turn: i,
3265
+ player: "remote",
3266
+ move: n
3267
+ });
3268
+ let a = t.checkWin();
3269
+ if (a) {
3270
+ H.debug("[session:move] game over detected", {
3271
+ winner: a,
3272
+ turn: i
3273
+ }), t.dispatch("local", "GAME_OVER"), t.dispatch("remote", "GAME_OVER"), t.cleanupGame(), H.debug("[session:move] remote game over applied", {
3274
+ winner: a,
3275
+ turn: i
3276
+ });
3277
+ return;
3278
+ }
3279
+ H.debug("[session:move] remote move applied", {
3280
+ turn: i,
3281
+ payload: n
3282
+ });
3283
+ }, at = (e) => e === "undo" || e === "restart", ot = (e) => {
3284
+ if (e.type !== "APPROVE" && e.type !== "REJECT") return;
3285
+ let t = q(), n = e.payload, r = t.getPendingAction(), i = r ?? (e.from === "local" && e.type === "REJECT" && at(n?.action) ? n.action : null);
3286
+ if (H.debug("[session:request] received", {
3287
+ type: e.type,
3288
+ from: e.from,
3289
+ action: i,
3290
+ local: t.getState("local"),
3291
+ remote: t.getState("remote"),
3292
+ history: t.getHistory().length
3293
+ }), !i) {
3294
+ console.warn("[Request] No pending action", { commandType: e.type });
3295
+ return;
3296
+ }
3297
+ if (n?.action && n.action !== i) {
3298
+ console.warn("[Request] Action mismatch", {
3299
+ pending: i,
3300
+ payload: n.action
3301
+ });
3302
+ return;
3303
+ }
3304
+ if (e.from === "local") {
3305
+ if (!r && e.type === "REJECT") {
3306
+ Y({
3307
+ type: "REJECT",
3308
+ payload: {
3309
+ action: i,
3310
+ reason: n?.reason ?? "rejected"
3311
+ }
3312
+ }), H.debug("[session:request] local auto rejected", {
3313
+ action: i,
3314
+ reason: n?.reason
3315
+ });
3316
+ return;
3317
+ }
3318
+ if (e.type === "APPROVE") {
3319
+ if (!t.canAction("local", "APPROVE")) {
3320
+ console.warn("[Request] Cannot APPROVE from current state");
3321
+ return;
3322
+ }
3323
+ t.dispatchApprove(), i === "undo" ? t.applyUndo(t.getPendingUndoCount() ?? 1) : i === "restart" && t.resetGame(), Y({
3324
+ type: "APPROVE",
3325
+ payload: { action: i }
3326
+ }), t.clearPendingStates(), H.debug("[session:request] local approved", { action: i });
3327
+ return;
3328
+ }
3329
+ if (!t.canAction("local", "REJECT")) {
3330
+ console.warn("[Request] Cannot REJECT from current state");
3331
+ return;
3332
+ }
3333
+ t.dispatchReject(), Y({
3334
+ type: "REJECT",
3335
+ payload: {
3336
+ action: i,
3337
+ reason: n?.reason ?? "rejected"
3338
+ }
3339
+ }), t.clearPendingStates(), H.debug("[session:request] local rejected", { action: i });
3340
+ return;
3341
+ }
3342
+ if (e.type === "APPROVE") {
3343
+ if (!t.canAction("local", "APPROVE")) {
3344
+ console.warn("[Request] Cannot APPROVE from current state (remote approved)");
3345
+ return;
3346
+ }
3347
+ t.dispatchApprove(), i === "undo" ? t.applyUndo(t.getPendingUndoCount() ?? 1) : i === "restart" && t.resetGame(), t.clearPendingStates(), H.debug("[session:request] remote approved", { action: i });
3348
+ return;
3349
+ }
3350
+ if (!t.canAction("local", "REJECT")) {
3351
+ console.warn("[Request] Cannot REJECT from current state (remote rejected)"), t.clearPendingStates();
3352
+ return;
3353
+ }
3354
+ t.dispatchReject(), t.clearPendingStates(), H.debug("[session:request] remote rejected", { action: i });
3355
+ }, st = (e) => e === "local" ? "remote" : "local", ct = () => {
3356
+ let e = q();
3357
+ return e.getResumeTurn() ?? (e.getState("local") === "turn" ? "local" : "remote");
3358
+ }, lt = () => {
3359
+ let e = q(), t = ct();
3360
+ return {
3361
+ history: e.getHistory(),
3362
+ lastStart: e.getLastStart(),
3363
+ turn: t,
3364
+ resumeTurn: e.getResumeTurn()
3365
+ };
3366
+ }, ut = () => {
3367
+ let e = q();
3368
+ return e.getState("local") === "syncing" || e.getState("remote") === "syncing" || e.getState("remote") === "offline" || e.getResumeTurn() !== null;
3369
+ }, dt = () => {
3370
+ let e = q();
3371
+ if (e.getState("local") !== "syncing") {
3372
+ if (!e.canAction("local", "SYNC")) return H.debug("[session:sync] local cannot enter sync", { local: e.getState("local") }), !1;
3373
+ e.dispatch("local", "SYNC", "syncing");
3374
+ }
3375
+ if (e.getState("remote") === "offline") {
3376
+ if (!e.canAction("remote", "ONLINE")) return H.debug("[session:sync] offline remote cannot enter sync", { remote: e.getState("remote") }), !1;
3377
+ e.dispatch("remote", "ONLINE", "syncing");
3378
+ } else if (e.getState("remote") !== "syncing") {
3379
+ if (!e.canAction("remote", "SYNC")) return H.debug("[session:sync] remote cannot enter sync", { remote: e.getState("remote") }), !1;
3380
+ e.dispatch("remote", "SYNC", "syncing");
3381
+ }
3382
+ return e.getState("local") === "syncing" && e.getState("remote") === "syncing";
3383
+ }, X = (e, t) => {
3384
+ let n = q(), r = t ? st : (e) => e;
3385
+ e.history && e.history.length > 0 ? n.replaceHistory(e.history.map((e) => ({
3386
+ ...e,
3387
+ player: r(e.player)
3388
+ }))) : n.clearHistory(), e.lastStart ? n.setLastStart(r(e.lastStart)) : n.setLastStart(null);
3389
+ let i = e.resumeTurn ? r(e.resumeTurn) : e.turn ? r(e.turn) : ct();
3390
+ H.debug("[session:sync] state restored", {
3391
+ historyLength: n.getHistory().length,
3392
+ lastStart: n.getLastStart(),
3393
+ nextTurnPlayer: i,
3394
+ mapped: t
3395
+ }), dt() && n.dispatchSyncComplete(i);
3396
+ }, ft = (e) => {
3397
+ let t = q();
3398
+ if (H.debug("[session:sync] received", {
3399
+ type: e.type,
3400
+ from: e.from,
3401
+ payload: e.payload,
3402
+ local: t.getState("local"),
3403
+ remote: t.getState("remote"),
3404
+ history: t.getHistory().length,
3405
+ resumeTurn: t.getResumeTurn()
3406
+ }), e.type === "SYNC_REQUEST") {
3407
+ if (e.from === "local") {
3408
+ if (t.getState("local") !== "syncing" && !t.canAction("local", "SYNC")) {
3409
+ console.warn("[Sync] Cannot SYNC from current state");
3410
+ return;
3411
+ }
3412
+ t.getState("local") !== "syncing" && t.dispatch("local", "SYNC", "syncing"), t.getState("remote") !== "syncing" && t.dispatch("remote", "SYNC", "syncing"), Y({
3413
+ type: "SYNC_REQUEST",
3414
+ from: "",
3415
+ payload: e.payload
3416
+ }), H.debug("[session:sync] request sent");
3417
+ return;
3418
+ }
3419
+ let n = lt();
3420
+ Y({
3421
+ type: "SYNC_STATE",
3422
+ from: "",
3423
+ payload: n
3424
+ }), H.debug("[session:sync] state sent", n), ut() && X(n, !1);
3425
+ return;
3426
+ }
3427
+ if (e.type === "SYNC_STATE") {
3428
+ if (e.from === "local") {
3429
+ let e = lt();
3430
+ Y({
3431
+ type: "SYNC_STATE",
3432
+ from: "",
3433
+ payload: e
3434
+ }), H.debug("[session:sync] state pushed", e), ut() && X(e, !1);
3435
+ return;
3436
+ }
3437
+ X(e.payload || {}, !0);
3438
+ }
3439
+ }, pt = (e) => {
3440
+ if (e.type !== "UNDO") return;
3441
+ let t = q(), n = J();
3442
+ if (H.debug("[session:undo] received", {
3443
+ from: e.from,
3444
+ local: t.getState("local"),
3445
+ remote: t.getState("remote"),
3446
+ pending: t.getPendingAction(),
3447
+ history: t.getHistory().length
3448
+ }), e.from === "local") {
3449
+ if (t.hasPendingAction()) return;
3450
+ if (!t.canAction("local", "UNDO")) {
3451
+ console.warn("[Undo] Cannot UNDO from current state");
3452
+ return;
3453
+ }
3454
+ let e = t.getState("local"), n = e === "turn" ? 2 : 1, r = e === "turn" ? "local" : "remote";
3455
+ if (t.getHistory().length < n) {
3456
+ console.warn("[Undo] Not enough history to undo", { count: n });
3457
+ return;
3458
+ }
3459
+ t.initializeUndoRequest(n, r), t.dispatch("local", "UNDO"), t.dispatch("remote", "REMOTE_UNDO"), Y({
3460
+ type: "UNDO",
3461
+ payload: { count: n }
3462
+ }), H.debug("[session:undo] local requested", { undoCount: n });
3463
+ return;
3464
+ }
3465
+ if (t.hasPendingAction()) {
3466
+ n.emit("REJECT", {
3467
+ action: "undo",
3468
+ reason: "busy"
3469
+ }, "local");
3470
+ return;
3471
+ }
3472
+ if (!t.canAction("local", "REMOTE_UNDO")) {
3473
+ console.warn("[Undo] Cannot accept remote UNDO request"), n.emit("REJECT", {
3474
+ action: "undo",
3475
+ reason: "invalid_state"
3476
+ }, "local");
3477
+ return;
3478
+ }
3479
+ let r = e.payload, i = r?.count === 2 ? 2 : 1;
3480
+ if (r?.count && r.count !== 1 && r.count !== 2) {
3481
+ n.emit("REJECT", {
3482
+ action: "undo",
3483
+ reason: "invalid"
3484
+ }, "local");
3485
+ return;
3486
+ }
3487
+ if (t.getHistory().length < i) {
3488
+ n.emit("REJECT", {
3489
+ action: "undo",
3490
+ reason: "no_history"
3491
+ }, "local");
3492
+ return;
3493
+ }
3494
+ let a = t.getState("local") === "turn" ? "local" : "remote";
3495
+ t.initializeUndoRequest(i, a), t.dispatch("local", "REMOTE_UNDO"), t.dispatch("remote", "UNDO"), H.debug("[session:undo] remote requested", {
3496
+ count: i,
3497
+ resumePlayer: a
3498
+ });
3499
+ }, mt = (e) => {
3500
+ if (e.type !== "RESTART") return;
3501
+ let t = q(), n = J();
3502
+ if (H.debug("[session:restart] received", {
3503
+ from: e.from,
3504
+ local: t.getState("local"),
3505
+ remote: t.getState("remote"),
3506
+ pending: t.getPendingAction(),
3507
+ history: t.getHistory().length
3508
+ }), e.from === "local") {
3509
+ if (t.hasPendingAction()) return;
3510
+ if (!t.canAction("local", "RESTART")) {
3511
+ console.warn("[Restart] Cannot RESTART from current state");
3512
+ return;
3513
+ }
3514
+ let e = t.getState("local") === "turn" ? "local" : "remote";
3515
+ t.initializeRestartRequest(e), t.dispatch("local", "RESTART"), t.dispatch("remote", "REMOTE_RESTART"), Y({ type: "RESTART" }), H.debug("[session:restart] local requested", { resumePlayer: e });
3516
+ return;
3517
+ }
3518
+ if (t.hasPendingAction()) {
3519
+ n.emit("REJECT", {
3520
+ action: "restart",
3521
+ reason: "busy"
3522
+ }, "local");
3523
+ return;
3524
+ }
3525
+ if (!t.canAction("local", "REMOTE_RESTART")) {
3526
+ console.warn("[Restart] Cannot accept remote RESTART request"), n.emit("REJECT", {
3527
+ action: "restart",
3528
+ reason: "invalid_state"
3529
+ }, "local");
3530
+ return;
3531
+ }
3532
+ let r = t.getState("local") === "turn" ? "local" : "remote";
3533
+ t.initializeRestartRequest(r), t.dispatch("local", "REMOTE_RESTART"), t.dispatch("remote", "RESTART"), H.debug("[session:restart] remote requested", { resumePlayer: r });
3534
+ }, Z = (e) => {
3535
+ if (e.type !== "OFFLINE" && e.type !== "ONLINE") return;
3536
+ let t = q(), n = J();
3537
+ if (H.debug("[session:connection] received", {
3538
+ type: e.type,
3539
+ from: e.from,
3540
+ local: t.getState("local"),
3541
+ remote: t.getState("remote"),
3542
+ pending: t.getPendingAction(),
3543
+ resumeTurn: t.getResumeTurn()
3544
+ }), e.type === "OFFLINE") {
3545
+ if (t.hasPendingAction()) {
3546
+ let e = t.getResumeTurn();
3547
+ t.canAction("local", "SYNC") && t.dispatch("local", "SYNC", "syncing"), t.clearPendingStates(), t.setResumeTurn(e);
3548
+ }
3549
+ if (!t.canAction("remote", "OFFLINE")) {
3550
+ console.warn("[Offline] Cannot transition to OFFLINE from current state");
3551
+ return;
3552
+ }
3553
+ let e = t.getResumeTurn() ?? (t.getState("local") === "turn" ? "local" : "remote");
3554
+ t.setResumeTurn(e), t.dispatch("remote", "OFFLINE", "offline"), H.debug("[session:connection] remote offline", { currentTurn: e });
3555
+ return;
3556
+ }
3557
+ if (t.getState("remote") !== "offline") {
3558
+ H.debug("[session:connection] ignored online while remote is not offline", { remote: t.getState("remote") });
3559
+ return;
3560
+ }
3561
+ if (!t.canAction("remote", "ONLINE")) {
3562
+ console.warn("[Offline] Cannot transition to ONLINE from current state");
3563
+ return;
3564
+ }
3565
+ t.dispatch("remote", "ONLINE", "syncing"), n.emit("SYNC_STATE", void 0, "local"), H.debug("[session:connection] remote online, sync state pushed");
3566
+ }, ht = (e) => {
3567
+ e.register("READY", tt), e.register("START", rt), e.register("MOVE", it), e.register("UNDO", pt), e.register("RESTART", mt), e.register("SYNC_REQUEST", ft), e.register("SYNC_STATE", ft), e.register("OFFLINE", Z), e.register("ONLINE", Z), e.register("APPROVE", ot), e.register("REJECT", ot);
3568
+ }, gt = class {
3569
+ constructor(e) {
3570
+ this.bus = e;
3571
+ }
3572
+ ready() {
3573
+ this.bus.emit("READY");
3574
+ }
3575
+ start() {
3576
+ this.bus.emit("START");
3577
+ }
3578
+ move(e) {
3579
+ this.bus.emit("MOVE", e);
3580
+ }
3581
+ undo() {
3582
+ this.bus.emit("UNDO");
3583
+ }
3584
+ restart() {
3585
+ this.bus.emit("RESTART");
3586
+ }
3587
+ approve() {
3588
+ this.bus.emit("APPROVE");
3589
+ }
3590
+ reject() {
3591
+ this.bus.emit("REJECT");
3592
+ }
3593
+ rejoin(e) {
3594
+ this.bus.emit("REJOIN", { sid: e });
3595
+ }
3596
+ }, _t = (e, t) => {
3597
+ let n = new Ve(), r = new Ye(null, null), i = new Ke(), a = Ze(e, n, null), o = new Je(r, i, () => a.getIsConnected());
3598
+ r.subscribeStateObserver(o), $e(r, n, a, t), ht(n);
3599
+ let s = new gt(n);
3600
+ return a.onConnectionChange((e) => {
3601
+ i.notifyConnectionChange(e), i.notifyStateChange(qe(r, e));
3602
+ }), {
3603
+ bus: n,
3604
+ state: r,
3605
+ observer: i,
3606
+ net: a,
3607
+ actions: s,
3608
+ send: a.send.bind(a)
3609
+ };
3610
+ }, vt = "wss://signal.jiahengli.xyz", yt = (e) => ({
3611
+ screen: "lobby",
3612
+ gameTitle: e?.gameTitle || "P2P Lockstep",
3613
+ sessionId: e?.sessionId || "default-session",
3614
+ signalUrl: e?.signalUrl || "wss://signal.jiahengli.xyz",
3615
+ targetId: "",
3616
+ peerId: "",
3617
+ remotePeerId: "",
3618
+ connectionState: "idle",
3619
+ connected: !1,
3620
+ registering: !1,
3621
+ connecting: !1,
3622
+ readySelf: !1,
3623
+ readyPeer: !1,
3624
+ canReady: !1,
3625
+ canStart: !1,
3626
+ canUndo: !1,
3627
+ canRestart: !1,
3628
+ started: !1,
3629
+ currentTurn: 1,
3630
+ turnOwner: null,
3631
+ localState: "idle",
3632
+ remoteState: "idle",
3633
+ pendingAction: null,
3634
+ historyLength: 0,
3635
+ lastStart: null,
3636
+ lastError: ""
3637
+ }), Q = {
3638
+ open: !1,
3639
+ title: "",
3640
+ description: "",
3641
+ confirmLabel: "Approve",
3642
+ cancelLabel: "Reject"
3643
+ }, bt = {
3644
+ open: !1,
3645
+ message: ""
3646
+ }, xt = [
3647
+ "turn",
3648
+ "remote_turn",
3649
+ "approving",
3650
+ "waiting_approval",
3651
+ "syncing"
3652
+ ], St = class extends HTMLElement {
3653
+ static get observedAttributes() {
3654
+ return [
3655
+ "game-title",
3656
+ "session-id",
3657
+ "signal-url"
3658
+ ];
3659
+ }
3660
+ #e = !1;
3661
+ #t = yt();
3662
+ #n = Q;
3663
+ #r = bt;
3664
+ #i = null;
3665
+ #a = null;
3666
+ #o = null;
3667
+ #s = null;
3668
+ #c = new Re();
3669
+ #l = null;
3670
+ #u = null;
3671
+ #d = null;
3672
+ #f = null;
3673
+ connectedCallback() {
3674
+ this.#e || (this.#e = !0, this.#t = yt({
3675
+ gameTitle: this.getAttribute("game-title") ?? void 0,
3676
+ sessionId: this.getAttribute("session-id") ?? void 0,
3677
+ signalUrl: this.getAttribute("signal-url") ?? void 0
3678
+ }), this.render(), this.addEventListener("lockstep-register", this.#C), this.addEventListener("lockstep-connect", this.#w), this.addEventListener("lockstep-signal-change", this.#T), this.addEventListener("lockstep-target-change", this.#E), this.addEventListener("lockstep-share-detected", this.#D), this.addEventListener("lockstep-copy-share", this.#O), this.addEventListener("lockstep-ready", this.#k), this.addEventListener("lockstep-start", this.#A), this.addEventListener("lockstep-undo", this.#j), this.addEventListener("lockstep-restart", this.#M), this.addEventListener("lockstep-dialog-confirm", this.#N), this.addEventListener("lockstep-dialog-cancel", this.#P), this.#p(), this.#m());
3679
+ }
3680
+ disconnectedCallback() {
3681
+ this.removeEventListener("lockstep-register", this.#C), this.removeEventListener("lockstep-connect", this.#w), this.removeEventListener("lockstep-signal-change", this.#T), this.removeEventListener("lockstep-target-change", this.#E), this.removeEventListener("lockstep-share-detected", this.#D), this.removeEventListener("lockstep-copy-share", this.#O), this.removeEventListener("lockstep-ready", this.#k), this.removeEventListener("lockstep-start", this.#A), this.removeEventListener("lockstep-undo", this.#j), this.removeEventListener("lockstep-restart", this.#M), this.removeEventListener("lockstep-dialog-confirm", this.#N), this.removeEventListener("lockstep-dialog-cancel", this.#P), this.#d &&= (window.clearTimeout(this.#d), null), this.#c.disconnect();
3682
+ }
3683
+ attributeChangedCallback(e, t, n) {
3684
+ this.#e && (e === "game-title" && n && this.#y({ gameTitle: n }), e === "session-id" && n && this.#y({ sessionId: n }), e === "signal-url" && n && this.#y({ signalUrl: n }));
3685
+ }
3686
+ getRuntime() {
3687
+ return this.#u;
3688
+ }
3689
+ getBoardHost() {
3690
+ return this.#a?.getBoardHost() ?? null;
3691
+ }
3692
+ render() {
3693
+ this.className = "block min-h-svh bg-[var(--lock-bg-deep)] text-[var(--lock-paper)]", this.innerHTML = `
3694
+ <div class="relative min-h-svh overflow-hidden bg-[radial-gradient(circle_at_18%_8%,rgba(255,255,255,0.85),transparent_28%),linear-gradient(145deg,var(--lock-bg),var(--lock-bg-deep))]">
3695
+ <div class="pointer-events-none absolute inset-0 hidden opacity-[0.45] sm:block bg-[linear-gradient(rgba(28,28,26,0.035)_1px,transparent_1px),linear-gradient(90deg,rgba(28,28,26,0.03)_1px,transparent_1px)] bg-[size:3.25rem_3.25rem]"></div>
3696
+
3697
+ <main class="relative mx-auto flex min-h-svh max-w-7xl flex-col px-3 py-3 sm:px-6 sm:py-6 lg:px-8 lg:py-8">
3698
+ <header class="lock-enter mb-5 hidden flex-wrap items-center justify-between gap-4 rounded-[1.25rem] border border-[var(--lock-border)] bg-[rgba(255,255,252,0.72)] px-4 py-3 shadow-sm backdrop-blur-xl sm:flex">
3699
+ <div class="flex items-center gap-3">
3700
+ <div>
3701
+ <p class="text-sm font-semibold text-[var(--lock-paper)]">P2P Lockstep</p>
3702
+ <p class="text-xs text-[var(--lock-muted)]">private match console</p>
3703
+ </div>
3704
+ </div>
3705
+ <div data-shell-connection-state class="rounded-full border border-[var(--lock-border)] bg-[rgba(255,255,252,0.78)] px-3 py-1 text-xs uppercase tracking-[0.16em] text-[var(--lock-muted)]">
3706
+ ${this.#t.connectionState}
3707
+ </div>
3708
+ </header>
3709
+
3710
+ <div class="flex-1 lock-enter">
3711
+ <p2p-lockstep-lobby-page ${this.#t.screen === "lobby" ? "" : "hidden"}></p2p-lockstep-lobby-page>
3712
+ <p2p-lockstep-game-page ${this.#t.screen === "game" ? "" : "hidden"}></p2p-lockstep-game-page>
3713
+ </div>
3714
+ </main>
3715
+
3716
+ <p2p-lockstep-confirm-dialog></p2p-lockstep-confirm-dialog>
3717
+ <p2p-lockstep-toast-message></p2p-lockstep-toast-message>
3718
+ </div>
3719
+ `, this.#i = this.querySelector("p2p-lockstep-lobby-page"), this.#a = this.querySelector("p2p-lockstep-game-page"), this.#o = this.querySelector("p2p-lockstep-confirm-dialog"), this.#s = this.querySelector("p2p-lockstep-toast-message"), this.#b();
3720
+ }
3721
+ #p() {
3722
+ this.#l = _t(this.#c, this.#t.sessionId), this.#u = {
3723
+ setGamePlugin: (e) => this.#l?.state.setGamePlugin(e),
3724
+ actions: { move: (e) => this.#l?.actions.move(e) },
3725
+ observer: {
3726
+ subscribe: (e) => this.#l?.observer.subscribe({
3727
+ onStateChange: e.onStateChange,
3728
+ onConnectionChange: e.onConnectionChange,
3729
+ onError: e.onError,
3730
+ onGameEvent: e.onGameEvent ?? (() => {})
3731
+ }) ?? (() => {}),
3732
+ getSnapshot: () => this.#l?.observer.getSnapshot() ?? null
3733
+ }
3734
+ }, this.#f = {
3735
+ onStateChange: (e) => this.#_(e),
3736
+ onConnectionChange: (e) => this.#v(e),
3737
+ onGameEvent: () => {},
3738
+ onError: (e) => {
3739
+ this.#y({
3740
+ lastError: e.message,
3741
+ connectionState: "error"
3742
+ }), this.#x(e.message);
3743
+ }
3744
+ }, this.#l.observer.subscribe(this.#f), this.#y({
3745
+ localState: "idle",
3746
+ remoteState: "idle",
3747
+ currentTurn: 1
3748
+ });
3749
+ }
3750
+ async #m() {
3751
+ let e = Ce();
3752
+ e.signalUrl && this.#y({ signalUrl: e.signalUrl }), e.peerId && this.#y({ targetId: e.peerId }), this.#t.signalUrl && (await this.#h(this.#t.signalUrl, !0), e.peerId && await this.#g(e.peerId, !0));
3753
+ }
3754
+ async #h(e, t = !1) {
3755
+ let n = e.trim();
3756
+ if (n) {
3757
+ this.#y({
3758
+ signalUrl: n,
3759
+ registering: !0,
3760
+ connectionState: "registering",
3761
+ lastError: ""
3762
+ });
3763
+ try {
3764
+ let { peerId: e } = await this.#c.register(n);
3765
+ this.#l?.net.setPeerIds({
3766
+ local: e,
3767
+ remote: this.#t.remotePeerId || null
3768
+ }), this.#y({
3769
+ peerId: e,
3770
+ registering: !1,
3771
+ connectionState: "registered"
3772
+ }), t || this.#x("Peer registered. You can share the link now.");
3773
+ } catch (e) {
3774
+ this.#y({
3775
+ registering: !1,
3776
+ connectionState: "error",
3777
+ lastError: e instanceof Error ? e.message : "Failed to register signaling session."
3778
+ }), this.#x(this.#t.lastError || "Failed to register signaling session.");
3779
+ }
3780
+ }
3781
+ }
3782
+ async #g(e, t = !1) {
3783
+ let n = e.trim();
3784
+ if (n) {
3785
+ !this.#t.peerId && this.#t.signalUrl && await this.#h(this.#t.signalUrl, !0), this.#y({
3786
+ targetId: n,
3787
+ remotePeerId: n,
3788
+ connecting: !0,
3789
+ connectionState: "connecting",
3790
+ screen: "game"
3791
+ }), this.#l?.net.setPeerIds({
3792
+ local: this.#t.peerId || null,
3793
+ remote: n
3794
+ });
3795
+ try {
3796
+ await this.#c.connect(n), this.#y({ connecting: !1 }), t || this.#x("Connection request sent.");
3797
+ } catch (e) {
3798
+ this.#y({
3799
+ connecting: !1,
3800
+ connectionState: "error",
3801
+ lastError: e instanceof Error ? e.message : "Failed to start peer connection."
3802
+ }), this.#x(this.#t.lastError || "Failed to start peer connection.");
3803
+ }
3804
+ }
3805
+ }
3806
+ #_(e) {
3807
+ let t = e.connected, n = e.localState === "ready", r = e.remoteState === "ready", i = t && e.localState === "idle", a = t && e.localState === "could_start", o = t && (e.localState === "turn" || e.localState === "remote_turn") && !e.pendingAction && e.history.length > 0, s = t && (e.localState === "turn" || e.localState === "remote_turn") && !e.pendingAction, c = xt.includes(e.localState) || e.localState === "offline" && e.lastStart !== null, l = e.localState === "turn" ? "me" : e.localState === "remote_turn" ? "peer" : null;
3808
+ this.#y({
3809
+ readySelf: n,
3810
+ readyPeer: r,
3811
+ connected: t,
3812
+ connectionState: t ? "connected" : this.#t.connectionState,
3813
+ canReady: i,
3814
+ canStart: a,
3815
+ canUndo: o,
3816
+ canRestart: s,
3817
+ screen: t ? "game" : this.#t.screen,
3818
+ started: c,
3819
+ currentTurn: e.turn,
3820
+ turnOwner: l,
3821
+ localState: e.localState,
3822
+ remoteState: e.remoteState,
3823
+ pendingAction: e.pendingAction,
3824
+ historyLength: e.history.length,
3825
+ lastStart: e.lastStart
3826
+ }), e.localState === "approving" && e.pendingAction ? this.#n = {
3827
+ open: !0,
3828
+ title: e.pendingAction === "undo" ? "Undo request pending" : "Restart request pending",
3829
+ description: e.pendingAction === "undo" ? "Your peer wants to roll the match back. Approve the undo or reject it and keep the current board." : "Your peer wants to restart the match. Approve to reset the board shell or reject to continue.",
3830
+ confirmLabel: "Approve",
3831
+ cancelLabel: "Reject"
3832
+ } : this.#n.open && (this.#n = Q), this.#b();
3833
+ }
3834
+ #v(e) {
3835
+ let t = this.#t.screen === "game", n = this.#c.peerState(), r = this.#c.getRemotePeerId() ?? this.#t.remotePeerId, i = this.#c.getLocalPeerId() ?? this.#t.peerId, a = e || n === "requesting" || t, o = n === "connected" ? "connected" : n === "requesting" ? "connecting" : t ? "offline" : i ? "registered" : "idle";
3836
+ this.#y({
3837
+ peerId: i,
3838
+ remotePeerId: r,
3839
+ connected: e,
3840
+ connecting: n === "requesting",
3841
+ connectionState: o,
3842
+ screen: a ? "game" : "lobby"
3843
+ }), e ? this.#x("Peer connected. Game page is live.") : n === "requesting" && !t ? this.#x("Peer connection request received.") : t && i && this.#x("Peer disconnected. Waiting for reconnect.");
3844
+ }
3845
+ #y(e) {
3846
+ this.#t = {
3847
+ ...this.#t,
3848
+ ...e
3849
+ }, this.#e && this.#b();
3850
+ }
3851
+ #b() {
3852
+ let e = this.#i, t = this.#a, n = this.#o, r = this.#s;
3853
+ if (!e || !t || !n || !r) return;
3854
+ e.toggleAttribute("hidden", this.#t.screen !== "lobby"), t.toggleAttribute("hidden", this.#t.screen !== "game");
3855
+ let i = this.querySelector("[data-shell-connection-state]");
3856
+ i && (i.textContent = this.#t.connectionState), e.state = {
3857
+ gameTitle: this.#t.gameTitle,
3858
+ signalUrl: this.#t.signalUrl,
3859
+ targetId: this.#t.targetId,
3860
+ peerId: this.#t.peerId,
3861
+ remotePeerId: this.#t.remotePeerId,
3862
+ connectionState: this.#t.connectionState,
3863
+ registering: this.#t.registering,
3864
+ connecting: this.#t.connecting
3865
+ }, t.state = {
3866
+ gameTitle: this.#t.gameTitle,
3867
+ peerId: this.#t.peerId,
3868
+ remotePeerId: this.#t.remotePeerId,
3869
+ connected: this.#t.connected,
3870
+ connectionState: this.#t.connectionState,
3871
+ readySelf: this.#t.readySelf,
3872
+ readyPeer: this.#t.readyPeer,
3873
+ canReady: this.#t.canReady,
3874
+ canStart: this.#t.canStart,
3875
+ canUndo: this.#t.canUndo,
3876
+ canRestart: this.#t.canRestart,
3877
+ started: this.#t.started,
3878
+ currentTurn: this.#t.currentTurn,
3879
+ turnOwner: this.#t.turnOwner,
3880
+ localState: this.#t.localState,
3881
+ remoteState: this.#t.remoteState,
3882
+ pendingAction: this.#t.pendingAction,
3883
+ sessionId: this.#t.sessionId
3884
+ }, n.state = this.#n, r.state = this.#r;
3885
+ }
3886
+ #x(e) {
3887
+ e && (this.#d && window.clearTimeout(this.#d), this.#r = {
3888
+ open: !0,
3889
+ message: e
3890
+ }, this.#b(), this.#d = window.setTimeout(() => {
3891
+ this.#r = bt, this.#b(), this.#d = null;
3892
+ }, 2200));
3893
+ }
3894
+ async #S(e) {
3895
+ if (e) {
3896
+ try {
3897
+ if (navigator.clipboard?.writeText) {
3898
+ await navigator.clipboard.writeText(e), this.#x("Share link copied.");
3899
+ return;
3900
+ }
3901
+ } catch {}
3902
+ window.prompt("Copy share link", e);
3903
+ }
3904
+ }
3905
+ #C = (e) => {
3906
+ this.#h(e.detail.signalUrl);
3907
+ };
3908
+ #w = (e) => {
3909
+ this.#g(e.detail.targetId);
3910
+ };
3911
+ #T = (e) => {
3912
+ this.#y({ signalUrl: e.detail.signalUrl });
3913
+ };
3914
+ #E = (e) => {
3915
+ this.#y({ targetId: e.detail.targetId });
3916
+ };
3917
+ #D = (e) => {
3918
+ this.#y({
3919
+ targetId: e.detail.peerId,
3920
+ signalUrl: e.detail.signalUrl || this.#t.signalUrl
3921
+ });
3922
+ };
3923
+ #O = (e) => {
3924
+ this.#S(e.detail.value);
3925
+ };
3926
+ #k = () => {
3927
+ this.#l?.actions.ready(), this.#x(this.#t.readySelf ? "Ready state cleared." : "Ready state sent.");
3928
+ };
3929
+ #A = () => {
3930
+ this.#l?.actions.start(), this.#x("Start request sent.");
3931
+ };
3932
+ #j = () => {
3933
+ this.#l?.actions.undo(), this.#x("Undo request sent.");
3934
+ };
3935
+ #M = () => {
3936
+ this.#l?.actions.restart(), this.#x("Restart request sent.");
3937
+ };
3938
+ #N = () => {
3939
+ this.#l?.actions.approve(), this.#n = Q, this.#b(), this.#x("Request approved.");
3940
+ };
3941
+ #P = () => {
3942
+ this.#l?.actions.reject(), this.#n = Q, this.#b(), this.#x("Request rejected.");
3943
+ };
3944
+ }, $ = (e, t) => {
3945
+ customElements.get(e) || customElements.define(e, t);
3946
+ }, Ct = () => {
3947
+ $("p2p-lockstep-share-panel", k), $("p2p-lockstep-status-panel", M), $("p2p-lockstep-action-bar", d), $("p2p-lockstep-confirm-dialog", g), $("p2p-lockstep-toast-message", N), $("p2p-lockstep-board-host", P), $("p2p-lockstep-lobby-page", I), $("p2p-lockstep-game-page", L), $("p2p-lockstep-app", St);
3948
+ };
3949
+ Ct();
3950
+ //#endregion
3951
+ export { vt as DEFAULT_SIGNAL_URL, d as P2PLockstepActionBarElement, St as P2PLockstepAppElement, P as P2PLockstepBoardHostElement, g as P2PLockstepConfirmDialogElement, L as P2PLockstepGamePageElement, I as P2PLockstepLobbyPageElement, k as P2PLockstepSharePanelElement, M as P2PLockstepStatusPanelElement, N as P2PLockstepToastMessageElement, Ct as defineP2PLockstepUi };
3952
+
3953
+ //# sourceMappingURL=index.js.map