p2p-lockstep-kit-ui 0.1.4 → 0.1.5

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 CHANGED
@@ -1,5 +1,5 @@
1
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) => {
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), e = null), t.exports), s = (e, i, o, s) => {
3
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
4
  get: ((e) => i[e]).bind(null, d),
5
5
  enumerable: !(s = n(i, d)) || s.enumerable
@@ -21,6 +21,10 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
21
21
  canStart: !1,
22
22
  canUndo: !1,
23
23
  canRestart: !1,
24
+ canOfferDraw: !1,
25
+ canResign: !1,
26
+ allowDraw: !1,
27
+ allowResign: !1,
24
28
  started: !1,
25
29
  connectionState: "idle"
26
30
  }, d = class extends HTMLElement {
@@ -39,22 +43,22 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
39
43
  return this.#e;
40
44
  }
41
45
  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";
46
+ let { canReady: e, canStart: t, canUndo: n, canRestart: r, canOfferDraw: i, canResign: a, allowDraw: o, allowResign: s, connected: c, readySelf: l, started: u } = this.#e, d = t ? "start" : l || e ? "ready" : "", f = t ? "Start" : l ? "Unready" : e ? "Ready" : c ? "Waiting" : "Waiting for connection", p = !u || !!d, m = u ? "In game" : t ? "Start ready" : l ? "Ready" : "Setup";
43
47
  this.className = "block", this.innerHTML = `
44
48
  <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
49
  <div class="flex flex-col gap-2 sm:gap-3">
46
50
  <div class="hidden items-center justify-between gap-3 px-1 lg:flex">
47
51
  <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>
52
+ <span class="rounded-full border border-[var(--lock-border)] px-2.5 py-1 text-[0.65rem] text-[var(--lock-muted)]">${m}</span>
49
53
  </div>
50
54
 
51
- ${l ? `<button
55
+ ${p ? `<button
52
56
  type="button"
53
- data-action="${s}"
57
+ data-action="${d}"
54
58
  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"}
59
+ ${d ? "" : "disabled"}
56
60
  >
57
- ${c}
61
+ ${f}
58
62
  </button>` : ""}
59
63
 
60
64
  <div class="grid grid-cols-2 gap-2 sm:gap-3">
@@ -74,6 +78,22 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
74
78
  >
75
79
  Restart
76
80
  </button>
81
+ ${o ? `<button
82
+ type="button"
83
+ data-action="draw"
84
+ 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"
85
+ ${i ? "" : "disabled"}
86
+ >
87
+ Offer draw
88
+ </button>` : ""}
89
+ ${s ? `<button
90
+ type="button"
91
+ data-action="resign"
92
+ class="lock-disabled inline-flex items-center justify-center rounded-full border border-[var(--lock-border)] bg-[var(--lock-error-bg)] px-3 py-2.5 text-xs font-semibold text-[var(--lock-rose)] transition hover:border-[var(--lock-border-strong)] sm:px-4 sm:py-3 sm:text-sm"
93
+ ${a ? "" : "disabled"}
94
+ >
95
+ Resign
96
+ </button>` : ""}
77
97
  </div>
78
98
  </div>
79
99
  </section>
@@ -691,7 +711,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
691
711
  }
692
712
  };
693
713
  })), T = /* @__PURE__ */ o(((e) => {
694
- var t = new Uint8Array(512), n = new Uint8Array(256);
714
+ var t = /* @__PURE__ */ new Uint8Array(512), n = /* @__PURE__ */ new Uint8Array(256);
695
715
  (function() {
696
716
  let e = 1;
697
717
  for (let r = 0; r < 255; r++) t[r] = e, n[e] = r, e <<= 1, e & 256 && (e ^= 285);
@@ -704,7 +724,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
704
724
  }, e.mul = function(e, r) {
705
725
  return e === 0 || r === 0 ? 0 : t[n[e] + n[r]];
706
726
  };
707
- })), te = /* @__PURE__ */ o(((e) => {
727
+ })), E = /* @__PURE__ */ o(((e) => {
708
728
  var t = T();
709
729
  e.mul = function(e, n) {
710
730
  let r = new Uint8Array(e.length + n.length - 1);
@@ -725,8 +745,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
725
745
  for (let i = 0; i < n; i++) r = e.mul(r, new Uint8Array([1, t.exp(i)]));
726
746
  return r;
727
747
  };
728
- })), ne = /* @__PURE__ */ o(((e, t) => {
729
- var n = te();
748
+ })), te = /* @__PURE__ */ o(((e, t) => {
749
+ var n = E();
730
750
  function r(e) {
731
751
  this.genPoly = void 0, this.degree = e, this.degree && this.initialize(this.degree);
732
752
  }
@@ -743,16 +763,16 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
743
763
  }
744
764
  return r;
745
765
  }, t.exports = r;
746
- })), E = /* @__PURE__ */ o(((e) => {
766
+ })), D = /* @__PURE__ */ o(((e) => {
747
767
  e.isValid = function(e) {
748
768
  return !isNaN(e) && e >= 1 && e <= 40;
749
769
  };
750
- })), D = /* @__PURE__ */ o(((e) => {
770
+ })), O = /* @__PURE__ */ o(((e) => {
751
771
  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
772
  r = r.replace(/u/g, "\\u");
753
773
  var i = "(?:(?![A-Z0-9 $%*+\\-./:]|" + r + ")(?:.|[\r\n]))+";
754
774
  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 $%*+\\-./:]+$");
775
+ var a = RegExp("^" + r + "$"), o = /* @__PURE__ */ RegExp("^[0-9]+$"), s = /* @__PURE__ */ RegExp("^[A-Z0-9 $%*+\\-./:]+$");
756
776
  e.testKanji = function(e) {
757
777
  return a.test(e);
758
778
  }, e.testNumeric = function(e) {
@@ -760,8 +780,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
760
780
  }, e.testAlphanumeric = function(e) {
761
781
  return s.test(e);
762
782
  };
763
- })), O = /* @__PURE__ */ o(((e) => {
764
- var t = E(), n = D();
783
+ })), k = /* @__PURE__ */ o(((e) => {
784
+ var t = D(), n = O();
765
785
  e.NUMERIC = {
766
786
  id: "Numeric",
767
787
  bit: 1,
@@ -824,8 +844,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
824
844
  return n;
825
845
  }
826
846
  };
827
- })), re = /* @__PURE__ */ o(((e) => {
828
- var t = v(), n = w(), r = y(), i = O(), a = E(), o = 7973, s = t.getBCHDigit(o);
847
+ })), ne = /* @__PURE__ */ o(((e) => {
848
+ var t = v(), n = w(), r = y(), i = k(), a = D(), o = 7973, s = t.getBCHDigit(o);
829
849
  function c(t, n, r) {
830
850
  for (let i = 1; i <= 40; i++) if (n <= e.getCapacity(i, r, t)) return i;
831
851
  }
@@ -871,15 +891,15 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
871
891
  for (; t.getBCHDigit(n) - s >= 0;) n ^= o << t.getBCHDigit(n) - s;
872
892
  return e << 12 | n;
873
893
  };
874
- })), ie = /* @__PURE__ */ o(((e) => {
894
+ })), re = /* @__PURE__ */ o(((e) => {
875
895
  var t = v(), n = 1335, r = 21522, i = t.getBCHDigit(n);
876
896
  e.getEncodedBits = function(e, a) {
877
897
  let o = e.bit << 3 | a, s = o << 10;
878
898
  for (; t.getBCHDigit(s) - i >= 0;) s ^= n << t.getBCHDigit(s) - i;
879
899
  return (o << 10 | s) ^ r;
880
900
  };
881
- })), ae = /* @__PURE__ */ o(((e, t) => {
882
- var n = O();
901
+ })), A = /* @__PURE__ */ o(((e, t) => {
902
+ var n = k();
883
903
  function r(e) {
884
904
  this.mode = n.NUMERIC, this.data = e.toString();
885
905
  }
@@ -895,8 +915,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
895
915
  let i = this.data.length - t;
896
916
  i > 0 && (n = this.data.substr(t), r = parseInt(n, 10), e.put(r, i * 3 + 1));
897
917
  }, t.exports = r;
898
- })), oe = /* @__PURE__ */ o(((e, t) => {
899
- var n = O(), r = /* @__PURE__ */ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".split("");
918
+ })), ie = /* @__PURE__ */ o(((e, t) => {
919
+ var n = k(), r = /* @__PURE__ */ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".split("");
900
920
  function i(e) {
901
921
  this.mode = n.ALPHANUMERIC, this.data = e;
902
922
  }
@@ -914,8 +934,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
914
934
  }
915
935
  this.data.length % 2 && e.put(r.indexOf(this.data[t]), 6);
916
936
  }, t.exports = i;
917
- })), se = /* @__PURE__ */ o(((e, t) => {
918
- var n = O();
937
+ })), ae = /* @__PURE__ */ o(((e, t) => {
938
+ var n = k();
919
939
  function r(e) {
920
940
  this.mode = n.BYTE, typeof e == "string" ? this.data = new TextEncoder().encode(e) : this.data = new Uint8Array(e);
921
941
  }
@@ -928,8 +948,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
928
948
  }, r.prototype.write = function(e) {
929
949
  for (let t = 0, n = this.data.length; t < n; t++) e.put(this.data[t], 8);
930
950
  }, t.exports = r;
931
- })), ce = /* @__PURE__ */ o(((e, t) => {
932
- var n = O(), r = v();
951
+ })), oe = /* @__PURE__ */ o(((e, t) => {
952
+ var n = k(), r = v();
933
953
  function i(e) {
934
954
  this.mode = n.KANJI, this.data = e;
935
955
  }
@@ -949,7 +969,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
949
969
  n = (n >>> 8 & 255) * 192 + (n & 255), e.put(n, 13);
950
970
  }
951
971
  }, t.exports = i;
952
- })), le = /* @__PURE__ */ o(((e, t) => {
972
+ })), se = /* @__PURE__ */ o(((e, t) => {
953
973
  var n = {
954
974
  single_source_shortest_paths: function(e, t, r) {
955
975
  var i = {}, a = {};
@@ -1002,8 +1022,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1002
1022
  }
1003
1023
  };
1004
1024
  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();
1025
+ })), ce = /* @__PURE__ */ o(((e) => {
1026
+ var t = k(), n = A(), r = ie(), i = ae(), a = oe(), o = O(), s = v(), c = se();
1007
1027
  function l(e) {
1008
1028
  return unescape(encodeURIComponent(e)).length;
1009
1029
  }
@@ -1130,8 +1150,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1130
1150
  }, e.rawSplit = function(t) {
1131
1151
  return e.fromArray(d(t, s.isKanjiModeEnabled()));
1132
1152
  };
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();
1153
+ })), le = /* @__PURE__ */ o(((e) => {
1154
+ var t = v(), n = y(), r = b(), i = x(), a = S(), o = C(), s = ee(), c = w(), l = te(), u = ne(), d = re(), f = k(), p = ce();
1135
1155
  function m(e, t) {
1136
1156
  let n = e.size, r = o.getPositions(t);
1137
1157
  for (let t = 0; t < r.length; t++) {
@@ -1162,7 +1182,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1162
1182
  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
1183
  e.set(r - 8, 8, 1, !0);
1164
1184
  }
1165
- function te(e, t) {
1185
+ function E(e, t) {
1166
1186
  let n = e.size, r = -1, i = n - 1, a = 7, o = 0;
1167
1187
  for (let s = n - 1; s > 0; s -= 2) for (s === 6 && s--;;) {
1168
1188
  for (let n = 0; n < 2; n++) if (!e.isReserved(i, s - n)) {
@@ -1175,7 +1195,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1175
1195
  }
1176
1196
  }
1177
1197
  }
1178
- function E(e, n, i) {
1198
+ function D(e, n, i) {
1179
1199
  let a = new r();
1180
1200
  i.forEach(function(t) {
1181
1201
  a.put(t.mode.bit, 4), a.put(t.getLength(), f.getCharCountIndicator(t.mode, e)), t.write(a);
@@ -1184,9 +1204,9 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1184
1204
  for (a.getLengthInBits() + 4 <= o && a.put(0, 4); a.getLengthInBits() % 8 != 0;) a.putBit(0);
1185
1205
  let s = (o - a.getLengthInBits()) / 8;
1186
1206
  for (let e = 0; e < s; e++) a.put(e % 2 ? 17 : 236, 8);
1187
- return D(a, e, n);
1207
+ return O(a, e, n);
1188
1208
  }
1189
- function D(e, n, r) {
1209
+ function O(e, n, r) {
1190
1210
  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
1211
  for (let e = 0; e < o; e++) {
1192
1212
  let t = e < s ? d : f;
@@ -1197,7 +1217,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1197
1217
  for (S = 0; S < p; S++) for (C = 0; C < o; C++) b[x++] = _[C][S];
1198
1218
  return b;
1199
1219
  }
1200
- function ae(e, n, r, a) {
1220
+ function A(e, n, r, a) {
1201
1221
  let o;
1202
1222
  if (Array.isArray(e)) o = p.fromArray(e);
1203
1223
  else if (typeof e == "string") {
@@ -1212,8 +1232,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1212
1232
  if (!c) throw Error("The amount of data is too big to be stored in a QR Code");
1213
1233
  if (!n) n = c;
1214
1234
  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), {
1235
+ let l = D(n, r, o), d = new i(t.getSymbolSize(n));
1236
+ return m(d, n), h(d), g(d, n), T(d, r, 0), n >= 7 && _(d, n), E(d, l), isNaN(a) && (a = s.getBestMask(d, T.bind(null, d, r))), s.applyMask(a, d), T(d, r, a), {
1217
1237
  modules: d,
1218
1238
  version: n,
1219
1239
  errorCorrectionLevel: r,
@@ -1224,9 +1244,9 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1224
1244
  e.create = function(e, r) {
1225
1245
  if (e === void 0 || e === "") throw Error("No input text");
1226
1246
  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);
1247
+ 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)), A(e, a, i, o);
1228
1248
  };
1229
- })), fe = /* @__PURE__ */ o(((e) => {
1249
+ })), j = /* @__PURE__ */ o(((e) => {
1230
1250
  function t(e) {
1231
1251
  if (typeof e == "number" && (e = e.toString()), typeof e != "string") throw Error("Color should be defined as hex string");
1232
1252
  let t = e.slice().replace("#", "").split("");
@@ -1273,8 +1293,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1273
1293
  t[u++] = d.r, t[u++] = d.g, t[u++] = d.b, t[u] = d.a;
1274
1294
  }
1275
1295
  };
1276
- })), pe = /* @__PURE__ */ o(((e) => {
1277
- var t = fe();
1296
+ })), ue = /* @__PURE__ */ o(((e) => {
1297
+ var t = j();
1278
1298
  function n(e, t, n) {
1279
1299
  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
1300
  }
@@ -1296,8 +1316,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1296
1316
  let a = e.render(t, n, i), o = i.type || "image/png", s = i.rendererOpts || {};
1297
1317
  return a.toDataURL(o, s.quality);
1298
1318
  };
1299
- })), me = /* @__PURE__ */ o(((e) => {
1300
- var t = fe();
1319
+ })), de = /* @__PURE__ */ o(((e) => {
1320
+ var t = j();
1301
1321
  function n(e, t) {
1302
1322
  let n = e.a / 255, r = t + "=\"" + e.hex + "\"";
1303
1323
  return n < 1 ? r + " " + t + "-opacity=\"" + n.toFixed(2).slice(1) + "\"" : r;
@@ -1318,8 +1338,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1318
1338
  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
1339
  return typeof a == "function" && a(null, p), p;
1320
1340
  };
1321
- })), he = /* @__PURE__ */ c((/* @__PURE__ */ o(((e) => {
1322
- var t = _(), n = de(), r = pe(), i = me();
1341
+ })), fe = /* @__PURE__ */ c((/* @__PURE__ */ o(((e) => {
1342
+ var t = _(), n = le(), r = ue(), i = de();
1323
1343
  function a(e, r, i, a, o) {
1324
1344
  let s = [].slice.call(arguments, 1), c = s.length, l = typeof s[c - 1] == "function";
1325
1345
  if (!l && !t()) throw Error("Callback required as last argument");
@@ -1346,12 +1366,12 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1346
1366
  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
1367
  return i.render(e, n);
1348
1368
  });
1349
- })))(), 1), ge = {
1369
+ })))(), 1), pe = {
1350
1370
  peerId: "",
1351
1371
  signalUrl: "",
1352
1372
  shareUrl: ""
1353
- }, k = class extends HTMLElement {
1354
- #e = ge;
1373
+ }, M = class extends HTMLElement {
1374
+ #e = pe;
1355
1375
  #t = !1;
1356
1376
  connectedCallback() {
1357
1377
  this.#t || (this.#t = !0, this.addEventListener("click", this.#n), this.render());
@@ -1398,7 +1418,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1398
1418
  return;
1399
1419
  }
1400
1420
  try {
1401
- await he.toCanvas(t, e, {
1421
+ await fe.toCanvas(t, e, {
1402
1422
  width: 208,
1403
1423
  margin: 1,
1404
1424
  color: {
@@ -1413,7 +1433,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1413
1433
  #n = (e) => {
1414
1434
  e.target?.closest("[data-action='copy-share']") && l(this, "lockstep-copy-share", { value: this.#e.shareUrl });
1415
1435
  };
1416
- }, _e = {
1436
+ }, me = {
1417
1437
  theme: "light",
1418
1438
  gameTitle: "P2P Lockstep",
1419
1439
  peerId: "",
@@ -1427,14 +1447,20 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1427
1447
  readySelf: !1,
1428
1448
  readyPeer: !1,
1429
1449
  pendingAction: null,
1450
+ outcome: null,
1430
1451
  sessionId: "default-session",
1431
1452
  historyLength: 0,
1432
1453
  lastStart: null,
1433
1454
  lastError: ""
1434
- }, A = (e) => e === "me" ? "Your turn" : e === "peer" ? "Peer turn" : "Waiting", j = (e, t) => t === "ready" ? `${e} ready` : t === "could_start" ? e === "Me" ? "You can start" : "Peer can start" : `${e} idle`, ve = (e, t) => {
1455
+ }, N = (e) => e === "me" ? "Your turn" : e === "peer" ? "Peer turn" : "Waiting", he = (e) => {
1456
+ if (!e) return null;
1457
+ if (e.kind === "draw") return e.reason === "agreement" ? "Draw by agreement" : "Draw by mutual resignation";
1458
+ let t = e.winner === "local" ? "You win" : "Peer wins";
1459
+ return e.reason === "resignation" ? `${t} by resignation` : t;
1460
+ }, P = (e, t) => t === "ready" ? `${e} ready` : t === "could_start" ? e === "Me" ? "You can start" : "Peer can start" : `${e} idle`, ge = (e, t) => {
1435
1461
  let n = e === "Local" ? "You" : "Peer";
1436
1462
  return t === "idle" ? `${n} idle` : t === "ready" ? `${n} ready` : t === "could_start" ? `${n} can start` : `${n} ${t.replaceAll("_", " ")}`;
1437
- }, ye = (e, t) => e || t === "connected" ? {
1463
+ }, _e = (e, t) => e || t === "connected" ? {
1438
1464
  label: "Live",
1439
1465
  detail: "connected",
1440
1466
  tone: "bg-[var(--lock-teal)]"
@@ -1462,8 +1488,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1462
1488
  label: "Standby",
1463
1489
  detail: "not registered",
1464
1490
  tone: "bg-[var(--lock-dim)]"
1465
- }, be = class extends HTMLElement {
1466
- #e = _e;
1491
+ }, ve = class extends HTMLElement {
1492
+ #e = me;
1467
1493
  #t = !1;
1468
1494
  connectedCallback() {
1469
1495
  this.#t || (this.#t = !0, this.addEventListener("click", this.#n), this.render());
@@ -1478,14 +1504,14 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1478
1504
  return this.#e;
1479
1505
  }
1480
1506
  render() {
1481
- let { connected: e, pendingAction: t } = this.#e, n = ye(e, this.#e.connectionState), r = j("Me", this.#e.localState), i = j("Peer", this.#e.remoteState), a = ve("Local", this.#e.localState), o = ve("Remote", this.#e.remoteState), s = `${r} / ${i}`, c = this.#e.lastStart === "local" ? "You" : this.#e.lastStart === "remote" ? "Peer" : "Not started", l = `${this.#e.historyLength} move${this.#e.historyLength === 1 ? "" : "s"} / ${c}`;
1507
+ let { connected: e, pendingAction: t } = this.#e, n = he(this.#e.outcome), r = _e(e, this.#e.connectionState), i = P("Me", this.#e.localState), a = P("Peer", this.#e.remoteState), o = ge("Local", this.#e.localState), s = ge("Remote", this.#e.remoteState), c = `${i} / ${a}`, l = this.#e.lastStart === "local" ? "You" : this.#e.lastStart === "remote" ? "Peer" : "Not started", u = n ?? `${this.#e.historyLength} move${this.#e.historyLength === 1 ? "" : "s"} / ${l}`;
1482
1508
  this.className = "block", this.innerHTML = `
1483
1509
  <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">
1484
1510
  <div class="flex items-center gap-2 lg:hidden">
1485
1511
  <div class="min-w-0 flex-1">
1486
1512
  <p data-mobile-title class="truncate text-sm font-semibold leading-tight text-[var(--lock-paper)]"></p>
1487
1513
  <div class="mt-1 flex min-w-0 items-center gap-1.5 text-[0.68rem] leading-none text-[var(--lock-muted)]">
1488
- <span class="h-2 w-2 shrink-0 rounded-full ${n.tone}"></span>
1514
+ <span class="h-2 w-2 shrink-0 rounded-full ${r.tone}"></span>
1489
1515
  <span data-mobile-connection class="shrink-0 font-medium"></span>
1490
1516
  <span class="text-[var(--lock-dim)]">/</span>
1491
1517
  <span data-mobile-turn class="min-w-0 truncate"></span>
@@ -1542,6 +1568,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1542
1568
  <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>
1543
1569
  <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>
1544
1570
  ${t ? `<span class="rounded-full border border-[var(--lock-border-strong)] bg-[var(--lock-pending-bg)] px-2.5 py-1 text-[0.68rem] text-[var(--lock-bronze-bright)]">Pending ${t}</span>` : ""}
1571
+ ${n ? `<span class="rounded-full border border-[var(--lock-border-strong)] bg-[var(--lock-pending-bg)] px-2.5 py-1 text-[0.68rem] text-[var(--lock-bronze-bright)]">${n}</span>` : ""}
1545
1572
  </div>
1546
1573
  </div>
1547
1574
  </details>
@@ -1556,7 +1583,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1556
1583
  <p data-match-meta class="mt-1.5 text-xs text-[var(--lock-muted)]"></p>
1557
1584
  </div>
1558
1585
  <div class="flex shrink-0 items-center gap-2">
1559
- <span class="h-2.5 w-2.5 rounded-full ${n.tone}"></span>
1586
+ <span class="h-2.5 w-2.5 rounded-full ${r.tone}"></span>
1560
1587
  <details class="group relative">
1561
1588
  <summary aria-label="Appearance settings" class="lock-control flex h-7 w-7 cursor-pointer list-none items-center justify-center rounded-full border border-[var(--lock-border)] text-xs font-semibold leading-none text-[var(--lock-muted)] [&::-webkit-details-marker]:hidden">...</summary>
1562
1589
  <div class="lock-surface-strong absolute right-0 z-50 mt-2 w-52 rounded-2xl border border-[var(--lock-border-strong)] p-3 shadow-xl shadow-black/15">
@@ -1574,7 +1601,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1574
1601
  <div class="grid grid-cols-2 gap-2">
1575
1602
  <article class="lock-card rounded-[1rem] border border-[var(--lock-border)] p-2.5">
1576
1603
  <p class="text-[0.58rem] uppercase tracking-[0.2em] text-[var(--lock-dim)]">Connection</p>
1577
- <p class="mt-1.5 text-sm font-semibold text-[var(--lock-paper)]">${n.label}</p>
1604
+ <p class="mt-1.5 text-sm font-semibold text-[var(--lock-paper)]">${r.label}</p>
1578
1605
  <p data-connection-state class="mt-0.5 truncate text-xs text-[var(--lock-muted)]"></p>
1579
1606
  </article>
1580
1607
 
@@ -1613,21 +1640,22 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1613
1640
  <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>
1614
1641
  <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>
1615
1642
  ${t ? `<span class="rounded-full border border-[var(--lock-border-strong)] bg-[var(--lock-pending-bg)] px-2 py-0.5 text-[0.64rem] text-[var(--lock-bronze-bright)]">Pending ${t}</span>` : ""}
1643
+ ${n ? `<span class="rounded-full border border-[var(--lock-border-strong)] bg-[var(--lock-pending-bg)] px-2 py-0.5 text-[0.64rem] text-[var(--lock-bronze-bright)]">${n}</span>` : ""}
1616
1644
  </div>
1617
1645
  </article>
1618
1646
  </div>
1619
1647
  </section>
1620
- `, 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-timeline]", l), p(this, "[data-detail-error]", this.#e.lastError), 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-match-meta]", l), p(this, "[data-error-message]", this.#e.lastError), 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);
1648
+ `, p(this, "[data-mobile-title]", this.#e.gameTitle), p(this, "[data-mobile-connection]", r.label), p(this, "[data-mobile-turn]", n ?? `#${this.#e.currentTurn} ${N(this.#e.turnOwner)}`), p(this, "[data-mobile-ready]", c), p(this, "[data-detail-connection]", r.label), p(this, "[data-detail-turn]", `#${this.#e.currentTurn} / ${N(this.#e.turnOwner)}`), p(this, "[data-detail-session]", this.#e.sessionId), p(this, "[data-detail-timeline]", u), p(this, "[data-detail-error]", this.#e.lastError), 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]", i), p(this, "[data-detail-ready-peer]", a), p(this, "[data-detail-local-state]", o), p(this, "[data-detail-remote-state]", s), p(this, "[data-title]", this.#e.gameTitle), p(this, "[data-match-meta]", u), p(this, "[data-error-message]", this.#e.lastError), p(this, "[data-connection-state]", r.detail), p(this, "[data-current-turn]", n ?? `#${this.#e.currentTurn}`), p(this, "[data-turn-owner]", n ? "Game over" : N(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]", i), p(this, "[data-ready-peer]", a), p(this, "[data-local-state]", o), p(this, "[data-remote-state]", s);
1621
1649
  }
1622
1650
  #n = (e) => {
1623
1651
  let t = e.target?.closest("button[data-theme-mode]");
1624
1652
  (t?.dataset.themeMode === "light" || t?.dataset.themeMode === "dark") && l(this, "lockstep-theme-change", { theme: t.dataset.themeMode });
1625
1653
  };
1626
- }, xe = {
1654
+ }, ye = {
1627
1655
  open: !1,
1628
1656
  message: ""
1629
- }, Se = class extends HTMLElement {
1630
- #e = xe;
1657
+ }, be = class extends HTMLElement {
1658
+ #e = ye;
1631
1659
  #t = !1;
1632
1660
  connectedCallback() {
1633
1661
  this.#t || (this.#t = !0, this.render());
@@ -1648,7 +1676,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1648
1676
  </div>
1649
1677
  `, p(this, "[data-message]", this.#e.message);
1650
1678
  }
1651
- }, Ce = class extends HTMLElement {
1679
+ }, xe = class extends HTMLElement {
1652
1680
  #e = !1;
1653
1681
  #t = null;
1654
1682
  #n = null;
@@ -1671,18 +1699,18 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1671
1699
  render() {
1672
1700
  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]");
1673
1701
  }
1674
- }, M = (e) => {
1702
+ }, Se = (e) => {
1675
1703
  let t = e.hash.replace(/^#/, "");
1676
1704
  return new URLSearchParams(t || e.search);
1677
- }, we = (e, t, n) => {
1705
+ }, Ce = (e, t, n) => {
1678
1706
  if (!e) return "";
1679
1707
  let r = new URL(n ?? window.location.href), i = new URLSearchParams();
1680
1708
  return i.set("id", e), t && i.set("url", t), r.hash = i.toString(), r.toString();
1681
- }, Te = (e) => {
1709
+ }, we = (e) => {
1682
1710
  let t = e.trim();
1683
1711
  if (!t || !t.includes("://")) return null;
1684
1712
  try {
1685
- let e = M(new URL(t)), n = e.get("id");
1713
+ let e = Se(new URL(t)), n = e.get("id");
1686
1714
  return n ? {
1687
1715
  peerId: n,
1688
1716
  signalUrl: e.get("url") ?? ""
@@ -1690,8 +1718,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1690
1718
  } catch {
1691
1719
  return null;
1692
1720
  }
1693
- }, N = () => {
1694
- let e = M(new URL(window.location.href));
1721
+ }, Te = () => {
1722
+ let e = Se(new URL(window.location.href));
1695
1723
  return {
1696
1724
  peerId: e.get("id") ?? "",
1697
1725
  signalUrl: e.get("url") ?? ""
@@ -1706,7 +1734,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1706
1734
  connectionState: "idle",
1707
1735
  registering: !1,
1708
1736
  connecting: !1
1709
- }, P = class extends HTMLElement {
1737
+ }, F = class extends HTMLElement {
1710
1738
  #e = Ee;
1711
1739
  #t = !1;
1712
1740
  #n = !1;
@@ -1742,7 +1770,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1742
1770
  i && (i.state = {
1743
1771
  peerId: this.#e.peerId,
1744
1772
  signalUrl: this.#e.signalUrl,
1745
- shareUrl: we(this.#e.peerId, this.#e.signalUrl)
1773
+ shareUrl: Ce(this.#e.peerId, this.#e.signalUrl)
1746
1774
  });
1747
1775
  }
1748
1776
  #i = (e) => {
@@ -1757,7 +1785,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1757
1785
  return;
1758
1786
  }
1759
1787
  if (t.dataset.field === "target-id") {
1760
- let e = Te(t.value);
1788
+ let e = we(t.value);
1761
1789
  if (e) {
1762
1790
  l(this, "lockstep-share-detected", e);
1763
1791
  return;
@@ -1779,17 +1807,22 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1779
1807
  canStart: !1,
1780
1808
  canUndo: !1,
1781
1809
  canRestart: !1,
1810
+ canOfferDraw: !1,
1811
+ canResign: !1,
1812
+ allowDraw: !1,
1813
+ allowResign: !1,
1782
1814
  started: !1,
1783
1815
  currentTurn: 1,
1784
1816
  turnOwner: null,
1785
1817
  localState: "idle",
1786
1818
  remoteState: "idle",
1787
1819
  pendingAction: null,
1820
+ outcome: null,
1788
1821
  sessionId: "default-session",
1789
1822
  historyLength: 0,
1790
1823
  lastStart: null,
1791
1824
  lastError: ""
1792
- }, F = class extends HTMLElement {
1825
+ }, I = class extends HTMLElement {
1793
1826
  #e = De;
1794
1827
  #t = !1;
1795
1828
  #n = null;
@@ -1825,6 +1858,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1825
1858
  readySelf: this.#e.readySelf,
1826
1859
  readyPeer: this.#e.readyPeer,
1827
1860
  pendingAction: this.#e.pendingAction,
1861
+ outcome: this.#e.outcome,
1828
1862
  sessionId: this.#e.sessionId,
1829
1863
  historyLength: this.#e.historyLength,
1830
1864
  lastStart: this.#e.lastStart,
@@ -1836,11 +1870,15 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1836
1870
  canStart: this.#e.canStart,
1837
1871
  canUndo: this.#e.canUndo,
1838
1872
  canRestart: this.#e.canRestart,
1873
+ canOfferDraw: this.#e.canOfferDraw,
1874
+ canResign: this.#e.canResign,
1875
+ allowDraw: this.#e.allowDraw,
1876
+ allowResign: this.#e.allowResign,
1839
1877
  started: this.#e.started,
1840
1878
  connectionState: this.#e.connectionState
1841
1879
  });
1842
1880
  }
1843
- }, I = (e) => JSON.stringify(e), Oe = (e) => {
1881
+ }, L = (e) => JSON.stringify(e), Oe = (e) => {
1844
1882
  if (typeof e != "string") throw TypeError("decode expects a serialized string");
1845
1883
  return JSON.parse(e);
1846
1884
  }, ke = (e) => {
@@ -1859,7 +1897,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1859
1897
  error: e
1860
1898
  };
1861
1899
  }
1862
- }, L = (e, t) => {
1900
+ }, R = (e, t) => {
1863
1901
  t === void 0 ? console.log(e) : console.log(e, t);
1864
1902
  let n = globalThis.__p2p_debug;
1865
1903
  if (typeof n == "function") try {
@@ -1870,36 +1908,36 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1870
1908
  }, Ae = class {
1871
1909
  constructor() {
1872
1910
  this.ws = null, this.peerId = null, this.ready = !1, this.signalHandlers = /* @__PURE__ */ new Set(), this.pendingRegistration = null, this.connect = (e) => new Promise((t, n) => {
1873
- this.ws?.close(), L("[signaling] ws connect", e), this.ws = new WebSocket(e);
1911
+ this.ws?.close(), R("[signaling] ws connect", e), this.ws = new WebSocket(e);
1874
1912
  let r = window.setTimeout(() => {
1875
1913
  try {
1876
1914
  this.ws?.close();
1877
1915
  } catch {}
1878
- L("[signaling] ws open timeout"), n(/* @__PURE__ */ Error("ws open timeout"));
1916
+ R("[signaling] ws open timeout"), n(/* @__PURE__ */ Error("ws open timeout"));
1879
1917
  }, 5e3);
1880
1918
  this.ws.addEventListener("open", () => {
1881
- this.ready = !0, this.registeredPayload = void 0, window.clearTimeout(r), L("[signaling] ws open"), t();
1919
+ this.ready = !0, this.registeredPayload = void 0, window.clearTimeout(r), R("[signaling] ws open"), t();
1882
1920
  }), this.ws.addEventListener("error", (e) => {
1883
- window.clearTimeout(r), L("[signaling] ws error", e), n(/* @__PURE__ */ Error("ws error"));
1921
+ window.clearTimeout(r), R("[signaling] ws error", e), n(/* @__PURE__ */ Error("ws error"));
1884
1922
  }), this.ws.addEventListener("close", (e) => {
1885
- this.ready = !1, this.peerId = null, this.registeredPayload = void 0, this.rejectPendingRegistration(/* @__PURE__ */ Error("ws closed")), window.clearTimeout(r), L("[signaling] ws close", {
1923
+ this.ready = !1, this.peerId = null, this.registeredPayload = void 0, this.rejectPendingRegistration(/* @__PURE__ */ Error("ws closed")), window.clearTimeout(r), R("[signaling] ws close", {
1886
1924
  code: e.code,
1887
1925
  reason: e.reason
1888
1926
  });
1889
1927
  }), this.ws.addEventListener("message", (e) => {
1890
1928
  let t = String(e.data), n = ke(t);
1891
1929
  if (!n.ok) {
1892
- L("[signaling] ws message decode error", t), this.rejectPendingRegistration(/* @__PURE__ */ Error("signaling decode error"));
1930
+ R("[signaling] ws message decode error", t), this.rejectPendingRegistration(/* @__PURE__ */ Error("signaling decode error"));
1893
1931
  return;
1894
1932
  }
1895
1933
  let r = n.value;
1896
- if (L("[signaling] ws message", r), r.type === "ERROR") {
1897
- L("[signaling] error", r), this.rejectPendingRegistration(/* @__PURE__ */ Error("signaling error"));
1934
+ if (R("[signaling] ws message", r), r.type === "ERROR") {
1935
+ R("[signaling] error", r), this.rejectPendingRegistration(/* @__PURE__ */ Error("signaling error"));
1898
1936
  return;
1899
1937
  }
1900
1938
  if ((r.type === "REGISTERED" || r.type === "RESUMED") && (this.peerId = r.to ?? null, this.registeredPayload = r.payload, this.peerId)) {
1901
1939
  let e = this.resolveRegisteredPayload();
1902
- L("[signaling] registered", {
1940
+ R("[signaling] registered", {
1903
1941
  peerId: this.peerId,
1904
1942
  resumeToken: e.resumeToken
1905
1943
  }), this.resolvePendingRegistration({
@@ -1921,14 +1959,14 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1921
1959
  }), this.register = async () => {
1922
1960
  this.assertConnected();
1923
1961
  let e = { type: "REGISTER" };
1924
- L("[signaling] send REGISTER");
1962
+ R("[signaling] send REGISTER");
1925
1963
  let t = this.awaitRegistration("register");
1926
- this.ws?.send(I(e));
1964
+ this.ws?.send(L(e));
1927
1965
  try {
1928
1966
  let e = await t;
1929
- return L("[signaling] register ok", e.peerId), e;
1967
+ return R("[signaling] register ok", e.peerId), e;
1930
1968
  } catch (e) {
1931
- throw L("[signaling] register error", e), e;
1969
+ throw R("[signaling] register error", e), e;
1932
1970
  }
1933
1971
  }, this.resume = async (e) => {
1934
1972
  this.assertConnected();
@@ -1939,14 +1977,14 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1939
1977
  data: e
1940
1978
  }
1941
1979
  };
1942
- L("[signaling] send RESUME", e.peerId);
1980
+ R("[signaling] send RESUME", e.peerId);
1943
1981
  let n = this.awaitRegistration("resume");
1944
- this.ws?.send(I(t));
1982
+ this.ws?.send(L(t));
1945
1983
  try {
1946
1984
  let e = await n;
1947
- return L("[signaling] resume ok", e.peerId), e;
1985
+ return R("[signaling] resume ok", e.peerId), e;
1948
1986
  } catch (e) {
1949
- throw L("[signaling] resume error", e), e;
1987
+ throw R("[signaling] resume error", e), e;
1950
1988
  }
1951
1989
  }, this.relay = (e) => {
1952
1990
  if (!this.ws || !this.ready) return;
@@ -1959,7 +1997,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1959
1997
  to: e.to,
1960
1998
  payload: t
1961
1999
  };
1962
- this.ws.send(I(n));
2000
+ this.ws.send(L(n));
1963
2001
  };
1964
2002
  }
1965
2003
  onSignal(e) {
@@ -1968,6 +2006,9 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1968
2006
  offSignal(e) {
1969
2007
  this.signalHandlers.delete(e);
1970
2008
  }
2009
+ close() {
2010
+ this.rejectPendingRegistration(/* @__PURE__ */ Error("signaling closed")), this.ready = !1, this.peerId = null, this.registeredPayload = void 0, this.ws?.close(), this.ws = null;
2011
+ }
1971
2012
  resolveRegisteredPayload() {
1972
2013
  let e = [], t = "";
1973
2014
  if (this.registeredPayload?.id === "iceServers" && (e = this.registeredPayload.data), this.registeredPayload?.id === "session") {
@@ -1984,12 +2025,13 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
1984
2025
  }
1985
2026
  awaitRegistration(e) {
1986
2027
  return this.pendingRegistration ? Promise.reject(/* @__PURE__ */ Error("registration already pending")) : new Promise((t, n) => {
2028
+ let r = window.setTimeout(() => {
2029
+ this.pendingRegistration = null, R(`[signaling] ${e} timeout`), n(/* @__PURE__ */ Error(`${e} timeout`));
2030
+ }, 5e3);
1987
2031
  this.pendingRegistration = {
1988
2032
  resolve: t,
1989
2033
  reject: n,
1990
- timeoutId: window.setTimeout(() => {
1991
- this.pendingRegistration = null, L(`[signaling] ${e} timeout`), n(/* @__PURE__ */ Error(`${e} timeout`));
1992
- }, 5e3)
2034
+ timeoutId: r
1993
2035
  };
1994
2036
  });
1995
2037
  }
@@ -2088,8 +2130,8 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2088
2130
  let n = Ne.find((n) => n.from === e && n.event === t);
2089
2131
  return n ? n.to : e;
2090
2132
  }, Fe = class {
2091
- constructor(e, t, n, r, i, a, o) {
2092
- 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 = () => {
2133
+ constructor(e, t, n, r, i, a, o, s = {}) {
2134
+ this.dc = null, this.pendingSends = [], this.remoteId = null, this.requestedId = null, this.state = "passive", this.signalQueue = Promise.resolve(), 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 = () => {
2093
2135
  if (this.pc.connectionState === "connected") {
2094
2136
  this.markConnectedIfReady();
2095
2137
  return;
@@ -2111,6 +2153,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2111
2153
  }, this.handleNegotiationNeeded = () => {
2112
2154
  this.canNegotiate() && this.runTask(this.negotiate(), "negotiate");
2113
2155
  }, this.connect = async (e) => {
2156
+ if (this.boundRemoteId && e !== this.boundRemoteId) throw Error(`RtcPeer is bound to ${this.boundRemoteId}`);
2114
2157
  if (this.state !== "passive") {
2115
2158
  this.requestedId = e, this.disconnect();
2116
2159
  return;
@@ -2119,14 +2162,18 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2119
2162
  }, this.disconnect = () => {
2120
2163
  this.dispatch("DISCONNECT");
2121
2164
  }, this.dispose = () => {
2122
- 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();
2165
+ this.subscribesToSignaling && 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();
2123
2166
  }, this.send = (e) => {
2124
2167
  if (!this.dc || this.dc.readyState !== "open") {
2125
2168
  this.state === "requesting" && this.pendingSends.push(e);
2126
2169
  return;
2127
2170
  }
2128
2171
  this.dc.send(e);
2129
- }, this.getPeerId = () => this.id, this.getRemoteId = () => this.remoteId, this.getPeerState = () => this.state, this.getMediaState = () => this.mediaState, this.startMedia = (e) => {
2172
+ }, this.getPeerId = () => this.id, this.getRemoteId = () => this.remoteId, this.getPeerState = () => this.state, this.getMediaState = () => this.mediaState, this.receiveSignal = (e) => {
2173
+ this.signalQueue = this.signalQueue.then(() => this.handleSignal(e)).catch((t) => {
2174
+ console.error(`[rtc-peer] signal:${e.type} failed`, t), this.dispatchMedia("DISCONNECT"), this.dispatch("DISCONNECT");
2175
+ });
2176
+ }, this.startMedia = (e) => {
2130
2177
  this.localStream = e, this.dispatchMedia("REQUEST");
2131
2178
  }, this.stopMedia = () => {
2132
2179
  this.localStream = null, this.dispatchMedia("STOP");
@@ -2191,7 +2238,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2191
2238
  this.signaling.relay(t);
2192
2239
  }, this.closeConnection = () => {
2193
2240
  let e = this.dc;
2194
- 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;
2241
+ 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 = this.boundRemoteId;
2195
2242
  }, this.detachLocalMedia = () => {
2196
2243
  if (this.senders.length) {
2197
2244
  for (let e of this.senders) try {
@@ -2237,7 +2284,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2237
2284
  }
2238
2285
  this.dispatchMedia("READY");
2239
2286
  }
2240
- }, 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 () => {
2287
+ }, this.canNegotiate = () => !!(this.remoteId && this.isMediaReady()), this.shouldHandleSignal = (e) => e.to && e.to !== this.id ? !1 : this.boundRemoteId ? e.from === this.boundRemoteId : 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 () => {
2241
2288
  if (this.remoteId) {
2242
2289
  if (this.negotiating) {
2243
2290
  this.renegotiateQueued = !0;
@@ -2258,16 +2305,16 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2258
2305
  this.negotiating = !1, this.renegotiateQueued && (this.renegotiateQueued = !1, this.runTask(this.negotiate(), "negotiate"));
2259
2306
  }
2260
2307
  }
2261
- }, 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) => {
2262
- this.runTask(this.handleSignal(e), `signal:${e.type}`);
2263
- }, 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);
2308
+ }, this.id = e, this.pc = t, this.signaling = n, this.boundRemoteId = s.remoteId ?? null, this.remoteId = this.boundRemoteId, this.subscribesToSignaling = s.subscribeToSignaling ?? !0, r && (this.onMessageHandler = r), i && (this.onRemoteStreamHandler = i), a && (this.onStateChangeHandler = a), o && (this.onMediaChangeHandler = o), this.onSignalHandler = (e) => {
2309
+ this.receiveSignal(e);
2310
+ }, this.subscribesToSignaling && 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);
2264
2311
  }
2265
2312
  runTask(e, t) {
2266
2313
  e.catch((e) => {
2267
2314
  console.error(`[rtc-peer] ${t} failed`, e), this.dispatchMedia("DISCONNECT"), this.dispatch("DISCONNECT");
2268
2315
  });
2269
2316
  }
2270
- }, R = "p2p-lockstep-kit:signal-session", Ie = () => {
2317
+ }, z = "p2p-lockstep-kit:signal-session", Ie = () => {
2271
2318
  if (typeof window > "u") return null;
2272
2319
  try {
2273
2320
  return window.localStorage;
@@ -2277,7 +2324,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2277
2324
  }, Le = () => {
2278
2325
  let e = Ie();
2279
2326
  if (!e) return null;
2280
- let t = e.getItem(R);
2327
+ let t = e.getItem(z);
2281
2328
  if (!t) return null;
2282
2329
  try {
2283
2330
  let e = JSON.parse(t);
@@ -2285,18 +2332,18 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2285
2332
  } catch {
2286
2333
  return null;
2287
2334
  }
2288
- }, z = (e) => {
2335
+ }, Re = (e) => {
2289
2336
  let t = Ie();
2290
2337
  if (t) {
2291
2338
  if (!e) {
2292
- t.removeItem(R);
2339
+ t.removeItem(z);
2293
2340
  return;
2294
2341
  }
2295
- t.setItem(R, JSON.stringify(e));
2342
+ t.setItem(z, JSON.stringify(e));
2296
2343
  }
2297
- }, Re = () => {
2298
- z(null);
2299
- }, ze = class {
2344
+ }, ze = () => {
2345
+ Re(null);
2346
+ }, Be = class {
2300
2347
  constructor(e = new Ae()) {
2301
2348
  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;
2302
2349
  }
@@ -2309,9 +2356,9 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2309
2356
  resumeToken: t.resumeToken
2310
2357
  });
2311
2358
  } catch {
2312
- Re();
2359
+ ze();
2313
2360
  }
2314
- n ||= await this.signaling.register(), n.resumeToken && z({
2361
+ n ||= await this.signaling.register(), n.resumeToken && Re({
2315
2362
  peerId: n.peerId,
2316
2363
  resumeToken: n.resumeToken,
2317
2364
  updatedAt: Date.now()
@@ -2336,7 +2383,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2336
2383
  this.peer && await this.peer.connect(e);
2337
2384
  }
2338
2385
  send(e) {
2339
- let t = I(e);
2386
+ let t = L(e);
2340
2387
  this.peer?.send(t);
2341
2388
  }
2342
2389
  disconnect() {
@@ -2360,24 +2407,19 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2360
2407
  onMediaChange(e) {
2361
2408
  this.onMediaChangeHandler = e, e(this.peer?.getMediaState() ?? "idle");
2362
2409
  }
2363
- }, Be = Object.defineProperty, Ve = (e, t, n) => t in e ? Be(e, t, {
2364
- enumerable: !0,
2365
- configurable: !0,
2366
- writable: !0,
2367
- value: n
2368
- }) : e[t] = n, B = (e, t, n) => Ve(e, typeof t == "symbol" ? t : t + "", n), V = (e) => (t, n) => {
2410
+ }, B = (e) => (t, n) => {
2369
2411
  let r = e === "debug" ? console.info : console[e];
2370
2412
  if (n !== void 0) {
2371
2413
  r(t, n);
2372
2414
  return;
2373
2415
  }
2374
2416
  r(t);
2375
- }, H = {
2376
- debug: V("debug"),
2377
- info: V("info"),
2378
- warn: V("warn"),
2379
- error: V("error")
2380
- }, He = (e) => {
2417
+ }, V = {
2418
+ debug: B("debug"),
2419
+ info: B("info"),
2420
+ warn: B("warn"),
2421
+ error: B("error")
2422
+ }, Ve = (e) => {
2381
2423
  if (typeof e != "string") return {
2382
2424
  ok: !1,
2383
2425
  error: /* @__PURE__ */ TypeError("decodeSafe expects a serialized string")
@@ -2393,14 +2435,13 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2393
2435
  error: e
2394
2436
  };
2395
2437
  }
2396
- }, Ue = (e) => {
2438
+ }, He = (e) => {
2397
2439
  if (typeof e != "string") return !e || typeof e != "object" ? null : e;
2398
- let t = He(e);
2440
+ let t = Ve(e);
2399
2441
  return !t.ok || !t.value || typeof t.value != "object" ? null : t.value;
2400
- }, We = class {
2401
- constructor() {
2402
- B(this, "handlers", {}), B(this, "processingQueue", Promise.resolve());
2403
- }
2442
+ }, Ue = class {
2443
+ handlers = {};
2444
+ processingQueue = Promise.resolve();
2404
2445
  emit(e, t, n = "local") {
2405
2446
  this.dispatch({
2406
2447
  type: e,
@@ -2409,11 +2450,11 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2409
2450
  });
2410
2451
  }
2411
2452
  register(e, t) {
2412
- this.handlers[e] = t, H.debug(`[session:bus] registered ${e}`);
2453
+ this.handlers[e] = t, V.debug(`[session:bus] registered ${e}`);
2413
2454
  }
2414
2455
  dispatch(e) {
2415
2456
  this.processingQueue = this.processingQueue.then(async () => {
2416
- H.debug(`[session:bus] dispatch ${e.type}`, {
2457
+ V.debug(`[session:bus] dispatch ${e.type}`, {
2417
2458
  from: e.from,
2418
2459
  payload: e.payload,
2419
2460
  turn: e.turn,
@@ -2422,16 +2463,16 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2422
2463
  let t = this.handlers[e.type];
2423
2464
  if (t) {
2424
2465
  try {
2425
- await t(e), H.debug(`[session:bus] handled ${e.type}`, { from: e.from });
2466
+ await t(e), V.debug(`[session:bus] handled ${e.type}`, { from: e.from });
2426
2467
  } catch (t) {
2427
2468
  console.error(`[CommandBus] Error in ${e.type}:`, t);
2428
2469
  }
2429
2470
  return;
2430
2471
  }
2431
- H.debug(`[session:bus] no handler for ${e.type}`, { from: e.from });
2472
+ V.debug(`[session:bus] no handler for ${e.type}`, { from: e.from });
2432
2473
  });
2433
2474
  }
2434
- }, U = [
2475
+ }, H = [
2435
2476
  {
2436
2477
  from: "idle",
2437
2478
  event: "READY",
@@ -2522,6 +2563,16 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2522
2563
  event: "RESTART",
2523
2564
  to: "waiting_approval"
2524
2565
  },
2566
+ {
2567
+ from: "turn",
2568
+ event: "REQUEST",
2569
+ to: "waiting_approval"
2570
+ },
2571
+ {
2572
+ from: "remote_turn",
2573
+ event: "REQUEST",
2574
+ to: "waiting_approval"
2575
+ },
2525
2576
  {
2526
2577
  from: "turn",
2527
2578
  event: "REMOTE_UNDO",
@@ -2542,6 +2593,16 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2542
2593
  event: "REMOTE_RESTART",
2543
2594
  to: "approving"
2544
2595
  },
2596
+ {
2597
+ from: "turn",
2598
+ event: "REMOTE_REQUEST",
2599
+ to: "approving"
2600
+ },
2601
+ {
2602
+ from: "remote_turn",
2603
+ event: "REMOTE_REQUEST",
2604
+ to: "approving"
2605
+ },
2545
2606
  {
2546
2607
  from: "waiting_approval",
2547
2608
  event: "APPROVE",
@@ -2582,6 +2643,21 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2582
2643
  event: "GAME_OVER",
2583
2644
  to: "idle"
2584
2645
  },
2646
+ {
2647
+ from: "waiting_approval",
2648
+ event: "GAME_OVER",
2649
+ to: "idle"
2650
+ },
2651
+ {
2652
+ from: "approving",
2653
+ event: "GAME_OVER",
2654
+ to: "idle"
2655
+ },
2656
+ {
2657
+ from: "syncing",
2658
+ event: "GAME_OVER",
2659
+ to: "idle"
2660
+ },
2585
2661
  {
2586
2662
  from: "turn",
2587
2663
  event: "SYNC",
@@ -2672,36 +2748,35 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2672
2748
  event: "ONLINE",
2673
2749
  to: "syncing"
2674
2750
  }
2675
- ], Ge = (e, t, n) => {
2676
- if (n) return U.find((r) => r.from === e && r.event === t && r.to === n) ? n : e;
2751
+ ], We = (e, t, n) => {
2752
+ if (n) return H.find((r) => r.from === e && r.event === t && r.to === n) ? n : e;
2677
2753
  {
2678
- let n = U.find((n) => n.from === e && n.event === t);
2754
+ let n = H.find((n) => n.from === e && n.event === t);
2679
2755
  return n ? n.to : e;
2680
2756
  }
2681
- }, Ke = (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 {
2757
+ }, Ge = (e, t, n) => n ? !!H.find((r) => r.from === e && r.event === t && r.to === n) : !!H.find((n) => n.from === e && n.event === t), U = class {
2758
+ state;
2682
2759
  constructor(e = "idle") {
2683
- B(this, "state"), this.state = e;
2760
+ this.state = e;
2684
2761
  }
2685
2762
  getState() {
2686
2763
  return this.state;
2687
2764
  }
2688
2765
  hasNextState(e, t) {
2689
- return Ke(this.state, e, t);
2766
+ return Ge(this.state, e, t);
2690
2767
  }
2691
2768
  dispatch(e, t) {
2692
- this.state = Ge(this.state, e, t);
2769
+ this.state = We(this.state, e, t);
2693
2770
  }
2694
- }, qe = class {
2771
+ }, Ke = class {
2695
2772
  validateMove() {
2696
2773
  return { valid: !0 };
2697
2774
  }
2698
2775
  checkWin() {
2699
2776
  return null;
2700
2777
  }
2701
- }, Je = class {
2702
- constructor() {
2703
- B(this, "observers", /* @__PURE__ */ new Set());
2704
- }
2778
+ }, qe = class {
2779
+ observers = /* @__PURE__ */ new Set();
2705
2780
  subscribe(e) {
2706
2781
  this.observers.add(e);
2707
2782
  }
@@ -2729,10 +2804,9 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2729
2804
  console.error("[StateObserver]", e);
2730
2805
  }
2731
2806
  }
2732
- }, Ye = class {
2733
- constructor() {
2734
- B(this, "observers", /* @__PURE__ */ new Set()), B(this, "currentSnapshot", null);
2735
- }
2807
+ }, Je = class {
2808
+ observers = /* @__PURE__ */ new Set();
2809
+ currentSnapshot = null;
2736
2810
  subscribe(e) {
2737
2811
  return this.observers.add(e), () => {
2738
2812
  this.observers.delete(e);
@@ -2778,7 +2852,7 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
2778
2852
  return this.observers.size;
2779
2853
  }
2780
2854
  };
2781
- function Xe(e, t = !1) {
2855
+ function W(e, t = !1) {
2782
2856
  return {
2783
2857
  localState: e.getState("local"),
2784
2858
  remoteState: e.getState("remote"),
@@ -2786,19 +2860,25 @@ function Xe(e, t = !1) {
2786
2860
  history: e.getHistory(),
2787
2861
  lastStart: e.getLastStart(),
2788
2862
  pendingAction: e.getPendingAction(),
2863
+ outcome: e.getOutcome(),
2789
2864
  connected: t
2790
2865
  };
2791
2866
  }
2792
- var Ze = class {
2867
+ var Ye = class {
2868
+ stateRef;
2869
+ uiObserver;
2870
+ getConnected;
2871
+ lastNotificationTime = 0;
2872
+ notificationThrottleMs = 0;
2793
2873
  constructor(e, t, n = () => !1) {
2794
- B(this, "stateRef", e), B(this, "uiObserver", t), B(this, "getConnected", n), B(this, "lastNotificationTime", 0), B(this, "notificationThrottleMs", 0);
2874
+ this.stateRef = e, this.uiObserver = t, this.getConnected = n;
2795
2875
  }
2796
2876
  onStateChanged() {
2797
2877
  let e = Date.now();
2798
2878
  if (this.lastNotificationTime + this.notificationThrottleMs > e) return;
2799
2879
  this.lastNotificationTime = e;
2800
- let t = Xe(this.stateRef, this.getConnected());
2801
- H.debug("[session:observer] state snapshot", {
2880
+ let t = W(this.stateRef, this.getConnected());
2881
+ V.debug("[session:observer] state snapshot", {
2802
2882
  local: t.localState,
2803
2883
  remote: t.remoteState,
2804
2884
  turn: t.turn,
@@ -2816,9 +2896,21 @@ var Ze = class {
2816
2896
  emitEvent(e) {
2817
2897
  this.uiObserver.notifyGameEvent(e);
2818
2898
  }
2819
- }, Qe = class {
2899
+ }, Xe = class {
2900
+ local = new U("idle");
2901
+ remote = new U("idle");
2902
+ localId = null;
2903
+ remoteId = null;
2904
+ history = [];
2905
+ pendingAction = null;
2906
+ pendingUndoCount = null;
2907
+ resumeTurn = null;
2908
+ lastStart = null;
2909
+ outcome = null;
2910
+ gamePlugin = new Ke();
2911
+ stateObserverManager = new qe();
2820
2912
  constructor(e, t) {
2821
- B(this, "local", new W("idle")), B(this, "remote", new W("idle")), B(this, "localId", null), B(this, "remoteId", null), B(this, "history", []), B(this, "pendingAction", null), B(this, "pendingUndoCount", null), B(this, "resumeTurn", null), B(this, "lastStart", null), B(this, "gamePlugin", new qe()), B(this, "stateObserverManager", new Je()), B(this, "gameSnapshot", null), e && (this.localId = e), t && (this.remoteId = t), H.debug("[session:state] created", {
2913
+ e && (this.localId = e), t && (this.remoteId = t), V.debug("[session:state] created", {
2822
2914
  localId: e,
2823
2915
  remoteId: t
2824
2916
  });
@@ -2833,7 +2925,7 @@ var Ze = class {
2833
2925
  return this.remoteId;
2834
2926
  }
2835
2927
  setremoteId(e) {
2836
- this.remoteId = e, H.debug("[session:state] remote id set", { remoteId: e });
2928
+ this.remoteId = e, V.debug("[session:state] remote id set", { remoteId: e });
2837
2929
  }
2838
2930
  getState(e) {
2839
2931
  return this.getPlayerFsm(e).getState();
@@ -2845,7 +2937,7 @@ var Ze = class {
2845
2937
  return this.history.slice();
2846
2938
  }
2847
2939
  replaceHistory(e) {
2848
- H.debug("[session:history] replace", { count: e.length }), this.clearHistory(), e.forEach((e) => {
2940
+ V.debug("[session:history] replace", { count: e.length }), this.clearHistory(), e.forEach((e) => {
2849
2941
  this.pushHistory({
2850
2942
  turn: e.turn,
2851
2943
  player: e.player,
@@ -2855,10 +2947,10 @@ var Ze = class {
2855
2947
  }
2856
2948
  clearHistory() {
2857
2949
  let e = this.history.length;
2858
- this.history.splice(0, this.history.length), H.debug("[session:history] clear", { count: e }), this.notifyHistoryChanged();
2950
+ this.history.splice(0, this.history.length), V.debug("[session:history] clear", { count: e }), this.notifyHistoryChanged();
2859
2951
  }
2860
2952
  pushHistory(e) {
2861
- this.history.push(e), H.debug("[session:history] push", {
2953
+ this.history.push(e), V.debug("[session:history] push", {
2862
2954
  turn: e.turn,
2863
2955
  player: e.player,
2864
2956
  move: e.move,
@@ -2867,7 +2959,7 @@ var Ze = class {
2867
2959
  }
2868
2960
  popHistory() {
2869
2961
  let e = this.history.pop() ?? null;
2870
- return e && (H.debug("[session:history] pop", {
2962
+ return e && (V.debug("[session:history] pop", {
2871
2963
  turn: e.turn,
2872
2964
  player: e.player,
2873
2965
  move: e.move,
@@ -2881,7 +2973,7 @@ var Ze = class {
2881
2973
  let r = this.getState(e);
2882
2974
  this.getPlayerFsm(e).dispatch(t, n);
2883
2975
  let i = this.getState(e);
2884
- H.debug(`[session:fsm] ${e} ${t}`, {
2976
+ V.debug(`[session:fsm] ${e} ${t}`, {
2885
2977
  from: r,
2886
2978
  to: i,
2887
2979
  requested: n,
@@ -2893,7 +2985,7 @@ var Ze = class {
2893
2985
  }), this.notifyStateChanged();
2894
2986
  }
2895
2987
  setPendingAction(e) {
2896
- H.debug("[session:state] pending action set", {
2988
+ V.debug("[session:state] pending action set", {
2897
2989
  from: this.pendingAction,
2898
2990
  to: e
2899
2991
  }), this.pendingAction = e;
@@ -2902,7 +2994,7 @@ var Ze = class {
2902
2994
  return this.pendingAction;
2903
2995
  }
2904
2996
  setPendingUndoCount(e) {
2905
- H.debug("[session:state] pending undo count set", {
2997
+ V.debug("[session:state] pending undo count set", {
2906
2998
  from: this.pendingUndoCount,
2907
2999
  to: e
2908
3000
  }), this.pendingUndoCount = e;
@@ -2911,7 +3003,7 @@ var Ze = class {
2911
3003
  return this.pendingUndoCount;
2912
3004
  }
2913
3005
  setLastStart(e) {
2914
- H.debug("[session:state] last start set", {
3006
+ V.debug("[session:state] last start set", {
2915
3007
  from: this.lastStart,
2916
3008
  to: e
2917
3009
  }), this.lastStart = e;
@@ -2920,7 +3012,7 @@ var Ze = class {
2920
3012
  return this.lastStart;
2921
3013
  }
2922
3014
  setResumeTurn(e) {
2923
- H.debug("[session:state] resume turn set", {
3015
+ V.debug("[session:state] resume turn set", {
2924
3016
  from: this.resumeTurn,
2925
3017
  to: e
2926
3018
  }), this.resumeTurn = e;
@@ -2928,11 +3020,20 @@ var Ze = class {
2928
3020
  getResumeTurn() {
2929
3021
  return this.resumeTurn;
2930
3022
  }
3023
+ setOutcome(e) {
3024
+ V.debug("[session:state] outcome set", {
3025
+ from: this.outcome,
3026
+ to: e
3027
+ }), this.outcome = e, this.notifyStateChanged();
3028
+ }
3029
+ getOutcome() {
3030
+ return this.outcome;
3031
+ }
2931
3032
  getPlayerFsm(e) {
2932
3033
  return e === "local" ? this.local : this.remote;
2933
3034
  }
2934
3035
  notifyStateChanged() {
2935
- H.debug("[session:state] notify state changed", {
3036
+ V.debug("[session:state] notify state changed", {
2936
3037
  local: this.getState("local"),
2937
3038
  remote: this.getState("remote"),
2938
3039
  turn: this.getTurnCount(),
@@ -2941,21 +3042,21 @@ var Ze = class {
2941
3042
  }), this.stateObserverManager.notifyStateChanged();
2942
3043
  }
2943
3044
  notifyHistoryChanged() {
2944
- H.debug("[session:state] notify history changed", {
3045
+ V.debug("[session:state] notify history changed", {
2945
3046
  turn: this.getTurnCount(),
2946
3047
  history: this.history.length,
2947
3048
  pending: this.pendingAction
2948
3049
  }), this.stateObserverManager.notifyHistoryChanged();
2949
3050
  }
2950
3051
  notifyGameReset() {
2951
- H.debug("[session:state] notify game reset"), this.stateObserverManager.notifyGameReset();
3052
+ V.debug("[session:state] notify game reset"), this.stateObserverManager.notifyGameReset();
2952
3053
  }
2953
3054
  dispatchPair(e, t, n, r) {
2954
3055
  let i = {
2955
3056
  local: this.local.getState(),
2956
3057
  remote: this.remote.getState()
2957
3058
  };
2958
- this.local.dispatch(e, t), this.remote.dispatch(n, r), H.debug("[session:fsm] pair dispatch", {
3059
+ this.local.dispatch(e, t), this.remote.dispatch(n, r), V.debug("[session:fsm] pair dispatch", {
2959
3060
  before: i,
2960
3061
  after: {
2961
3062
  local: this.local.getState(),
@@ -2970,33 +3071,40 @@ var Ze = class {
2970
3071
  pending: this.pendingAction
2971
3072
  }), this.notifyStateChanged();
2972
3073
  }
3074
+ gameSnapshot = null;
2973
3075
  saveGameSnapshot(e) {
2974
- this.gameSnapshot = e, H.debug("[session:state] game snapshot saved", { snapshot: e });
3076
+ this.gameSnapshot = e, V.debug("[session:state] game snapshot saved", { snapshot: e });
2975
3077
  }
2976
3078
  getGameSnapshot() {
2977
3079
  return this.gameSnapshot;
2978
3080
  }
2979
3081
  clearGameSnapshot() {
2980
- this.gameSnapshot = null, H.debug("[session:state] game snapshot cleared");
3082
+ this.gameSnapshot = null, V.debug("[session:state] game snapshot cleared");
2981
3083
  }
2982
3084
  hasPendingAction() {
2983
3085
  return this.pendingAction !== null;
2984
3086
  }
2985
3087
  clearPendingStates() {
2986
- H.debug("[session:state] pending states cleared", {
3088
+ V.debug("[session:state] pending states cleared", {
2987
3089
  pending: this.pendingAction,
2988
3090
  pendingUndoCount: this.pendingUndoCount,
2989
3091
  resumeTurn: this.resumeTurn
2990
3092
  }), this.pendingAction = null, this.pendingUndoCount = null, this.resumeTurn = null, this.notifyStateChanged();
2991
3093
  }
2992
3094
  initializeUndoRequest(e, t) {
2993
- this.pendingAction = "undo", this.pendingUndoCount = e, this.resumeTurn = t, H.debug("[session:state] undo request initialized", {
3095
+ this.pendingAction = "undo", this.pendingUndoCount = e, this.resumeTurn = t, V.debug("[session:state] undo request initialized", {
2994
3096
  undoCount: e,
2995
3097
  resumeTurn: t
2996
3098
  });
2997
3099
  }
2998
3100
  initializeRestartRequest(e) {
2999
- this.pendingAction = "restart", this.resumeTurn = e, H.debug("[session:state] restart request initialized", { resumeTurn: e });
3101
+ this.pendingAction = "restart", this.resumeTurn = e, V.debug("[session:state] restart request initialized", { resumeTurn: e });
3102
+ }
3103
+ initializePendingRequest(e, t) {
3104
+ this.pendingAction = e, this.resumeTurn = t, V.debug("[session:state] approval request initialized", {
3105
+ action: e,
3106
+ resumeTurn: t
3107
+ });
3000
3108
  }
3001
3109
  isPendingUndo() {
3002
3110
  return this.pendingAction === "undo";
@@ -3005,20 +3113,20 @@ var Ze = class {
3005
3113
  return this.pendingAction === "restart";
3006
3114
  }
3007
3115
  applyUndo(e = 1) {
3008
- H.debug("[session:history] apply undo", { count: e });
3116
+ V.debug("[session:history] apply undo", { count: e });
3009
3117
  for (let t = 0; t < e; t++) this.popHistory();
3010
3118
  }
3011
3119
  resetGame() {
3012
- H.debug("[session:state] reset game", {
3120
+ V.debug("[session:state] reset game", {
3013
3121
  local: this.getState("local"),
3014
3122
  remote: this.getState("remote"),
3015
3123
  history: this.history.length,
3016
3124
  lastStart: this.lastStart,
3017
3125
  pending: this.pendingAction
3018
- }), 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();
3126
+ }), this.clearHistory(), this.local = new U("idle"), this.remote = new U("idle"), this.lastStart = null, this.outcome = null, this.pendingAction = null, this.pendingUndoCount = null, this.resumeTurn = null, this.notifyGameReset(), this.notifyStateChanged();
3019
3127
  }
3020
3128
  recordStartPlayer(e) {
3021
- this.lastStart = e, H.debug("[session:state] start player recorded", { player: e });
3129
+ this.lastStart = e, V.debug("[session:state] start player recorded", { player: e });
3022
3130
  }
3023
3131
  getLastMove() {
3024
3132
  return this.history.length > 0 ? this.history[this.history.length - 1] : null;
@@ -3040,7 +3148,7 @@ var Ze = class {
3040
3148
  remote: this.remote.getState(),
3041
3149
  lastStart: this.lastStart
3042
3150
  };
3043
- 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", {
3151
+ 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"), V.debug("[session:fsm] start dispatch", {
3044
3152
  before: t,
3045
3153
  firstPlayer: e,
3046
3154
  after: {
@@ -3054,7 +3162,7 @@ var Ze = class {
3054
3162
  e === "local" ? this.dispatchPair("SYNC_COMPLETE", "turn", "SYNC_COMPLETE", "remote_turn") : this.dispatchPair("SYNC_COMPLETE", "remote_turn", "SYNC_COMPLETE", "turn"), this.resumeTurn = null;
3055
3163
  }
3056
3164
  setGamePlugin(e) {
3057
- this.gamePlugin = e, H.debug("[session:plugin] game plugin set", {
3165
+ this.gamePlugin = e, V.debug("[session:plugin] game plugin set", {
3058
3166
  hasInitialize: !!e.initialize,
3059
3167
  hasCleanup: !!e.cleanup
3060
3168
  }), e.initialize && e.initialize();
@@ -3064,7 +3172,7 @@ var Ze = class {
3064
3172
  }
3065
3173
  validateMove(e) {
3066
3174
  let t = this.buildGameState(), n = this.gamePlugin.validateMove(e, t);
3067
- return H.debug("[session:plugin] validate move", {
3175
+ return V.debug("[session:plugin] validate move", {
3068
3176
  move: e,
3069
3177
  result: n,
3070
3178
  local: t.localState,
@@ -3075,14 +3183,17 @@ var Ze = class {
3075
3183
  }
3076
3184
  checkWin() {
3077
3185
  let e = this.buildGameState(), t = this.gamePlugin.checkWin(e, this.getHistory());
3078
- return H.debug("[session:plugin] check win", {
3186
+ return V.debug("[session:plugin] check win", {
3079
3187
  winner: t,
3080
3188
  turn: e.turn,
3081
3189
  history: e.history.length
3082
3190
  }), t;
3083
3191
  }
3192
+ completeGame(e) {
3193
+ this.setOutcome(e), this.canAction("local", "GAME_OVER") && this.dispatch("local", "GAME_OVER"), this.canAction("remote", "GAME_OVER") && this.dispatch("remote", "GAME_OVER"), this.clearPendingStates(), this.cleanupGame();
3194
+ }
3084
3195
  cleanupGame() {
3085
- this.gamePlugin.cleanup && this.gamePlugin.cleanup(), H.debug("[session:plugin] cleanup game");
3196
+ this.gamePlugin.cleanup && this.gamePlugin.cleanup(), V.debug("[session:plugin] cleanup game");
3086
3197
  }
3087
3198
  buildGameState() {
3088
3199
  return {
@@ -3093,10 +3204,17 @@ var Ze = class {
3093
3204
  lastStart: this.getLastStart()
3094
3205
  };
3095
3206
  }
3096
- }, $e = class {
3207
+ }, Ze = class {
3208
+ client;
3209
+ bus;
3210
+ localPeerId;
3211
+ remotePeerId;
3212
+ isConnected = !1;
3213
+ connectionChangeListener = () => {};
3214
+ mediaStateListener = () => {};
3097
3215
  constructor(e, t, n) {
3098
- B(this, "client", e), B(this, "bus", t), B(this, "localPeerId"), B(this, "remotePeerId"), B(this, "isConnected", !1), B(this, "connectionChangeListener", () => {}), B(this, "mediaStateListener", () => {}), this.localPeerId = n ?? null, this.remotePeerId = null, this.client.onMessage((e) => {
3099
- let t = Ue(e);
3216
+ this.client = e, this.bus = t, this.localPeerId = n ?? null, this.remotePeerId = null, this.client.onMessage((e) => {
3217
+ let t = He(e);
3100
3218
  !t || typeof t != "object" || !t.type || this.bus.dispatch({
3101
3219
  ...t,
3102
3220
  type: t.type,
@@ -3139,9 +3257,13 @@ var Ze = class {
3139
3257
  onMediaStateChange(e) {
3140
3258
  this.mediaStateListener = e;
3141
3259
  }
3142
- }, et = (e, t, n) => new $e(e, t, n), tt = class {
3260
+ }, Qe = (e, t, n) => new Ze(e, t, n), $e = class {
3261
+ state;
3262
+ bus;
3263
+ net;
3264
+ sid;
3143
3265
  constructor(e, t, n, r) {
3144
- B(this, "state"), B(this, "bus"), B(this, "net"), B(this, "sid"), this.state = e, this.bus = t, this.net = n, this.sid = r;
3266
+ this.state = e, this.bus = t, this.net = n, this.sid = r;
3145
3267
  }
3146
3268
  getState() {
3147
3269
  return this.state;
@@ -3155,14 +3277,14 @@ var Ze = class {
3155
3277
  getSid() {
3156
3278
  return this.sid;
3157
3279
  }
3158
- }, G = null, nt = (e, t, n, r) => {
3159
- G = new tt(e, t, n, r);
3280
+ }, G = null, et = (e, t, n, r) => {
3281
+ G = new $e(e, t, n, r);
3160
3282
  }, K = () => {
3161
3283
  if (!G) throw Error("[SessionContext] Not initialized. Call initializeContext() first.");
3162
3284
  return G;
3163
- }, q = () => K().getState(), J = () => K().getBus(), rt = () => K().getSid(), Y = (e) => K().getNet().send(e), it = (e) => {
3164
- let t = q(), n = J(), r = rt();
3165
- if (H.debug("[session:ready] received", {
3285
+ }, q = () => K().getState(), J = () => K().getBus(), tt = () => K().getSid(), Y = (e) => K().getNet().send(e), nt = (e) => {
3286
+ let t = q(), n = J(), r = tt();
3287
+ if (V.debug("[session:ready] received", {
3166
3288
  from: e.from,
3167
3289
  sid: e.sid,
3168
3290
  localSid: r,
@@ -3176,7 +3298,7 @@ var Ze = class {
3176
3298
  t.dispatch("local", "READY"), t.dispatch("remote", "REMOTE_READY"), Y({
3177
3299
  type: "READY",
3178
3300
  sid: r
3179
- }), H.debug("[session:ready] local toggled", {
3301
+ }), V.debug("[session:ready] local toggled", {
3180
3302
  local: t.getState("local"),
3181
3303
  remote: t.getState("remote")
3182
3304
  });
@@ -3194,13 +3316,13 @@ var Ze = class {
3194
3316
  console.warn("[Ready] Cannot dispatch READY for remote peer", { state: t.getState("remote") });
3195
3317
  return;
3196
3318
  }
3197
- t.dispatch("remote", "READY"), t.dispatch("local", "REMOTE_READY"), H.debug("[session:ready] remote toggled", {
3319
+ t.dispatch("remote", "READY"), t.dispatch("local", "REMOTE_READY"), V.debug("[session:ready] remote toggled", {
3198
3320
  local: t.getState("local"),
3199
3321
  remote: t.getState("remote")
3200
3322
  });
3201
- }, at = (e) => e ? e === "local" ? "remote" : "local" : Math.random() < .5 ? "local" : "remote", ot = (e) => {
3323
+ }, rt = (e) => e ? e === "local" ? "remote" : "local" : Math.random() < .5 ? "local" : "remote", it = (e) => {
3202
3324
  let t = q();
3203
- if (H.debug("[session:start] received", {
3325
+ if (V.debug("[session:start] received", {
3204
3326
  from: e.from,
3205
3327
  payload: e.payload,
3206
3328
  local: t.getState("local"),
@@ -3214,11 +3336,11 @@ var Ze = class {
3214
3336
  });
3215
3337
  return;
3216
3338
  }
3217
- let e = at(t.getLastStart()), n = e === "local" ? "turn" : "remote_turn", r = e === "local" ? "remote_turn" : "turn";
3218
- 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({
3339
+ let e = rt(t.getLastStart()), n = e === "local" ? "turn" : "remote_turn", r = e === "local" ? "remote_turn" : "turn";
3340
+ t.getHistory().length > 0 && (t.clearHistory(), V.debug("[session:start] cleared previous match history")), t.setOutcome(null), t.setLastStart(e), t.dispatch("local", "START", n), t.dispatch("remote", "REMOTE_START", r), Y({
3219
3341
  type: "START",
3220
3342
  payload: { starter: e === "local" ? "sender" : "receiver" }
3221
- }), H.debug("[session:start] local started", { nextStarter: e });
3343
+ }), V.debug("[session:start] local started", { nextStarter: e });
3222
3344
  return;
3223
3345
  }
3224
3346
  let n = e.payload?.starter;
@@ -3234,10 +3356,10 @@ var Ze = class {
3234
3356
  return;
3235
3357
  }
3236
3358
  let r = n === "sender" ? "remote" : "local", i = r === "local" ? "turn" : "remote_turn", a = r === "local" ? "remote_turn" : "turn";
3237
- 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 });
3238
- }, st = (e) => {
3359
+ t.getHistory().length > 0 && (t.clearHistory(), V.debug("[session:start] cleared previous match history")), t.setOutcome(null), t.setLastStart(r), t.dispatch("local", "REMOTE_START", i), t.dispatch("remote", "START", a), V.debug("[session:start] remote started", { starter: r });
3360
+ }, at = (e) => {
3239
3361
  let t = q(), n = e.payload;
3240
- if (H.debug("[session:move] received", {
3362
+ if (V.debug("[session:move] received", {
3241
3363
  from: e.from,
3242
3364
  payload: n,
3243
3365
  local: t.getState("local"),
@@ -3267,16 +3389,20 @@ var Ze = class {
3267
3389
  type: "MOVE",
3268
3390
  turn: r,
3269
3391
  payload: n
3270
- }), H.debug("[session:move] local move sent", {
3392
+ }), V.debug("[session:move] local move sent", {
3271
3393
  turn: r,
3272
3394
  payload: n
3273
3395
  });
3274
3396
  let i = t.checkWin();
3275
3397
  if (i) {
3276
- H.debug("[session:move] game over detected", {
3398
+ V.debug("[session:move] game over detected", {
3277
3399
  winner: i,
3278
3400
  turn: r
3279
- }), t.dispatch("local", "GAME_OVER"), t.dispatch("remote", "GAME_OVER"), t.cleanupGame(), H.debug("[session:move] local game over applied", {
3401
+ }), t.completeGame({
3402
+ kind: "win",
3403
+ winner: i,
3404
+ reason: "rules"
3405
+ }), V.debug("[session:move] local game over applied", {
3280
3406
  winner: i,
3281
3407
  turn: r
3282
3408
  });
@@ -3305,23 +3431,33 @@ var Ze = class {
3305
3431
  });
3306
3432
  let a = t.checkWin();
3307
3433
  if (a) {
3308
- H.debug("[session:move] game over detected", {
3434
+ V.debug("[session:move] game over detected", {
3309
3435
  winner: a,
3310
3436
  turn: i
3311
- }), t.dispatch("local", "GAME_OVER"), t.dispatch("remote", "GAME_OVER"), t.cleanupGame(), H.debug("[session:move] remote game over applied", {
3437
+ }), t.completeGame({
3438
+ kind: "win",
3439
+ winner: a,
3440
+ reason: "rules"
3441
+ }), V.debug("[session:move] remote game over applied", {
3312
3442
  winner: a,
3313
3443
  turn: i
3314
3444
  });
3315
3445
  return;
3316
3446
  }
3317
- H.debug("[session:move] remote move applied", {
3447
+ V.debug("[session:move] remote move applied", {
3318
3448
  turn: i,
3319
3449
  payload: n
3320
3450
  });
3321
- }, ct = (e) => e === "undo" || e === "restart", lt = (e) => {
3451
+ }, ot = (e) => e === "undo" || e === "restart" || e === "draw", st = (e) => {
3452
+ let t = q();
3453
+ e === "undo" ? t.applyUndo(t.getPendingUndoCount() ?? 1) : e === "restart" ? t.resetGame() : t.completeGame({
3454
+ kind: "draw",
3455
+ reason: "agreement"
3456
+ });
3457
+ }, ct = (e) => {
3322
3458
  if (e.type !== "APPROVE" && e.type !== "REJECT") return;
3323
- let t = q(), n = e.payload, r = t.getPendingAction(), i = r ?? (e.from === "local" && e.type === "REJECT" && ct(n?.action) ? n.action : null);
3324
- if (H.debug("[session:request] received", {
3459
+ let t = q(), n = e.payload, r = t.getPendingAction(), i = r ?? (e.from === "local" && e.type === "REJECT" && ot(n?.action) ? n.action : null);
3460
+ if (V.debug("[session:request] received", {
3325
3461
  type: e.type,
3326
3462
  from: e.from,
3327
3463
  action: i,
@@ -3347,7 +3483,7 @@ var Ze = class {
3347
3483
  action: i,
3348
3484
  reason: n?.reason ?? "rejected"
3349
3485
  }
3350
- }), H.debug("[session:request] local auto rejected", {
3486
+ }), V.debug("[session:request] local auto rejected", {
3351
3487
  action: i,
3352
3488
  reason: n?.reason
3353
3489
  });
@@ -3358,10 +3494,10 @@ var Ze = class {
3358
3494
  console.warn("[Request] Cannot APPROVE from current state");
3359
3495
  return;
3360
3496
  }
3361
- t.dispatchApprove(), i === "undo" ? t.applyUndo(t.getPendingUndoCount() ?? 1) : i === "restart" && t.resetGame(), Y({
3497
+ t.dispatchApprove(), st(i), Y({
3362
3498
  type: "APPROVE",
3363
3499
  payload: { action: i }
3364
- }), t.clearPendingStates(), H.debug("[session:request] local approved", { action: i });
3500
+ }), t.clearPendingStates(), V.debug("[session:request] local approved", { action: i });
3365
3501
  return;
3366
3502
  }
3367
3503
  if (!t.canAction("local", "REJECT")) {
@@ -3374,7 +3510,7 @@ var Ze = class {
3374
3510
  action: i,
3375
3511
  reason: n?.reason ?? "rejected"
3376
3512
  }
3377
- }), t.clearPendingStates(), H.debug("[session:request] local rejected", { action: i });
3513
+ }), t.clearPendingStates(), V.debug("[session:request] local rejected", { action: i });
3378
3514
  return;
3379
3515
  }
3380
3516
  if (e.type === "APPROVE") {
@@ -3382,58 +3518,64 @@ var Ze = class {
3382
3518
  console.warn("[Request] Cannot APPROVE from current state (remote approved)");
3383
3519
  return;
3384
3520
  }
3385
- t.dispatchApprove(), i === "undo" ? t.applyUndo(t.getPendingUndoCount() ?? 1) : i === "restart" && t.resetGame(), t.clearPendingStates(), H.debug("[session:request] remote approved", { action: i });
3521
+ t.dispatchApprove(), st(i), t.clearPendingStates(), V.debug("[session:request] remote approved", { action: i });
3386
3522
  return;
3387
3523
  }
3388
3524
  if (!t.canAction("local", "REJECT")) {
3389
3525
  console.warn("[Request] Cannot REJECT from current state (remote rejected)"), t.clearPendingStates();
3390
3526
  return;
3391
3527
  }
3392
- t.dispatchReject(), t.clearPendingStates(), H.debug("[session:request] remote rejected", { action: i });
3393
- }, ut = (e) => e === "local" ? "remote" : "local", dt = () => {
3528
+ t.dispatchReject(), t.clearPendingStates(), V.debug("[session:request] remote rejected", { action: i });
3529
+ }, lt = (e) => e === "local" ? "remote" : "local", ut = () => {
3394
3530
  let e = q();
3395
3531
  return e.getResumeTurn() ?? (e.getState("local") === "turn" ? "local" : "remote");
3396
- }, ft = () => {
3397
- let e = q(), t = dt();
3532
+ }, dt = () => {
3533
+ let e = q(), t = ut();
3398
3534
  return {
3399
3535
  history: e.getHistory(),
3400
3536
  lastStart: e.getLastStart(),
3401
3537
  turn: t,
3402
- resumeTurn: e.getResumeTurn()
3538
+ resumeTurn: e.getResumeTurn(),
3539
+ outcome: e.getOutcome()
3403
3540
  };
3404
- }, pt = () => {
3541
+ }, ft = () => {
3405
3542
  let e = q();
3406
3543
  return e.getState("local") === "syncing" || e.getState("remote") === "syncing" || e.getState("remote") === "offline" || e.getResumeTurn() !== null;
3407
- }, mt = () => {
3544
+ }, pt = () => {
3408
3545
  let e = q();
3409
3546
  if (e.getState("local") !== "syncing") {
3410
- if (!e.canAction("local", "SYNC")) return H.debug("[session:sync] local cannot enter sync", { local: e.getState("local") }), !1;
3547
+ if (!e.canAction("local", "SYNC")) return V.debug("[session:sync] local cannot enter sync", { local: e.getState("local") }), !1;
3411
3548
  e.dispatch("local", "SYNC", "syncing");
3412
3549
  }
3413
3550
  if (e.getState("remote") === "offline") {
3414
- if (!e.canAction("remote", "ONLINE")) return H.debug("[session:sync] offline remote cannot enter sync", { remote: e.getState("remote") }), !1;
3551
+ if (!e.canAction("remote", "ONLINE")) return V.debug("[session:sync] offline remote cannot enter sync", { remote: e.getState("remote") }), !1;
3415
3552
  e.dispatch("remote", "ONLINE", "syncing");
3416
3553
  } else if (e.getState("remote") !== "syncing") {
3417
- if (!e.canAction("remote", "SYNC")) return H.debug("[session:sync] remote cannot enter sync", { remote: e.getState("remote") }), !1;
3554
+ if (!e.canAction("remote", "SYNC")) return V.debug("[session:sync] remote cannot enter sync", { remote: e.getState("remote") }), !1;
3418
3555
  e.dispatch("remote", "SYNC", "syncing");
3419
3556
  }
3420
3557
  return e.getState("local") === "syncing" && e.getState("remote") === "syncing";
3421
3558
  }, X = (e, t) => {
3422
- let n = q(), r = t ? ut : (e) => e;
3559
+ let n = q(), r = t ? lt : (e) => e;
3423
3560
  e.history && e.history.length > 0 ? n.replaceHistory(e.history.map((e) => ({
3424
3561
  ...e,
3425
3562
  player: r(e.player)
3426
3563
  }))) : n.clearHistory(), e.lastStart ? n.setLastStart(r(e.lastStart)) : n.setLastStart(null);
3427
- let i = e.resumeTurn ? r(e.resumeTurn) : e.turn ? r(e.turn) : dt();
3428
- H.debug("[session:sync] state restored", {
3564
+ let i = e.outcome ? e.outcome.kind === "win" ? {
3565
+ ...e.outcome,
3566
+ winner: r(e.outcome.winner)
3567
+ } : e.outcome : null;
3568
+ n.setOutcome(i);
3569
+ let a = e.resumeTurn ? r(e.resumeTurn) : e.turn ? r(e.turn) : ut();
3570
+ V.debug("[session:sync] state restored", {
3429
3571
  historyLength: n.getHistory().length,
3430
3572
  lastStart: n.getLastStart(),
3431
- nextTurnPlayer: i,
3573
+ nextTurnPlayer: a,
3432
3574
  mapped: t
3433
- }), mt() && n.dispatchSyncComplete(i);
3434
- }, ht = (e) => {
3575
+ }), pt() && (i ? (n.dispatch("local", "GAME_OVER"), n.dispatch("remote", "GAME_OVER")) : n.dispatchSyncComplete(a));
3576
+ }, mt = (e) => {
3435
3577
  let t = q();
3436
- if (H.debug("[session:sync] received", {
3578
+ if (V.debug("[session:sync] received", {
3437
3579
  type: e.type,
3438
3580
  from: e.from,
3439
3581
  payload: e.payload,
@@ -3451,33 +3593,33 @@ var Ze = class {
3451
3593
  type: "SYNC_REQUEST",
3452
3594
  from: "",
3453
3595
  payload: e.payload
3454
- }), H.debug("[session:sync] request sent");
3596
+ }), V.debug("[session:sync] request sent");
3455
3597
  return;
3456
3598
  }
3457
- let n = ft();
3599
+ let n = dt();
3458
3600
  Y({
3459
3601
  type: "SYNC_STATE",
3460
3602
  from: "",
3461
3603
  payload: n
3462
- }), H.debug("[session:sync] state sent", n), pt() && X(n, !1);
3604
+ }), V.debug("[session:sync] state sent", n), ft() && X(n, !1);
3463
3605
  return;
3464
3606
  }
3465
3607
  if (e.type === "SYNC_STATE") {
3466
3608
  if (e.from === "local") {
3467
- let e = ft();
3609
+ let e = dt();
3468
3610
  Y({
3469
3611
  type: "SYNC_STATE",
3470
3612
  from: "",
3471
3613
  payload: e
3472
- }), H.debug("[session:sync] state pushed", e), pt() && X(e, !1);
3614
+ }), V.debug("[session:sync] state pushed", e), ft() && X(e, !1);
3473
3615
  return;
3474
3616
  }
3475
3617
  X(e.payload || {}, !0);
3476
3618
  }
3477
- }, gt = (e) => {
3619
+ }, ht = (e) => {
3478
3620
  if (e.type !== "UNDO") return;
3479
3621
  let t = q(), n = J();
3480
- if (H.debug("[session:undo] received", {
3622
+ if (V.debug("[session:undo] received", {
3481
3623
  from: e.from,
3482
3624
  local: t.getState("local"),
3483
3625
  remote: t.getState("remote"),
@@ -3497,7 +3639,7 @@ var Ze = class {
3497
3639
  t.initializeUndoRequest(n, r), t.dispatch("local", "UNDO"), t.dispatch("remote", "REMOTE_UNDO"), Y({
3498
3640
  type: "UNDO",
3499
3641
  payload: { count: n }
3500
- }), H.debug("[session:undo] local requested", { undoCount: n });
3642
+ }), V.debug("[session:undo] local requested", { undoCount: n });
3501
3643
  return;
3502
3644
  }
3503
3645
  if (t.hasPendingAction()) {
@@ -3530,14 +3672,14 @@ var Ze = class {
3530
3672
  return;
3531
3673
  }
3532
3674
  let a = t.getState("local") === "turn" ? "local" : "remote";
3533
- t.initializeUndoRequest(i, a), t.dispatch("local", "REMOTE_UNDO"), t.dispatch("remote", "UNDO"), H.debug("[session:undo] remote requested", {
3675
+ t.initializeUndoRequest(i, a), t.dispatch("local", "REMOTE_UNDO"), t.dispatch("remote", "UNDO"), V.debug("[session:undo] remote requested", {
3534
3676
  count: i,
3535
3677
  resumePlayer: a
3536
3678
  });
3537
- }, _t = (e) => {
3679
+ }, gt = (e) => {
3538
3680
  if (e.type !== "RESTART") return;
3539
3681
  let t = q(), n = J();
3540
- if (H.debug("[session:restart] received", {
3682
+ if (V.debug("[session:restart] received", {
3541
3683
  from: e.from,
3542
3684
  local: t.getState("local"),
3543
3685
  remote: t.getState("remote"),
@@ -3550,7 +3692,7 @@ var Ze = class {
3550
3692
  return;
3551
3693
  }
3552
3694
  let e = t.getState("local") === "turn" ? "local" : "remote";
3553
- t.initializeRestartRequest(e), t.dispatch("local", "RESTART"), t.dispatch("remote", "REMOTE_RESTART"), Y({ type: "RESTART" }), H.debug("[session:restart] local requested", { resumePlayer: e });
3695
+ t.initializeRestartRequest(e), t.dispatch("local", "RESTART"), t.dispatch("remote", "REMOTE_RESTART"), Y({ type: "RESTART" }), V.debug("[session:restart] local requested", { resumePlayer: e });
3554
3696
  return;
3555
3697
  }
3556
3698
  if (t.hasPendingAction()) {
@@ -3568,11 +3710,11 @@ var Ze = class {
3568
3710
  return;
3569
3711
  }
3570
3712
  let r = t.getState("local") === "turn" ? "local" : "remote";
3571
- t.initializeRestartRequest(r), t.dispatch("local", "REMOTE_RESTART"), t.dispatch("remote", "RESTART"), H.debug("[session:restart] remote requested", { resumePlayer: r });
3572
- }, vt = (e) => {
3713
+ t.initializeRestartRequest(r), t.dispatch("local", "REMOTE_RESTART"), t.dispatch("remote", "RESTART"), V.debug("[session:restart] remote requested", { resumePlayer: r });
3714
+ }, _t = (e) => {
3573
3715
  if (e.type !== "OFFLINE" && e.type !== "ONLINE") return;
3574
3716
  let t = q(), n = J();
3575
- if (H.debug("[session:connection] received", {
3717
+ if (V.debug("[session:connection] received", {
3576
3718
  type: e.type,
3577
3719
  from: e.from,
3578
3720
  local: t.getState("local"),
@@ -3589,23 +3731,88 @@ var Ze = class {
3589
3731
  return;
3590
3732
  }
3591
3733
  let e = t.getResumeTurn() ?? (t.getState("local") === "turn" ? "local" : "remote");
3592
- t.setResumeTurn(e), t.dispatch("remote", "OFFLINE", "offline"), H.debug("[session:connection] remote offline", { currentTurn: e });
3734
+ t.setResumeTurn(e), t.dispatch("remote", "OFFLINE", "offline"), V.debug("[session:connection] remote offline", { currentTurn: e });
3593
3735
  return;
3594
3736
  }
3595
3737
  if (t.getState("remote") !== "offline") {
3596
- H.debug("[session:connection] ignored online while remote is not offline", { remote: t.getState("remote") });
3738
+ V.debug("[session:connection] ignored online while remote is not offline", { remote: t.getState("remote") });
3597
3739
  return;
3598
3740
  }
3599
3741
  if (!t.canAction("remote", "ONLINE")) {
3600
3742
  console.warn("[Offline] Cannot transition to ONLINE from current state");
3601
3743
  return;
3602
3744
  }
3603
- t.dispatch("remote", "ONLINE", "syncing"), n.emit("SYNC_STATE", void 0, "local"), H.debug("[session:connection] remote online, sync state pushed");
3604
- }, yt = (e) => {
3605
- e.register("READY", it), e.register("START", ot), e.register("MOVE", st), e.register("UNDO", gt), e.register("RESTART", _t), e.register("SYNC_REQUEST", ht), e.register("SYNC_STATE", ht), e.register("OFFLINE", vt), e.register("ONLINE", vt), e.register("APPROVE", lt), e.register("REJECT", lt);
3606
- }, bt = class {
3745
+ t.dispatch("remote", "ONLINE", "syncing"), n.emit("SYNC_STATE", void 0, "local"), V.debug("[session:connection] remote online, sync state pushed");
3746
+ }, vt = (e) => e === "draw", yt = () => q().getState("local") === "turn" ? "local" : "remote", bt = (e) => {
3747
+ if (e.type !== "REQUEST") return;
3748
+ let t = q(), n = J(), r = e.payload, i = r?.action;
3749
+ if (!vt(i)) {
3750
+ e.from === "remote" && Y({
3751
+ type: "REJECT",
3752
+ payload: {
3753
+ action: i,
3754
+ reason: "unknown_action"
3755
+ }
3756
+ });
3757
+ return;
3758
+ }
3759
+ if (t.getOutcome()) return;
3760
+ if (e.from === "local") {
3761
+ if (t.hasPendingAction() || !t.canAction("local", "REQUEST")) return;
3762
+ let e = yt();
3763
+ t.initializePendingRequest(i, e), t.dispatch("local", "REQUEST"), t.dispatch("remote", "REMOTE_REQUEST"), Y({
3764
+ type: "REQUEST",
3765
+ payload: {
3766
+ action: i,
3767
+ payload: r?.payload
3768
+ }
3769
+ }), V.debug("[session:request] local requested", { action: i });
3770
+ return;
3771
+ }
3772
+ if (t.hasPendingAction()) {
3773
+ n.emit("REJECT", {
3774
+ action: i,
3775
+ reason: "busy"
3776
+ }, "local");
3777
+ return;
3778
+ }
3779
+ if (!t.canAction("local", "REMOTE_REQUEST")) {
3780
+ n.emit("REJECT", {
3781
+ action: i,
3782
+ reason: "invalid_state"
3783
+ }, "local");
3784
+ return;
3785
+ }
3786
+ let a = yt();
3787
+ t.initializePendingRequest(i, a), t.dispatch("local", "REMOTE_REQUEST"), t.dispatch("remote", "REQUEST"), V.debug("[session:request] remote requested", { action: i });
3788
+ }, xt = (e) => {
3789
+ if (e.type !== "RESIGN") return;
3790
+ let t = q(), n = t.getOutcome();
3791
+ if (n?.kind === "win" && n.reason === "resignation") {
3792
+ t.setOutcome({
3793
+ kind: "draw",
3794
+ reason: "mutual_resignation"
3795
+ }), V.debug("[session:resign] simultaneous resignation resolved");
3796
+ return;
3797
+ }
3798
+ n || t.hasPendingAction() || (t.getState("local") === "turn" || t.getState("local") === "remote_turn") && (e.from === "local" ? (Y({ type: "RESIGN" }), t.completeGame({
3799
+ kind: "win",
3800
+ winner: "remote",
3801
+ reason: "resignation"
3802
+ })) : t.completeGame({
3803
+ kind: "win",
3804
+ winner: "local",
3805
+ reason: "resignation"
3806
+ }), V.debug("[session:resign] game completed", {
3807
+ from: e.from,
3808
+ outcome: t.getOutcome()
3809
+ }));
3810
+ }, St = (e) => {
3811
+ e.register("READY", nt), e.register("START", it), e.register("MOVE", at), e.register("UNDO", ht), e.register("RESTART", gt), e.register("REQUEST", bt), e.register("RESIGN", xt), e.register("SYNC_REQUEST", mt), e.register("SYNC_STATE", mt), e.register("OFFLINE", _t), e.register("ONLINE", _t), e.register("APPROVE", ct), e.register("REJECT", ct);
3812
+ }, Ct = class {
3813
+ bus;
3607
3814
  constructor(e) {
3608
- B(this, "bus", e);
3815
+ this.bus = e;
3609
3816
  }
3610
3817
  ready() {
3611
3818
  this.bus.emit("READY");
@@ -3622,18 +3829,30 @@ var Ze = class {
3622
3829
  restart() {
3623
3830
  this.bus.emit("RESTART");
3624
3831
  }
3832
+ request(e, t) {
3833
+ this.bus.emit("REQUEST", {
3834
+ action: e,
3835
+ payload: t
3836
+ });
3837
+ }
3838
+ offerDraw() {
3839
+ this.request("draw");
3840
+ }
3841
+ resign() {
3842
+ this.bus.emit("RESIGN");
3843
+ }
3625
3844
  approve() {
3626
3845
  this.bus.emit("APPROVE");
3627
3846
  }
3628
3847
  reject() {
3629
3848
  this.bus.emit("REJECT");
3630
3849
  }
3631
- }, xt = (e, t) => {
3632
- let n = new We(), r = new Qe(null, null), i = new Ye(), a = et(e, n, null), o = new Ze(r, i, () => a.getIsConnected());
3633
- r.subscribeStateObserver(o), nt(r, n, a, t), yt(n);
3634
- let s = new bt(n);
3850
+ }, wt = (e, t) => {
3851
+ let n = new Ue(), r = new Xe(null, null), i = new Je(), a = Qe(e, n, null), o = new Ye(r, i, () => a.getIsConnected());
3852
+ r.subscribeStateObserver(o), et(r, n, a, t), St(n);
3853
+ let s = new Ct(n);
3635
3854
  return a.onConnectionChange((e) => {
3636
- i.notifyConnectionChange(e), i.notifyStateChange(Xe(r, e));
3855
+ i.notifyConnectionChange(e), i.notifyStateChange(W(r, e));
3637
3856
  }), {
3638
3857
  bus: n,
3639
3858
  state: r,
@@ -3642,7 +3861,7 @@ var Ze = class {
3642
3861
  actions: s,
3643
3862
  send: a.send.bind(a)
3644
3863
  };
3645
- }, St = "wss://signal.jiahengli.xyz", Ct = (e) => ({
3864
+ }, Tt = "wss://signal.jiahengli.xyz", Et = (e) => ({
3646
3865
  screen: "pairing",
3647
3866
  theme: e?.theme || "light",
3648
3867
  gameTitle: e?.gameTitle || "P2P Lockstep",
@@ -3661,25 +3880,30 @@ var Ze = class {
3661
3880
  canStart: !1,
3662
3881
  canUndo: !1,
3663
3882
  canRestart: !1,
3883
+ canOfferDraw: !1,
3884
+ canResign: !1,
3885
+ allowDraw: e?.allowDraw ?? !1,
3886
+ allowResign: e?.allowResign ?? !1,
3664
3887
  started: !1,
3665
3888
  currentTurn: 1,
3666
3889
  turnOwner: null,
3667
3890
  localState: "idle",
3668
3891
  remoteState: "idle",
3669
3892
  pendingAction: null,
3893
+ outcome: null,
3670
3894
  historyLength: 0,
3671
3895
  lastStart: null,
3672
3896
  lastError: ""
3673
- }), wt = "p2p-lockstep-theme", Z = (e) => e === "light" || e === "dark", Tt = () => {
3897
+ }), Dt = "p2p-lockstep-theme", Z = (e) => e === "light" || e === "dark", Ot = () => {
3674
3898
  try {
3675
- let e = window.localStorage.getItem(wt);
3899
+ let e = window.localStorage.getItem(Dt);
3676
3900
  return Z(e) ? e : null;
3677
3901
  } catch {
3678
3902
  return null;
3679
3903
  }
3680
- }, Et = (e) => {
3904
+ }, kt = (e) => {
3681
3905
  try {
3682
- window.localStorage.setItem(wt, e);
3906
+ window.localStorage.setItem(Dt, e);
3683
3907
  } catch {}
3684
3908
  }, Q = {
3685
3909
  open: !1,
@@ -3687,64 +3911,69 @@ var Ze = class {
3687
3911
  description: "",
3688
3912
  confirmLabel: "Approve",
3689
3913
  cancelLabel: "Reject"
3690
- }, Dt = {
3914
+ }, At = {
3691
3915
  open: !1,
3692
3916
  message: ""
3693
- }, Ot = [
3917
+ }, jt = [
3694
3918
  "turn",
3695
3919
  "remote_turn",
3696
3920
  "approving",
3697
3921
  "waiting_approval",
3698
3922
  "syncing"
3699
- ], kt = class extends HTMLElement {
3923
+ ], Mt = class extends HTMLElement {
3700
3924
  static get observedAttributes() {
3701
3925
  return [
3702
3926
  "game-title",
3703
3927
  "session-id",
3704
3928
  "signal-url",
3705
- "theme"
3929
+ "theme",
3930
+ "allow-draw",
3931
+ "allow-resign"
3706
3932
  ];
3707
3933
  }
3708
3934
  #e = !1;
3709
- #t = Ct();
3935
+ #t = Et();
3710
3936
  #n = Q;
3711
- #r = Dt;
3712
- #i = null;
3937
+ #r = null;
3938
+ #i = At;
3713
3939
  #a = null;
3714
3940
  #o = null;
3715
3941
  #s = null;
3716
- #c = new ze();
3717
- #l = null;
3942
+ #c = null;
3943
+ #l = new Be();
3718
3944
  #u = null;
3719
3945
  #d = null;
3720
3946
  #f = null;
3721
- #p = !1;
3722
- #m = null;
3947
+ #p = null;
3948
+ #m = !1;
3949
+ #h = null;
3723
3950
  connectedCallback() {
3724
3951
  if (this.#e) return;
3725
3952
  this.#e = !0;
3726
- let e = Z(this.getAttribute("theme")) ? this.getAttribute("theme") : "light", t = Tt() ?? e;
3727
- this.#t = Ct({
3953
+ let e = Z(this.getAttribute("theme")) ? this.getAttribute("theme") : "light", t = Ot() ?? e;
3954
+ this.#t = Et({
3728
3955
  gameTitle: this.getAttribute("game-title") ?? void 0,
3729
3956
  sessionId: this.getAttribute("session-id") ?? void 0,
3730
3957
  signalUrl: this.getAttribute("signal-url") ?? void 0,
3731
- theme: t
3732
- }), this.getAttribute("theme") !== t && this.setAttribute("theme", t), this.render(), this.addEventListener("lockstep-register", this.#D), this.addEventListener("lockstep-connect", this.#O), this.addEventListener("lockstep-signal-change", this.#k), this.addEventListener("lockstep-target-change", this.#A), this.addEventListener("lockstep-share-detected", this.#j), this.addEventListener("lockstep-copy-share", this.#M), this.addEventListener("lockstep-theme-change", this.#N), this.addEventListener("lockstep-ready", this.#P), this.addEventListener("lockstep-start", this.#F), this.addEventListener("lockstep-undo", this.#I), this.addEventListener("lockstep-restart", this.#L), this.addEventListener("lockstep-dialog-confirm", this.#R), this.addEventListener("lockstep-dialog-cancel", this.#z), document.addEventListener("visibilitychange", this.#B), window.addEventListener("pageshow", this.#V), this.#h(), this.#g();
3958
+ theme: t,
3959
+ allowDraw: this.hasAttribute("allow-draw"),
3960
+ allowResign: this.hasAttribute("allow-resign")
3961
+ }), this.getAttribute("theme") !== t && this.setAttribute("theme", t), this.render(), this.addEventListener("lockstep-register", this.#O), this.addEventListener("lockstep-connect", this.#k), this.addEventListener("lockstep-signal-change", this.#A), this.addEventListener("lockstep-target-change", this.#j), this.addEventListener("lockstep-share-detected", this.#M), this.addEventListener("lockstep-copy-share", this.#N), this.addEventListener("lockstep-theme-change", this.#P), this.addEventListener("lockstep-ready", this.#F), this.addEventListener("lockstep-start", this.#I), this.addEventListener("lockstep-undo", this.#L), this.addEventListener("lockstep-restart", this.#R), this.addEventListener("lockstep-draw", this.#z), this.addEventListener("lockstep-resign", this.#B), this.addEventListener("lockstep-dialog-confirm", this.#V), this.addEventListener("lockstep-dialog-cancel", this.#H), document.addEventListener("visibilitychange", this.#U), window.addEventListener("pageshow", this.#W), this.#g(), this.#_();
3733
3962
  }
3734
3963
  disconnectedCallback() {
3735
- this.removeEventListener("lockstep-register", this.#D), this.removeEventListener("lockstep-connect", this.#O), this.removeEventListener("lockstep-signal-change", this.#k), this.removeEventListener("lockstep-target-change", this.#A), this.removeEventListener("lockstep-share-detected", this.#j), this.removeEventListener("lockstep-copy-share", this.#M), this.removeEventListener("lockstep-theme-change", this.#N), this.removeEventListener("lockstep-ready", this.#P), this.removeEventListener("lockstep-start", this.#F), this.removeEventListener("lockstep-undo", this.#I), this.removeEventListener("lockstep-restart", this.#L), this.removeEventListener("lockstep-dialog-confirm", this.#R), this.removeEventListener("lockstep-dialog-cancel", this.#z), document.removeEventListener("visibilitychange", this.#B), window.removeEventListener("pageshow", this.#V), this.#d &&= (window.clearTimeout(this.#d), null), this.#c.disconnect();
3964
+ this.removeEventListener("lockstep-register", this.#O), this.removeEventListener("lockstep-connect", this.#k), this.removeEventListener("lockstep-signal-change", this.#A), this.removeEventListener("lockstep-target-change", this.#j), this.removeEventListener("lockstep-share-detected", this.#M), this.removeEventListener("lockstep-copy-share", this.#N), this.removeEventListener("lockstep-theme-change", this.#P), this.removeEventListener("lockstep-ready", this.#F), this.removeEventListener("lockstep-start", this.#I), this.removeEventListener("lockstep-undo", this.#L), this.removeEventListener("lockstep-restart", this.#R), this.removeEventListener("lockstep-draw", this.#z), this.removeEventListener("lockstep-resign", this.#B), this.removeEventListener("lockstep-dialog-confirm", this.#V), this.removeEventListener("lockstep-dialog-cancel", this.#H), document.removeEventListener("visibilitychange", this.#U), window.removeEventListener("pageshow", this.#W), this.#f &&= (window.clearTimeout(this.#f), null), this.#l.disconnect();
3736
3965
  }
3737
3966
  attributeChangedCallback(e, t, n) {
3738
- this.#e && (e === "game-title" && n && this.#C({ gameTitle: n }), e === "session-id" && n && this.#C({ sessionId: n }), e === "signal-url" && n && this.#C({ signalUrl: n }), e === "theme" && Z(n) && this.#C({ theme: n }));
3967
+ this.#e && (e === "game-title" && n && this.#w({ gameTitle: n }), e === "session-id" && n && this.#w({ sessionId: n }), e === "signal-url" && n && this.#w({ signalUrl: n }), e === "theme" && Z(n) && this.#w({ theme: n }), e === "allow-draw" && this.#w({ allowDraw: n !== null }), e === "allow-resign" && this.#w({ allowResign: n !== null }));
3739
3968
  }
3740
3969
  getRuntime() {
3741
- return this.#u;
3970
+ return this.#d;
3742
3971
  }
3743
3972
  resumeConnection() {
3744
- this.#_();
3973
+ this.#v();
3745
3974
  }
3746
3975
  getBoardHost() {
3747
- return this.#a?.getBoardHost() ?? null;
3976
+ return this.#o?.getBoardHost() ?? null;
3748
3977
  }
3749
3978
  render() {
3750
3979
  this.className = "block min-h-svh bg-[var(--lock-bg-deep)] text-[var(--lock-paper)]", this.innerHTML = `
@@ -3773,157 +4002,177 @@ var Ze = class {
3773
4002
  <p2p-lockstep-confirm-dialog></p2p-lockstep-confirm-dialog>
3774
4003
  <p2p-lockstep-toast-message></p2p-lockstep-toast-message>
3775
4004
  </div>
3776
- `, this.#i = this.querySelector("p2p-lockstep-pairing-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.#w();
3777
- }
3778
- #h() {
3779
- this.#l = xt(this.#c, this.#t.sessionId), this.#u = {
3780
- setGamePlugin: (e) => this.#l?.state.setGamePlugin(e),
3781
- actions: { move: (e) => this.#l?.actions.move(e) },
4005
+ `, this.#a = this.querySelector("p2p-lockstep-pairing-page"), this.#o = this.querySelector("p2p-lockstep-game-page"), this.#s = this.querySelector("p2p-lockstep-confirm-dialog"), this.#c = this.querySelector("p2p-lockstep-toast-message"), this.#T();
4006
+ }
4007
+ #g() {
4008
+ this.#u = wt(this.#l, this.#t.sessionId), this.#d = {
4009
+ setGamePlugin: (e) => this.#u?.state.setGamePlugin(e),
4010
+ actions: {
4011
+ move: (e) => this.#u?.actions.move(e),
4012
+ offerDraw: () => this.#u?.actions.offerDraw(),
4013
+ resign: () => this.#u?.actions.resign()
4014
+ },
3782
4015
  observer: {
3783
- subscribe: (e) => this.#l?.observer.subscribe({
4016
+ subscribe: (e) => this.#u?.observer.subscribe({
3784
4017
  onStateChange: e.onStateChange,
3785
4018
  onConnectionChange: e.onConnectionChange,
3786
4019
  onError: e.onError,
3787
4020
  onGameEvent: e.onGameEvent ?? (() => {})
3788
4021
  }) ?? (() => {}),
3789
- getSnapshot: () => this.#l?.observer.getSnapshot() ?? null
4022
+ getSnapshot: () => this.#u?.observer.getSnapshot() ?? null
3790
4023
  }
3791
- }, this.#f = {
3792
- onStateChange: (e) => this.#x(e),
3793
- onConnectionChange: (e) => this.#S(e),
4024
+ }, this.#p = {
4025
+ onStateChange: (e) => this.#S(e),
4026
+ onConnectionChange: (e) => this.#C(e),
3794
4027
  onGameEvent: () => {},
3795
4028
  onError: (e) => {
3796
- this.#C({
4029
+ this.#w({
3797
4030
  lastError: e.message,
3798
4031
  connectionState: "error"
3799
- }), this.#T(e.message);
4032
+ }), this.#E(e.message);
3800
4033
  }
3801
- }, this.#l.observer.subscribe(this.#f), this.#C({
4034
+ }, this.#u.observer.subscribe(this.#p), this.#w({
3802
4035
  localState: "idle",
3803
4036
  remoteState: "idle",
3804
4037
  currentTurn: 1
3805
4038
  });
3806
4039
  }
3807
- async #g() {
3808
- let e = N();
3809
- e.signalUrl && this.#C({ signalUrl: e.signalUrl }), e.peerId && this.#C({ targetId: e.peerId }), this.#t.signalUrl && (await this.#y(this.#t.signalUrl, !0), e.peerId && await this.#b(e.peerId, !0));
4040
+ async #_() {
4041
+ let e = Te();
4042
+ e.signalUrl && this.#w({ signalUrl: e.signalUrl }), e.peerId && this.#w({ targetId: e.peerId }), this.#t.signalUrl && (await this.#b(this.#t.signalUrl, !0), e.peerId && await this.#x(e.peerId, !0));
3810
4043
  }
3811
- #_() {
3812
- if (this.#m || !this.isConnected) return;
3813
- let e = N(), t = this.#c.getRemotePeerId() || this.#t.remotePeerId || e.peerId;
3814
- this.#t.screen !== "game" || !this.#t.signalUrl || !t || (this.#m = this.#v(t).finally(() => {
3815
- this.#m = null;
4044
+ #v() {
4045
+ if (this.#h || !this.isConnected) return;
4046
+ let e = Te(), t = this.#l.getRemotePeerId() || this.#t.remotePeerId || e.peerId;
4047
+ this.#t.screen !== "game" || !this.#t.signalUrl || !t || (this.#h = this.#y(t).finally(() => {
4048
+ this.#h = null;
3816
4049
  }));
3817
4050
  }
3818
- async #v(e) {
3819
- this.#C({
4051
+ async #y(e) {
4052
+ this.#w({
3820
4053
  targetId: e,
3821
4054
  remotePeerId: e,
3822
4055
  connected: !1,
3823
4056
  connecting: !0,
3824
4057
  connectionState: "connecting",
3825
4058
  lastError: ""
3826
- }), this.#T("Restoring peer connection."), await this.#y(this.#t.signalUrl, !0), this.#c.getLocalPeerId() && await this.#b(e, !0);
4059
+ }), this.#E("Restoring peer connection."), await this.#b(this.#t.signalUrl, !0), this.#l.getLocalPeerId() && await this.#x(e, !0);
3827
4060
  }
3828
- async #y(e, t = !1) {
4061
+ async #b(e, t = !1) {
3829
4062
  let n = e.trim();
3830
4063
  if (n) {
3831
- this.#C({
4064
+ this.#w({
3832
4065
  signalUrl: n,
3833
4066
  registering: !0,
3834
4067
  connectionState: "registering",
3835
4068
  lastError: ""
3836
4069
  });
3837
4070
  try {
3838
- let { peerId: e } = await this.#c.register(n);
3839
- this.#l?.net.setPeerIds({
4071
+ let { peerId: e } = await this.#l.register(n);
4072
+ this.#u?.net.setPeerIds({
3840
4073
  local: e,
3841
4074
  remote: this.#t.remotePeerId || null
3842
- }), this.#C({
4075
+ }), this.#w({
3843
4076
  peerId: e,
3844
4077
  registering: !1,
3845
4078
  connectionState: "registered"
3846
- }), t || this.#T("Peer registered. You can share the link now.");
4079
+ }), t || this.#E("Peer registered. You can share the link now.");
3847
4080
  } catch (e) {
3848
- this.#C({
4081
+ this.#w({
3849
4082
  registering: !1,
3850
4083
  connectionState: "error",
3851
4084
  lastError: e instanceof Error ? e.message : "Failed to register signaling session."
3852
- }), this.#T(this.#t.lastError || "Failed to register signaling session.");
4085
+ }), this.#E(this.#t.lastError || "Failed to register signaling session.");
3853
4086
  }
3854
4087
  }
3855
4088
  }
3856
- async #b(e, t = !1) {
4089
+ async #x(e, t = !1) {
3857
4090
  let n = e.trim();
3858
4091
  if (n) {
3859
- !this.#t.peerId && this.#t.signalUrl && await this.#y(this.#t.signalUrl, !0), this.#C({
4092
+ !this.#t.peerId && this.#t.signalUrl && await this.#b(this.#t.signalUrl, !0), this.#w({
3860
4093
  targetId: n,
3861
4094
  remotePeerId: n,
3862
4095
  connecting: !0,
3863
4096
  connectionState: "connecting",
3864
4097
  lastError: ""
3865
- }), this.#l?.net.setPeerIds({
4098
+ }), this.#u?.net.setPeerIds({
3866
4099
  local: this.#t.peerId || null,
3867
4100
  remote: n
3868
4101
  });
3869
4102
  try {
3870
- await this.#c.connect(n), this.#C({ connecting: !1 }), t || this.#T("Connection request sent.");
4103
+ await this.#l.connect(n), this.#w({ connecting: !1 }), t || this.#E("Connection request sent.");
3871
4104
  } catch (e) {
3872
- this.#C({
4105
+ this.#w({
3873
4106
  connecting: !1,
3874
4107
  connectionState: "error",
3875
4108
  lastError: e instanceof Error ? e.message : "Failed to start peer connection."
3876
- }), this.#T(this.#t.lastError || "Failed to start peer connection.");
4109
+ }), this.#E(this.#t.lastError || "Failed to start peer connection.");
3877
4110
  }
3878
4111
  }
3879
4112
  }
3880
- #x(e) {
3881
- 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 = Ot.includes(e.localState) || e.localState === "offline" && e.lastStart !== null, l = e.localState === "turn" ? "me" : e.localState === "remote_turn" ? "peer" : null;
3882
- this.#C({
4113
+ #S(e) {
4114
+ let t = e.connected, n = e.localState === "ready", r = e.remoteState === "ready", i = !e.outcome && (e.localState === "turn" || e.localState === "remote_turn"), a = t && e.localState === "idle", o = t && e.localState === "could_start", s = t && i && !e.pendingAction && e.history.length > 0, c = t && i && !e.pendingAction, l = this.#t.allowDraw && t && i && !e.pendingAction, u = this.#t.allowResign && t && i && !e.pendingAction, d = jt.includes(e.localState) || e.localState === "offline" && e.lastStart !== null, f = e.localState === "turn" ? "me" : e.localState === "remote_turn" ? "peer" : null;
4115
+ if (this.#w({
3883
4116
  readySelf: n,
3884
4117
  readyPeer: r,
3885
4118
  connected: t,
3886
4119
  connectionState: t ? "connected" : this.#t.connectionState,
3887
- canReady: i,
3888
- canStart: a,
3889
- canUndo: o,
3890
- canRestart: s,
4120
+ canReady: a,
4121
+ canStart: o,
4122
+ canUndo: s,
4123
+ canRestart: c,
4124
+ canOfferDraw: l,
4125
+ canResign: u,
3891
4126
  screen: t ? "game" : this.#t.screen,
3892
- started: c,
4127
+ started: d,
3893
4128
  currentTurn: e.turn,
3894
- turnOwner: l,
4129
+ turnOwner: f,
3895
4130
  localState: e.localState,
3896
4131
  remoteState: e.remoteState,
3897
4132
  pendingAction: e.pendingAction,
4133
+ outcome: e.outcome,
3898
4134
  historyLength: e.history.length,
3899
4135
  lastStart: e.lastStart
3900
- }), e.localState === "approving" && e.pendingAction ? this.#n = {
3901
- open: !0,
3902
- title: e.pendingAction === "undo" ? "Undo request pending" : "Restart request pending",
3903
- 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.",
3904
- confirmLabel: "Approve",
3905
- cancelLabel: "Reject"
3906
- } : this.#n.open && (this.#n = Q), this.#w();
4136
+ }), e.localState === "approving" && e.pendingAction) {
4137
+ this.#r = "approval";
4138
+ let t = e.pendingAction === "undo" ? {
4139
+ title: "Undo request pending",
4140
+ description: "Your peer wants to roll the match back. Approve the undo or reject it and keep the current board."
4141
+ } : e.pendingAction === "restart" ? {
4142
+ title: "Restart request pending",
4143
+ description: "Your peer wants to restart the match. Approve to reset the board shell or reject to continue."
4144
+ } : {
4145
+ title: "Draw offer",
4146
+ description: "Your peer has offered a draw. Accept to end the match as a draw or reject to continue playing."
4147
+ };
4148
+ this.#n = {
4149
+ open: !0,
4150
+ ...t,
4151
+ confirmLabel: e.pendingAction === "draw" ? "Accept draw" : "Approve",
4152
+ cancelLabel: "Reject"
4153
+ };
4154
+ } else this.#r === "approval" && (this.#n = Q, this.#r = null);
4155
+ this.#T();
3907
4156
  }
3908
- #S(e) {
3909
- 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 || t, o = n === "connected" ? "connected" : n === "requesting" ? "connecting" : t ? "offline" : i ? "registered" : "idle";
3910
- this.#C({
4157
+ #C(e) {
4158
+ let t = this.#t.screen === "game", n = this.#l.peerState(), r = this.#l.getRemotePeerId() ?? this.#t.remotePeerId, i = this.#l.getLocalPeerId() ?? this.#t.peerId, a = e || t, o = n === "connected" ? "connected" : n === "requesting" ? "connecting" : t ? "offline" : i ? "registered" : "idle";
4159
+ this.#w({
3911
4160
  peerId: i,
3912
4161
  remotePeerId: r,
3913
4162
  connected: e,
3914
4163
  connecting: n === "requesting",
3915
4164
  connectionState: o,
3916
4165
  screen: a ? "game" : "pairing"
3917
- }), e ? this.#T("Peer connected. Game page is live.") : n === "requesting" && !t ? this.#T("Connecting to peer.") : t && i && this.#T("Peer disconnected. Waiting for reconnect.");
4166
+ }), e ? this.#E("Peer connected. Game page is live.") : n === "requesting" && !t ? this.#E("Connecting to peer.") : t && i && this.#E("Peer disconnected. Waiting for reconnect.");
3918
4167
  }
3919
- #C(e) {
4168
+ #w(e) {
3920
4169
  this.#t = {
3921
4170
  ...this.#t,
3922
4171
  ...e
3923
- }, this.#e && this.#w();
4172
+ }, this.#e && this.#T();
3924
4173
  }
3925
- #w() {
3926
- let e = this.#i, t = this.#a, n = this.#o, r = this.#s;
4174
+ #T() {
4175
+ let e = this.#a, t = this.#o, n = this.#s, r = this.#c;
3927
4176
  if (!e || !t || !n || !r) return;
3928
4177
  e.toggleAttribute("hidden", this.#t.screen !== "pairing"), t.toggleAttribute("hidden", this.#t.screen !== "game");
3929
4178
  let i = this.querySelector("[data-shell-connection-state]");
@@ -3950,98 +4199,115 @@ var Ze = class {
3950
4199
  canStart: this.#t.canStart,
3951
4200
  canUndo: this.#t.canUndo,
3952
4201
  canRestart: this.#t.canRestart,
4202
+ canOfferDraw: this.#t.canOfferDraw,
4203
+ canResign: this.#t.canResign,
4204
+ allowDraw: this.#t.allowDraw,
4205
+ allowResign: this.#t.allowResign,
3953
4206
  started: this.#t.started,
3954
4207
  currentTurn: this.#t.currentTurn,
3955
4208
  turnOwner: this.#t.turnOwner,
3956
4209
  localState: this.#t.localState,
3957
4210
  remoteState: this.#t.remoteState,
3958
4211
  pendingAction: this.#t.pendingAction,
4212
+ outcome: this.#t.outcome,
3959
4213
  sessionId: this.#t.sessionId,
3960
4214
  historyLength: this.#t.historyLength,
3961
4215
  lastStart: this.#t.lastStart,
3962
4216
  lastError: this.#t.lastError
3963
- }, n.state = this.#n, r.state = this.#r;
4217
+ }, n.state = this.#n, r.state = this.#i;
3964
4218
  }
3965
- #T(e) {
3966
- e && (this.#d && window.clearTimeout(this.#d), this.#r = {
4219
+ #E(e) {
4220
+ e && (this.#f && window.clearTimeout(this.#f), this.#i = {
3967
4221
  open: !0,
3968
4222
  message: e
3969
- }, this.#w(), this.#d = window.setTimeout(() => {
3970
- this.#r = Dt, this.#w(), this.#d = null;
4223
+ }, this.#T(), this.#f = window.setTimeout(() => {
4224
+ this.#i = At, this.#T(), this.#f = null;
3971
4225
  }, 2200));
3972
4226
  }
3973
- async #E(e) {
4227
+ async #D(e) {
3974
4228
  if (e) {
3975
4229
  try {
3976
4230
  if (navigator.clipboard?.writeText) {
3977
- await navigator.clipboard.writeText(e), this.#T("Copied to clipboard.");
4231
+ await navigator.clipboard.writeText(e), this.#E("Copied to clipboard.");
3978
4232
  return;
3979
4233
  }
3980
4234
  } catch {}
3981
4235
  window.prompt("Copy value", e);
3982
4236
  }
3983
4237
  }
3984
- #D = (e) => {
3985
- this.#y(e.detail.signalUrl);
3986
- };
3987
4238
  #O = (e) => {
3988
- this.#b(e.detail.targetId);
4239
+ this.#b(e.detail.signalUrl);
3989
4240
  };
3990
4241
  #k = (e) => {
3991
- this.#C({ signalUrl: e.detail.signalUrl });
4242
+ this.#x(e.detail.targetId);
3992
4243
  };
3993
4244
  #A = (e) => {
3994
- this.#C({ targetId: e.detail.targetId });
4245
+ this.#w({ signalUrl: e.detail.signalUrl });
3995
4246
  };
3996
4247
  #j = (e) => {
3997
- this.#C({
4248
+ this.#w({ targetId: e.detail.targetId });
4249
+ };
4250
+ #M = (e) => {
4251
+ this.#w({
3998
4252
  targetId: e.detail.peerId,
3999
4253
  signalUrl: e.detail.signalUrl || this.#t.signalUrl
4000
4254
  });
4001
4255
  };
4002
- #M = (e) => {
4003
- this.#E(e.detail.value);
4004
- };
4005
4256
  #N = (e) => {
4257
+ this.#D(e.detail.value);
4258
+ };
4259
+ #P = (e) => {
4006
4260
  if (!Z(e.detail.theme) || e.detail.theme === this.#t.theme) return;
4007
4261
  let t = e.detail.theme;
4008
- Et(t), this.setAttribute("theme", t), this.#T(`${t === "dark" ? "Night" : "Day"} mode enabled.`);
4009
- };
4010
- #P = () => {
4011
- this.#l?.actions.ready(), this.#T(this.#t.readySelf ? "Ready state cleared." : "Ready state sent.");
4262
+ kt(t), this.setAttribute("theme", t), this.#E(`${t === "dark" ? "Night" : "Day"} mode enabled.`);
4012
4263
  };
4013
4264
  #F = () => {
4014
- this.#l?.actions.start(), this.#T("Start request sent.");
4265
+ this.#u?.actions.ready(), this.#E(this.#t.readySelf ? "Ready state cleared." : "Ready state sent.");
4015
4266
  };
4016
4267
  #I = () => {
4017
- this.#l?.actions.undo(), this.#T("Undo request sent.");
4268
+ this.#u?.actions.start(), this.#E("Start request sent.");
4018
4269
  };
4019
4270
  #L = () => {
4020
- this.#l?.actions.restart(), this.#T("Restart request sent.");
4271
+ this.#u?.actions.undo(), this.#E("Undo request sent.");
4021
4272
  };
4022
4273
  #R = () => {
4023
- this.#l?.actions.approve(), this.#n = Q, this.#w(), this.#T("Request approved.");
4274
+ this.#u?.actions.restart(), this.#E("Restart request sent.");
4024
4275
  };
4025
4276
  #z = () => {
4026
- this.#l?.actions.reject(), this.#n = Q, this.#w(), this.#T("Request rejected.");
4277
+ this.#t.canOfferDraw && (this.#u?.actions.offerDraw(), this.#E("Draw offer sent."));
4027
4278
  };
4028
4279
  #B = () => {
4280
+ this.#t.canResign && (this.#r = "resign", this.#n = {
4281
+ open: !0,
4282
+ title: "Resign this match?",
4283
+ description: "Resigning ends the current match immediately and awards the win to your peer.",
4284
+ confirmLabel: "Resign",
4285
+ cancelLabel: "Keep playing"
4286
+ }, this.#T());
4287
+ };
4288
+ #V = () => {
4289
+ this.#r === "resign" ? (this.#u?.actions.resign(), this.#E("You resigned the match.")) : (this.#u?.actions.approve(), this.#E("Request approved.")), this.#r = null, this.#n = Q, this.#T();
4290
+ };
4291
+ #H = () => {
4292
+ this.#r === "approval" && (this.#u?.actions.reject(), this.#E("Request rejected.")), this.#r = null, this.#n = Q, this.#T();
4293
+ };
4294
+ #U = () => {
4029
4295
  if (document.visibilityState === "hidden") {
4030
- this.#p = !0;
4296
+ this.#m = !0;
4031
4297
  return;
4032
4298
  }
4033
- this.#p && (this.#p = !1, this.#_());
4299
+ this.#m && (this.#m = !1, this.#v());
4034
4300
  };
4035
- #V = (e) => {
4036
- e.persisted && this.#_();
4301
+ #W = (e) => {
4302
+ e.persisted && this.#v();
4037
4303
  };
4038
4304
  }, $ = (e, t) => {
4039
4305
  customElements.get(e) || customElements.define(e, t);
4040
- }, At = () => {
4041
- $("p2p-lockstep-share-panel", k), $("p2p-lockstep-status-panel", be), $("p2p-lockstep-action-bar", d), $("p2p-lockstep-confirm-dialog", g), $("p2p-lockstep-toast-message", Se), $("p2p-lockstep-board-host", Ce), $("p2p-lockstep-pairing-page", P), $("p2p-lockstep-game-page", F), $("p2p-lockstep-app", kt);
4306
+ }, Nt = () => {
4307
+ $("p2p-lockstep-share-panel", M), $("p2p-lockstep-status-panel", ve), $("p2p-lockstep-action-bar", d), $("p2p-lockstep-confirm-dialog", g), $("p2p-lockstep-toast-message", be), $("p2p-lockstep-board-host", xe), $("p2p-lockstep-pairing-page", F), $("p2p-lockstep-game-page", I), $("p2p-lockstep-app", Mt);
4042
4308
  };
4043
- At();
4309
+ Nt();
4044
4310
  //#endregion
4045
- export { St as DEFAULT_SIGNAL_URL, d as P2PLockstepActionBarElement, kt as P2PLockstepAppElement, Ce as P2PLockstepBoardHostElement, g as P2PLockstepConfirmDialogElement, F as P2PLockstepGamePageElement, P as P2PLockstepPairingPageElement, k as P2PLockstepSharePanelElement, be as P2PLockstepStatusPanelElement, Se as P2PLockstepToastMessageElement, At as defineP2PLockstepUi };
4311
+ export { Tt as DEFAULT_SIGNAL_URL, d as P2PLockstepActionBarElement, Mt as P2PLockstepAppElement, xe as P2PLockstepBoardHostElement, g as P2PLockstepConfirmDialogElement, I as P2PLockstepGamePageElement, F as P2PLockstepPairingPageElement, M as P2PLockstepSharePanelElement, ve as P2PLockstepStatusPanelElement, be as P2PLockstepToastMessageElement, Nt as defineP2PLockstepUi };
4046
4312
 
4047
4313
  //# sourceMappingURL=index.js.map