@minicode-dev/chat 0.1.11 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +102 -6
  2. package/assets/sounds/effects/avalanche.mp3 +0 -0
  3. package/dist/chunks/{TanksGameCard-B47ZQcSr.js → TanksGameCard-GrqmdwJ7.js} +2 -2
  4. package/dist/chunks/{TanksGameCard-B47ZQcSr.js.map → TanksGameCard-GrqmdwJ7.js.map} +1 -1
  5. package/dist/chunks/TanksLiveGameCard-DSmQcUMh.js +1225 -0
  6. package/dist/chunks/TanksLiveGameCard-DSmQcUMh.js.map +1 -0
  7. package/dist/chunks/{WebRtcLab-lijo_Rta.js → WebRtcLab-ClRSYt4E.js} +2 -2
  8. package/dist/chunks/{WebRtcLab-lijo_Rta.js.map → WebRtcLab-ClRSYt4E.js.map} +1 -1
  9. package/dist/chunks/avalancheScene3d-Dnl2E3EA.js +1878 -0
  10. package/dist/chunks/avalancheScene3d-Dnl2E3EA.js.map +1 -0
  11. package/dist/chunks/createLiveScene-819NWv84.js +365 -0
  12. package/dist/chunks/createLiveScene-819NWv84.js.map +1 -0
  13. package/dist/chunks/createPeerLink-DBVs_yvQ.js +1136 -0
  14. package/dist/chunks/createPeerLink-DBVs_yvQ.js.map +1 -0
  15. package/dist/chunks/{createTankScene-CV7Brxmt.js → createTankScene-6asWHKFf.js} +120 -119
  16. package/dist/chunks/{createTankScene-CV7Brxmt.js.map → createTankScene-6asWHKFf.js.map} +1 -1
  17. package/dist/chunks/fx-BNJvJYOu.js +871 -0
  18. package/dist/chunks/fx-BNJvJYOu.js.map +1 -0
  19. package/dist/chunks/tank-DIn6Jyt8.js +605 -0
  20. package/dist/chunks/tank-DIn6Jyt8.js.map +1 -0
  21. package/dist/index.js +1581 -1184
  22. package/dist/index.js.map +1 -1
  23. package/dist/styles.css +1 -1
  24. package/index.d.ts +23 -3
  25. package/package.json +1 -1
  26. package/dist/chunks/TanksLiveGameCard-BNJqWt1z.js +0 -915
  27. package/dist/chunks/TanksLiveGameCard-BNJqWt1z.js.map +0 -1
  28. package/dist/chunks/createLiveScene-CJQtq54t.js +0 -364
  29. package/dist/chunks/createLiveScene-CJQtq54t.js.map +0 -1
  30. package/dist/chunks/createPeerLink-CL7VZuHS.js +0 -480
  31. package/dist/chunks/createPeerLink-CL7VZuHS.js.map +0 -1
  32. package/dist/chunks/fx-BHsl4S_J.js +0 -1470
  33. package/dist/chunks/fx-BHsl4S_J.js.map +0 -1
@@ -0,0 +1,1136 @@
1
+ // src/net/webrtc/protocol.js
2
+ var e = "LIRA_WEBRTC_V1:", t = 1e4, n = [
3
+ "hello",
4
+ "ready",
5
+ "offer",
6
+ "answer",
7
+ "ice",
8
+ "ack",
9
+ "bye",
10
+ "turn"
11
+ ], r = /^[A-Za-z0-9_-]{4,64}$/, i = 32, a = (e) => typeof e == "string" && e.startsWith("LIRA_WEBRTC_V1:"), o = (e, t) => {
12
+ if (t == null) return [
13
+ "hello",
14
+ "ready",
15
+ "bye"
16
+ ].includes(e);
17
+ if (typeof t != "object" || Array.isArray(t)) return !1;
18
+ switch (e) {
19
+ case "offer":
20
+ case "answer": return typeof t.sdp == "string" && t.sdp.length > 0;
21
+ case "ice": return Array.isArray(t.c) && t.c.length <= i && t.c.every((e) => e === null || e && typeof e.candidate == "string");
22
+ case "turn": return [
23
+ "key_request",
24
+ "key_reply",
25
+ "proposal",
26
+ "prepare",
27
+ "prepared",
28
+ "commit",
29
+ "committed",
30
+ "done",
31
+ "reject",
32
+ "reconnect"
33
+ ].includes(t.op) ? ["key_request", "key_reply"].includes(t.op) ? typeof t.publicKey == "string" && /^[A-Za-z0-9+/=]{80,100}$/.test(t.publicKey) : ["proposal", "prepare"].includes(t.op) ? typeof t.iv == "string" && /^[A-Za-z0-9+/=]{16}$/.test(t.iv) && typeof t.cipher == "string" && t.cipher.length <= 8200 && /^[A-Za-z0-9+/=]+$/.test(t.cipher) : t.recreate !== void 0 && typeof t.recreate != "boolean" ? !1 : t.reason === void 0 || [
34
+ "busy",
35
+ "invalid",
36
+ "expired",
37
+ "unavailable",
38
+ "timeout"
39
+ ].includes(t.reason) : !1;
40
+ case "ack": return typeof t.of == "string" && r.test(t.of);
41
+ default: return !0;
42
+ }
43
+ };
44
+ function s(e) {
45
+ return !!e && typeof e == "object" && e.v === 1 && n.includes(e.t) && typeof e.sid == "string" && r.test(e.sid) && typeof e.mid == "string" && r.test(e.mid) && typeof e.from == "string" && r.test(e.from) && (e.to == null || typeof e.to == "string" && r.test(e.to)) && Number.isInteger(e.gen ?? 0) && (e.gen ?? 0) >= 0 && (e.at == null || Number.isFinite(e.at)) && o(e.t, e.d);
46
+ }
47
+ function c(t) {
48
+ let n = e + JSON.stringify({
49
+ v: 1,
50
+ ...t
51
+ });
52
+ return n.length <= 1e4 ? n : null;
53
+ }
54
+ function l(e) {
55
+ if (!a(e) || e.length > 1e4) return null;
56
+ try {
57
+ let t = JSON.parse(e.slice(15));
58
+ return s(t) ? t : null;
59
+ } catch {
60
+ return null;
61
+ }
62
+ }
63
+ var u = () => {
64
+ try {
65
+ if (globalThis.crypto?.randomUUID) return globalThis.crypto.randomUUID().replace(/-/g, "").slice(0, 20);
66
+ } catch {}
67
+ return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 12)}`;
68
+ }, d = 8, f = 16, p = 512, m = 172800, h = (e) => typeof e == "object" && !!e && !Array.isArray(e), g = (e, t) => Object.prototype.hasOwnProperty.call(e, t), _ = (e) => {
69
+ throw Error(e);
70
+ }, v = (e) => typeof e == "string" && e.trim().length > 0 && e.length <= p && !/[\u0000-\u001f\u007f]/.test(e);
71
+ function y(e) {
72
+ if (h(e) || Array.isArray(e)) for (let [t, n] of Object.entries(e)) /^(?:api[_-]?(?:token|key|secret)|authorization|bearer|token|secret|secret[_-]?key|access[_-]?token|refresh[_-]?token|turn[_-]?key[_-]?api[_-]?token)$/i.test(t) && _("No pegues tokens API ni secretos permanentes. Utiliza solamente credenciales TURN temporales."), y(n);
73
+ }
74
+ function b(e) {
75
+ if (e.startsWith("[")) try {
76
+ return e.endsWith("]") && new URL(`http://${e}/`).hostname.startsWith("[");
77
+ } catch {
78
+ return !1;
79
+ }
80
+ return e.length > 253 ? !1 : /^[\d.]+$/.test(e) ? e.split(".").length === 4 && e.split(".").every((e) => /^(?:0|[1-9]\d{0,2})$/.test(e) && Number(e) <= 255) : e.split(".").every((e) => /^[a-z\d](?:[a-z\d-]{0,61}[a-z\d])?$/i.test(e));
81
+ }
82
+ function x(e) {
83
+ (typeof e != "string" || e.length > 512 || /\s/.test(e)) && _("Hay una URL ICE inválida. Usa URLs stun:, stuns:, turn: o turns:.");
84
+ let t = /^(stun|stuns|turn|turns):((?:\[[a-f\d:.]+\])|(?:[a-z\d.-]+))(?::(\d{1,5}))?(?:\?transport=(udp|tcp))?$/i.exec(e);
85
+ return (!t || !b(t[2]) || t[3] !== void 0 && (Number(t[3]) < 1 || Number(t[3]) > 65535) || t[4] && !/^turns?$/i.test(t[1])) && _("Hay una URL ICE inválida. Revisa el servidor, puerto y transporte UDP o TCP."), /^turns?$/i.test(t[1]);
86
+ }
87
+ function S(e, t) {
88
+ let n = [];
89
+ if (g(e, "expiresAt") && e.expiresAt !== null) {
90
+ let t = typeof e.expiresAt == "string" ? Date.parse(e.expiresAt) : e.expiresAt;
91
+ Number.isSafeInteger(t) && Number.isFinite(new Date(t).getTime()) || _("La fecha de expiración no es válida."), n.push(t);
92
+ }
93
+ for (let r of ["expiresIn", "ttl"]) {
94
+ if (!g(e, r) || e[r] === null) continue;
95
+ let i = e[r];
96
+ (!Number.isInteger(i) || i < 1 || i > m) && _("El TTL debe estar entre 1 y 172800 segundos."), n.push(t + i * 1e3);
97
+ }
98
+ return n;
99
+ }
100
+ function C(e, { ttlSeconds: t, now: n = Date.now() } = {}) {
101
+ Number.isSafeInteger(n) && Number.isFinite(new Date(n).getTime()) || _("No se pudo comprobar la vigencia de la configuración.");
102
+ let r;
103
+ try {
104
+ r = typeof e == "string" ? e : JSON.stringify(e);
105
+ } catch {
106
+ _("La configuración debe ser un objeto JSON válido.");
107
+ }
108
+ typeof r == "string" && r.trim() || _("Pega la configuración JSON de TURN."), (r.length > 6e3 || new TextEncoder().encode(r).length > 6e3) && _("La configuración es demasiado grande (máximo 6000 caracteres).");
109
+ let i;
110
+ try {
111
+ i = JSON.parse(r);
112
+ } catch {
113
+ _("El JSON no es válido. Copia la respuesta completa de credenciales TURN.");
114
+ }
115
+ h(i) || _("La configuración debe contener un objeto iceServers.");
116
+ let a = [[i, 0]];
117
+ for (; a.length;) {
118
+ let [e, t] = a.pop();
119
+ if (t > 8 && _("La configuración JSON contiene demasiados niveles."), h(e) || Array.isArray(e)) for (let n of Object.values(e)) n && typeof n == "object" && a.push([n, t + 1]);
120
+ }
121
+ y(i), i.success === !1 && _("La respuesta del proveedor indica un error. Obtén credenciales TURN válidas.");
122
+ let o = h(i.result) ? i.result : i;
123
+ (!Array.isArray(o.iceServers) || o.iceServers.length < 1 || o.iceServers.length > d) && _("iceServers debe contener entre 1 y 8 servidores ICE.");
124
+ let s = 0, c = !1, l = o.iceServers.map((e) => {
125
+ h(e) || _("Cada servidor ICE debe ser un objeto con URLs válidas.");
126
+ let t = typeof e.urls == "string" ? [e.urls] : e.urls;
127
+ (!Array.isArray(t) || !t.length || t.length > f) && _("Cada servidor debe incluir al menos una URL ICE válida."), s += t.length, s > f && _("La configuración admite hasta 16 URLs ICE.");
128
+ let n = t.map(x).some(Boolean), r = { urls: [...new Set(t)] };
129
+ return n && (c = !0, v(e.username) && v(e.credential) || _("Cada servidor TURN necesita username y credential temporales válidos."), e.credentialType !== void 0 && e.credentialType !== "password" && _("Solo se admiten credenciales TURN de tipo password."), r.username = e.username, r.credential = e.credential), r;
130
+ });
131
+ c || _("La configuración solo contiene STUN. Incluye al menos un servidor TURN con sus credenciales.");
132
+ let u = [...S(i, n), ...o === i ? [] : S(o, n)];
133
+ t != null && t !== "" && ((!Number.isInteger(t) || t < 1 || t > m) && _("El TTL debe estar entre 1 y 172800 segundos."), u.push(n + t * 1e3));
134
+ let p = u.length ? Math.min(...u) : null;
135
+ p !== null && !Number.isFinite(new Date(p).getTime()) && _("La fecha de expiración no es válida."), p !== null && p <= n && _("Las credenciales TURN han expirado. Genera y pega una configuración nueva.");
136
+ let g = {
137
+ iceServers: l,
138
+ expiresAt: p
139
+ };
140
+ return new TextEncoder().encode(JSON.stringify(g)).length > 6e3 && _("La configuración es demasiado grande para compartirla de forma segura."), g;
141
+ }
142
+ // src/net/webrtc/manualTurnSharing.js
143
+ var w = /^[a-z\d_-]{4,64}$/i, T = 32, E = "No se pudo sincronizar la conexión alternativa. Revisa las credenciales e inténtalo de nuevo.", D = {
144
+ busy: "El otro jugador ya está configurando una conexión alternativa. Espera a que termine.",
145
+ timeout: "El otro jugador no confirmó la configuración a tiempo. Mantengan abierta la partida e inténtalo de nuevo.",
146
+ expired: "Las credenciales TURN han expirado. Genera y pega una configuración nueva.",
147
+ unavailable: "No se pudo preparar el intercambio seguro. Usa HTTPS y mantén abierta la partida.",
148
+ invalid: E
149
+ }, O = (e) => btoa(String.fromCharCode(...new Uint8Array(e))), k = (e, t) => {
150
+ if (typeof e != "string" || e.length > t || e.length % 4 || !/^[a-z\d+/]+={0,2}$/i.test(e)) throw Error(E);
151
+ return Uint8Array.from(atob(e), (e) => e.charCodeAt(0));
152
+ }, A = (e) => {
153
+ if (e !== "all" && e !== "relay") throw Error("La política ICE debe ser all o relay.");
154
+ return e;
155
+ };
156
+ function ee({ authority: e, selfId: t, peerId: n, roomId: r, tabId: i, sendSignal: a, applyConfig: o, commitConfig: s, onChange: c = () => {}, ensurePeer: l, cryptoImpl: u = globalThis.crypto, timeoutMs: d = 2e4 }) {
157
+ t = String(t), n = String(n), r = String(r);
158
+ let f = null, p = null, m = !1, h = Promise.resolve(), g = /* @__PURE__ */ new Map(), _ = {
159
+ status: "idle",
160
+ shared: !1,
161
+ received: !1,
162
+ expiresAt: null,
163
+ error: null
164
+ }, v = (e) => {
165
+ _ = {
166
+ ..._,
167
+ ...e
168
+ }, m || c({ ..._ });
169
+ }, y = (e) => !m && p === e && !e.closed, b = () => {
170
+ if (!u?.subtle || !u?.getRandomValues || !w.test(i) || !r || !t || !n || t === n) throw Error(D.unavailable);
171
+ }, x = () => [...u.getRandomValues(/* @__PURE__ */ new Uint8Array(16))].map((e) => e.toString(16).padStart(2, "0")).join(""), S = (e, i, a, o) => new TextEncoder().encode(JSON.stringify([
172
+ r,
173
+ ...[t, n].sort(),
174
+ e.sid,
175
+ i,
176
+ a,
177
+ o
178
+ ])), ee = (e) => {
179
+ g.set(e.sid, {
180
+ peerTab: e.peerTab,
181
+ replies: e.replies
182
+ }), g.size > T && g.delete(g.keys().next().value);
183
+ }, j = (e) => {
184
+ clearTimeout(e.timer), e.closed = !0, e.config = e.keyPair = e.sharedKey = null, p === e && (p = null);
185
+ }, M = (e, t = "invalid", n = !1) => {
186
+ y(e) && (n && e.peerTab && N(e, {
187
+ op: "reject",
188
+ reason: t
189
+ }), ee(e), j(e), v({
190
+ status: "failed",
191
+ error: D[t] || E
192
+ }), e.reject?.(Error(D[t] || E)));
193
+ }, N = (e, t, n) => {
194
+ if (!m && e.peerTab) {
195
+ n && e.replies.set(n, t);
196
+ try {
197
+ let n = a(e.sid, t, e.peerTab);
198
+ n === !1 || n === null ? M(e, "unavailable") : n && typeof n.then == "function" && n.catch(() => M(e, "unavailable"));
199
+ } catch {
200
+ M(e, "unavailable");
201
+ }
202
+ }
203
+ }, te = (e, t, n = null) => {
204
+ let r = {
205
+ sid: e,
206
+ initiatedHere: t,
207
+ peerTab: f,
208
+ config: n,
209
+ stage: "starting",
210
+ replies: /* @__PURE__ */ new Map(),
211
+ keyPair: null,
212
+ sharedKey: null,
213
+ closed: !1,
214
+ timer: null
215
+ };
216
+ return p = r, r.timer = setTimeout(() => M(r, "timeout", !0), d), v({
217
+ status: t && !f ? "waiting_peer" : "sharing",
218
+ shared: !1,
219
+ received: !1,
220
+ expiresAt: n?.expiresAt ?? null,
221
+ error: null
222
+ }), r;
223
+ }, P = (e) => {
224
+ if (!y(e)) return;
225
+ let t = e.config?.expiresAt ?? null;
226
+ ee(e), j(e), v({
227
+ status: "synchronized",
228
+ shared: !0,
229
+ received: _.received,
230
+ expiresAt: t,
231
+ error: null
232
+ }), e.resolve?.({ expiresAt: t });
233
+ }, ne = async (e) => {
234
+ let t = await u.subtle.generateKey({
235
+ name: "ECDH",
236
+ namedCurve: "P-256"
237
+ }, !1, ["deriveKey"]);
238
+ return y(e) ? (e.keyPair = t, e.publicKey = O(await u.subtle.exportKey("raw", t.publicKey)), e.publicKey) : null;
239
+ }, re = async (e, t) => {
240
+ let n = k(t, 100);
241
+ if (n.length !== 65 || n[0] !== 4) throw Error(E);
242
+ let r = await u.subtle.importKey("raw", n, {
243
+ name: "ECDH",
244
+ namedCurve: "P-256"
245
+ }, !1, []), i = await u.subtle.deriveKey({
246
+ name: "ECDH",
247
+ public: r
248
+ }, e.keyPair.privateKey, {
249
+ name: "AES-GCM",
250
+ length: 256
251
+ }, !1, ["encrypt", "decrypt"]);
252
+ y(e) && (e.sharedKey = i);
253
+ }, ie = async (e, t) => {
254
+ if (!e.sharedKey || !e.config) throw Error(E);
255
+ let n = u.getRandomValues(/* @__PURE__ */ new Uint8Array(12)), r = new TextEncoder().encode(JSON.stringify(e.config)), a = await u.subtle.encrypt({
256
+ name: "AES-GCM",
257
+ iv: n,
258
+ additionalData: S(e, i, e.peerTab, t)
259
+ }, e.sharedKey, r);
260
+ return {
261
+ op: t,
262
+ iv: O(n),
263
+ cipher: O(a)
264
+ };
265
+ }, ae = async (e, t) => {
266
+ if (!e.sharedKey) throw Error(E);
267
+ let n = k(t.iv, 20);
268
+ if (n.length !== 12) throw Error(E);
269
+ let r = await u.subtle.decrypt({
270
+ name: "AES-GCM",
271
+ iv: n,
272
+ additionalData: S(e, e.peerTab, i, t.op)
273
+ }, e.sharedKey, k(t.cipher, 8200)), a = JSON.parse(new TextDecoder().decode(r));
274
+ return {
275
+ ...C(a),
276
+ iceTransportPolicy: A(a.iceTransportPolicy)
277
+ };
278
+ }, F = (e) => {
279
+ if (e.config?.expiresAt !== null && e.config?.expiresAt <= Date.now()) throw Error(D.expired);
280
+ }, oe = async (e) => (F(e), v({
281
+ status: "applying",
282
+ expiresAt: e.config.expiresAt
283
+ }), await o(e.config)), se = (e, t) => {
284
+ try {
285
+ let n = a(e.sid, {
286
+ op: "reject",
287
+ reason: t
288
+ }, e.from);
289
+ n?.then && n.catch(() => {});
290
+ } catch {}
291
+ };
292
+ async function ce(t) {
293
+ if (m || !t || !w.test(t.sid) || t.to !== i || t.from !== f || !t.d || typeof t.d != "object") return;
294
+ let n = t.d, r = g.get(t.sid);
295
+ if (r) {
296
+ r.peerTab === t.from && r.replies.has(n.op) && N({
297
+ sid: t.sid,
298
+ peerTab: r.peerTab,
299
+ replies: r.replies
300
+ }, r.replies.get(n.op));
301
+ return;
302
+ }
303
+ let a = p;
304
+ if (n.op === "key_request") {
305
+ if (a && a.sid !== t.sid) {
306
+ if (e || !a.initiatedHere) {
307
+ se(t, "busy");
308
+ return;
309
+ }
310
+ M(a, "busy"), a = null;
311
+ }
312
+ if (a) {
313
+ let e = a.replies.get("key_request");
314
+ e && N(a, e);
315
+ return;
316
+ }
317
+ try {
318
+ if (b(), a = te(t.sid, !1), a.peerTab = t.from, await ne(a), !y(a) || (await re(a, n.publicKey), !y(a))) return;
319
+ a.stage = e ? "await_proposal" : "await_prepare", N(a, {
320
+ op: "key_reply",
321
+ publicKey: a.publicKey
322
+ }, "key_request");
323
+ } catch {
324
+ a ? M(a, "invalid", !0) : se(t, "unavailable");
325
+ }
326
+ } else if (a && a.sid === t.sid && a.peerTab === t.from) try {
327
+ switch (n.op) {
328
+ case "reject":
329
+ M(a, Object.prototype.hasOwnProperty.call(D, n.reason) ? n.reason : "invalid");
330
+ return;
331
+ case "key_reply": {
332
+ if (!a.initiatedHere || a.stage !== "await_key" || (await re(a, n.publicKey), !y(a))) return;
333
+ let t = await ie(a, e ? "prepare" : "proposal");
334
+ if (!y(a)) return;
335
+ a.stage = e ? "await_prepared" : "await_prepare", v({
336
+ status: "sharing",
337
+ shared: !0
338
+ }), N(a, t, "key_reply");
339
+ return;
340
+ }
341
+ case "proposal": {
342
+ if (!e) return;
343
+ if (a.stage !== "await_proposal") {
344
+ let e = a.replies.get("proposal");
345
+ e && N(a, e);
346
+ return;
347
+ }
348
+ if (a.config = await ae(a, n), !y(a)) return;
349
+ v({
350
+ status: "sharing",
351
+ received: !0,
352
+ expiresAt: a.config.expiresAt
353
+ });
354
+ let t = await ie(a, "prepare");
355
+ if (!y(a)) return;
356
+ a.stage = "await_prepared", N(a, t, "proposal");
357
+ return;
358
+ }
359
+ case "prepare": {
360
+ if (e) return;
361
+ if (a.stage !== "await_prepare") {
362
+ let e = a.replies.get("prepare");
363
+ e && N(a, e);
364
+ return;
365
+ }
366
+ if (a.config = await ae(a, n), !y(a)) return;
367
+ v({
368
+ received: !0,
369
+ expiresAt: a.config.expiresAt
370
+ });
371
+ let t = await oe(a);
372
+ if (!y(a)) return;
373
+ a.stage = "await_commit", N(a, {
374
+ op: "prepared",
375
+ recreate: t?.recreate === !0
376
+ }, "prepare");
377
+ return;
378
+ }
379
+ case "prepared":
380
+ if (!e) return;
381
+ if (a.stage !== "await_prepared") {
382
+ let e = a.replies.get("prepared");
383
+ e && N(a, e);
384
+ return;
385
+ }
386
+ if (await oe(a), !y(a)) return;
387
+ a.recreatePeer = n.recreate === !0, a.stage = "await_committed", N(a, { op: "commit" }, "prepared");
388
+ return;
389
+ case "commit":
390
+ if (e) return;
391
+ if (a.stage !== "await_commit") {
392
+ let e = a.replies.get("commit");
393
+ e && N(a, e);
394
+ return;
395
+ }
396
+ F(a), a.stage = "await_done", N(a, { op: "committed" }, "commit");
397
+ return;
398
+ case "committed":
399
+ if (!e || a.stage !== "await_committed" || (F(a), a.stage = "committing", await s({
400
+ iceTransportPolicy: a.config.iceTransportPolicy,
401
+ recreatePeer: a.recreatePeer === !0
402
+ }), !y(a))) return;
403
+ N(a, { op: "done" }, "committed"), P(a);
404
+ return;
405
+ case "done":
406
+ !e && a.stage === "await_done" && P(a);
407
+ return;
408
+ default: return;
409
+ }
410
+ } catch (e) {
411
+ M(a, e?.message === D.expired ? "expired" : "invalid", !0);
412
+ }
413
+ }
414
+ return {
415
+ configure(e, { ttlSeconds: t, iceTransportPolicy: n = "all" } = {}) {
416
+ if (m) return Promise.reject(Error(D.unavailable));
417
+ if (p) return Promise.reject(Error(D.busy));
418
+ let r;
419
+ try {
420
+ b(), r = {
421
+ ...C(e, { ttlSeconds: t }),
422
+ iceTransportPolicy: A(n)
423
+ };
424
+ } catch (e) {
425
+ return v({
426
+ status: "failed",
427
+ error: e.message
428
+ }), Promise.reject(e);
429
+ }
430
+ let i = te(x(), !0, r), a = new Promise((e, t) => {
431
+ i.resolve = e, i.reject = t;
432
+ });
433
+ return (async () => {
434
+ try {
435
+ let e = f || await l?.();
436
+ if (!y(i)) return;
437
+ if (!w.test(e) || f && f !== e) throw Error(D.unavailable);
438
+ f = e, i.peerTab = e;
439
+ let t = await ne(i);
440
+ if (!y(i)) return;
441
+ i.stage = "await_key", v({ status: "sharing" }), N(i, {
442
+ op: "key_request",
443
+ publicKey: t
444
+ });
445
+ } catch {
446
+ M(i, "unavailable", !0);
447
+ }
448
+ })(), a;
449
+ },
450
+ bindPeer(e) {
451
+ !m && e && w.test(e) && (f && f !== e && (p && M(p, "unavailable"), g.clear()), f = e, p && !p.peerTab && (p.peerTab = e));
452
+ },
453
+ handleSignal(e) {
454
+ return h = h.then(() => ce(e)).catch(() => {}), h;
455
+ },
456
+ failTransfer(e) {
457
+ p?.sid === e && M(p, "timeout", !0);
458
+ },
459
+ getState() {
460
+ return { ..._ };
461
+ },
462
+ destroy() {
463
+ if (!m) {
464
+ if (m = !0, p) {
465
+ let e = p;
466
+ j(e), e.reject?.(Error(D.unavailable));
467
+ }
468
+ g.clear(), f = null, _ = {
469
+ status: "idle",
470
+ shared: !1,
471
+ received: !1,
472
+ expiresAt: null,
473
+ error: null
474
+ };
475
+ }
476
+ }
477
+ };
478
+ }
479
+ // src/net/webrtc/createPeerLink.js
480
+ var j = [{ urls: ["stun:stun.l.google.com:19302", "stun:stun.cloudflare.com:3478"] }], M = 1200, N = 6, te = 2e3, P = 3e4, ne = 80, re = 3e3, ie = 2e4, ae = 1e3, F = 1e4, oe = 2, se = 5, ce = 16384, le = 500, ue = () => ({
481
+ sent: 0,
482
+ dropped: 0,
483
+ received: 0,
484
+ firstSeq: null,
485
+ maxSeq: 0,
486
+ outOfOrder: 0,
487
+ lossPct: 0,
488
+ hzIn: 0,
489
+ hzOut: 0,
490
+ windowIn: 0,
491
+ windowOut: 0
492
+ }), de = {
493
+ host: "directa (host)",
494
+ srflx: "directa (NAT vía STUN)",
495
+ prflx: "directa (NAT)",
496
+ relay: "TURN (relay)"
497
+ };
498
+ function I({ signaling: e, selfId: t, peerId: n, roomId: r = null, tabId: i = u(), iceServers: o = j, iceTransportPolicy: s = "all", autoReconnect: d = !0, configurationAuthority: f, listen: p = !0, RTCPeerConnectionImpl: m = globalThis.RTCPeerConnection, onChange: h = () => {}, onMove: g = () => {}, onEvent: _ = () => {}, log: v = () => {} } = {}) {
499
+ if (!e?.send || !e?.subscribe) throw Error("createPeerLink: signaling { send, subscribe } requerido");
500
+ t = String(t), n = String(n);
501
+ let y = o, b = s, x = null, S = null, C = null, w, T = /* @__PURE__ */ new Map(), E = /* @__PURE__ */ new Set(), D = f ?? t < n, O = (e) => (e || []).some((e) => [e.urls].flat().some((e) => /^turns?:/i.test(String(e)))), k = p, A = !1, I = null, L = 0, R = null, fe = null, z = /* @__PURE__ */ new Set(), B = {
502
+ phase: "idle",
503
+ role: null,
504
+ sid: null,
505
+ gen: 0,
506
+ tabId: i,
507
+ peerTab: null,
508
+ ice: "new",
509
+ connection: "new",
510
+ signalingState: "stable",
511
+ gathering: "new",
512
+ route: null,
513
+ rtt: null,
514
+ statsRtt: null,
515
+ reconnects: 0,
516
+ restarts: 0,
517
+ error: null,
518
+ move: ue(),
519
+ signals: {
520
+ sent: 0,
521
+ received: 0,
522
+ sendFailures: 0,
523
+ retransmits: 0,
524
+ duplicates: 0,
525
+ ignored: 0,
526
+ invalid: 0,
527
+ tooLarge: 0,
528
+ maxLength: 0
529
+ },
530
+ events: {
531
+ sent: 0,
532
+ received: 0
533
+ },
534
+ turnConfigured: O(y),
535
+ manualTurn: {
536
+ status: "idle",
537
+ shared: !1,
538
+ received: !1,
539
+ expiresAt: null,
540
+ error: null
541
+ },
542
+ candidates: {
543
+ local: 0,
544
+ remote: 0,
545
+ accepted: 0,
546
+ rejected: 0,
547
+ localRelay: 0,
548
+ remoteRelay: 0
549
+ },
550
+ iceErrors: [],
551
+ channels: {
552
+ move: "closed",
553
+ events: "closed"
554
+ },
555
+ startedAt: null,
556
+ connectedAt: null
557
+ }, V = () => {
558
+ A || h(pe());
559
+ }, pe = () => ({
560
+ ...B,
561
+ route: B.route && { ...B.route },
562
+ move: { ...B.move },
563
+ signals: { ...B.signals },
564
+ events: { ...B.events },
565
+ manualTurn: { ...B.manualTurn },
566
+ candidates: { ...B.candidates },
567
+ iceErrors: B.iceErrors.map((e) => ({ ...e })),
568
+ channels: {
569
+ move: I?.move?.readyState ?? "closed",
570
+ events: I?.events?.readyState ?? "closed"
571
+ },
572
+ elapsedMs: B.startedAt == null ? 0 : Math.max(0, (B.connectedAt ?? Date.now()) - B.startedAt)
573
+ }), H = (e, t = null) => {
574
+ B.phase = e, B.error = t, v(`fase: ${e}${t ? ` (${t})` : ""}`), V();
575
+ }, U = (t) => {
576
+ let n = () => (A || (B.signals.sendFailures += 1, V()), !1);
577
+ try {
578
+ return Promise.resolve(e.send(t)).then((e) => e !== !1 || n(), n);
579
+ } catch {
580
+ return Promise.resolve(n());
581
+ }
582
+ }, W = (e, t, n, { to: r = e?.peerTab ?? null, reliable: a = !0, gen: o = e?.gen ?? 0, sid: s = e?.sid } = {}) => {
583
+ let l = u(), d = c({
584
+ t,
585
+ sid: s,
586
+ gen: o,
587
+ mid: l,
588
+ at: Date.now(),
589
+ from: i,
590
+ to: r,
591
+ d: n ?? void 0
592
+ });
593
+ if (!d) return B.signals.tooLarge += 1, v(`señal ${t} supera el límite y no se envía`), e && J(e, "signal_too_large"), null;
594
+ if (B.signals.sent += 1, B.signals.maxLength = Math.max(B.signals.maxLength, d.length), U(d), a && e) {
595
+ let n = {
596
+ text: d,
597
+ tries: 1,
598
+ timer: null,
599
+ gen: o,
600
+ peerTab: r,
601
+ sid: s
602
+ }, i = () => {
603
+ !e.closed && e.outbox.has(l) && (n.tries >= N ? (e.outbox.delete(l), v(`señal ${t} sin ACK tras ${N} intentos`), t !== "bye" && J(e, "signal_timeout")) : (n.tries += 1, B.signals.retransmits += 1, U(d), n.timer = setTimeout(i, M)));
604
+ };
605
+ n.timer = setTimeout(i, M), e.outbox.set(l, n);
606
+ }
607
+ return l;
608
+ }, me = (e) => !z.has(e) && (z.add(e), z.size > le && z.delete(z.values().next().value), !0), he = (e) => {
609
+ if (A || !e || !a(e.text) || r != null && e.roomId && String(e.roomId) !== String(r)) return;
610
+ let t = l(e.text);
611
+ if (!t) B.signals.invalid += 1;
612
+ else if (String(e.userId) !== n || t.from === i || t.to && t.to !== i) B.signals.ignored += 1;
613
+ else if (t.t === "turn" && (t.to !== i || t.from !== S)) B.signals.ignored += 1;
614
+ else if (B.signals.received += 1, t.t !== "hello" && t.t !== "ack" && W(null, "ack", { of: t.mid }, {
615
+ to: t.from,
616
+ reliable: !1,
617
+ sid: t.sid,
618
+ gen: t.gen
619
+ }), !me(`${t.from}:${t.mid}`)) B.signals.duplicates += 1, V();
620
+ else {
621
+ switch (t.t) {
622
+ case "ack":
623
+ Fe(t);
624
+ break;
625
+ case "hello":
626
+ Ie(t);
627
+ break;
628
+ case "ready":
629
+ Le(t);
630
+ break;
631
+ case "offer":
632
+ Re(t);
633
+ break;
634
+ case "answer":
635
+ ze(t);
636
+ break;
637
+ case "ice":
638
+ Be(t);
639
+ break;
640
+ case "bye":
641
+ Ve(t);
642
+ break;
643
+ case "turn": t.d.op === "reconnect" ? D && t.sid === C && B.phase !== "connected" && !q() && $() : w.handleSignal(t);
644
+ }
645
+ I && t.sid === I.sid && t.from === I.peerTab && t.at && (I.peerAt = Math.max(I.peerAt, t.at));
646
+ }
647
+ }, ge = (e, t, n) => {
648
+ if (A || !n || n !== S) return null;
649
+ let r = u(), a = c({
650
+ t: "turn",
651
+ sid: e,
652
+ gen: 0,
653
+ mid: r,
654
+ at: Date.now(),
655
+ from: i,
656
+ to: n,
657
+ d: t
658
+ });
659
+ if (!a) throw Error("La configuración es demasiado grande para compartir.");
660
+ let o = {
661
+ sid: e,
662
+ peerTab: n,
663
+ text: a,
664
+ tries: 1,
665
+ timer: null
666
+ }, s = () => {
667
+ !A && T.has(r) && (o.tries >= N ? (G(e), w.failTransfer(e)) : (o.tries++, B.signals.retransmits++, U(a), o.timer = setTimeout(s, M)));
668
+ };
669
+ return T.set(r, o), B.signals.sent++, B.signals.maxLength = Math.max(B.signals.maxLength, a.length), U(a), o.timer = setTimeout(s, M), V(), r;
670
+ }, G = (e) => {
671
+ for (let [t, n] of T) e && n.sid !== e || (clearTimeout(n.timer), T.delete(t));
672
+ }, _e = (e, t) => {
673
+ S && S !== e && G(), S = e, C = t, w.bindPeer(e);
674
+ for (let t of E) clearTimeout(t.timer), t.resolve(e);
675
+ E.clear();
676
+ };
677
+ w = ee({
678
+ authority: D,
679
+ selfId: t,
680
+ peerId: n,
681
+ roomId: r,
682
+ tabId: i,
683
+ sendSignal: ge,
684
+ applyConfig: ({ iceServers: e, iceTransportPolicy: t, expiresAt: n }) => {
685
+ if (A || n != null && n <= Date.now()) throw Error("Las credenciales TURN han expirado.");
686
+ y = e, b = t, x = n, B.turnConfigured = O(e);
687
+ let r = I;
688
+ if (r?.pc && !r.closed) try {
689
+ if (typeof r.pc.setConfiguration != "function") throw Error("unsupported");
690
+ r.pc.setConfiguration({
691
+ iceServers: e,
692
+ iceTransportPolicy: t
693
+ }), r.recreateForConfig = !1;
694
+ } catch {
695
+ r.recreateForConfig = !0;
696
+ }
697
+ return V(), { recreate: !!r?.recreateForConfig };
698
+ },
699
+ commitConfig: ({ recreatePeer: e = !1 } = {}) => {
700
+ if (A || !D) return;
701
+ if (x != null && x <= Date.now()) throw Error("Las credenciales TURN han expirado.");
702
+ let t = I, n = B.phase === "connected" && ["connected", "completed"].includes(t?.pc?.iceConnectionState) && t?.move?.readyState === "open" && t?.events?.readyState === "open";
703
+ t && (t.deferredRestart = !1), (!n || b !== "all" || t.recreateForConfig || e) && (clearTimeout(R), R = null, t && !t.closed && !t.recreateForConfig && !e && t.role === "caller" && t.pc?.signalingState === "stable" ? (t.restarts = 0, X(t, { manualCommit: !0 })) : $());
704
+ },
705
+ ensurePeer: () => S ? Promise.resolve(S) : new Promise((e, t) => {
706
+ let n = {
707
+ resolve: e,
708
+ reject: t,
709
+ timer: null
710
+ };
711
+ n.timer = setTimeout(() => {
712
+ E.delete(n), t(/* @__PURE__ */ Error("El otro jugador no está disponible. Abre la partida en ambos dispositivos."));
713
+ }, P), E.add(n), D && !I && $();
714
+ }),
715
+ onChange(e) {
716
+ B.manualTurn = e, [
717
+ "waiting_peer",
718
+ "sharing",
719
+ "applying"
720
+ ].includes(e.status) ? (clearTimeout(R), R = null, I && (clearTimeout(I.connectTimer), clearTimeout(I.disconnectTimer))) : ["failed", "synchronized"].includes(e.status) && !A && (I?.deferredRestart && (I.deferredRestart = !1, X(I)), B.phase !== "connected" && (I ? Y(I) : D && be(B.error ?? "connection_recovery"))), V();
721
+ }
722
+ });
723
+ let ve = e.subscribe(he), ye = (e, t = u(), n = null) => ({
724
+ role: e,
725
+ sid: t,
726
+ peerTab: n,
727
+ gen: 0,
728
+ localGen: 0,
729
+ remoteGen: -1,
730
+ makingOffer: !1,
731
+ pc: null,
732
+ move: null,
733
+ events: null,
734
+ closed: !1,
735
+ outbox: /* @__PURE__ */ new Map(),
736
+ pendingIce: [],
737
+ localIce: [],
738
+ iceTimer: null,
739
+ helloTimer: null,
740
+ helloStarted: Date.now(),
741
+ disconnectTimer: null,
742
+ connectTimer: null,
743
+ pingTimer: null,
744
+ statsTimer: null,
745
+ tickTimer: null,
746
+ lastSeen: Date.now(),
747
+ pingSeq: 0,
748
+ moveSeq: 0,
749
+ restarts: 0,
750
+ open: 0,
751
+ peerAt: 0
752
+ }), K = (e, { bye: t = !1, recover: n = !1 } = {}) => {
753
+ if (e && !e.closed) {
754
+ if (t && e.peerTab && W(e, "bye", n ? { recover: !0 } : null, { reliable: !1 }), e.closed = !0, [
755
+ e.iceTimer,
756
+ e.disconnectTimer,
757
+ e.connectTimer
758
+ ].forEach((e) => clearTimeout(e)), [
759
+ e.helloTimer,
760
+ e.pingTimer,
761
+ e.statsTimer,
762
+ e.tickTimer
763
+ ].forEach((e) => clearInterval(e)), e.outbox.forEach((e) => clearTimeout(e.timer)), e.outbox.clear(), [e.move, e.events].forEach((e) => {
764
+ if (e) {
765
+ e.onopen = e.onclose = e.onmessage = e.onerror = null;
766
+ try {
767
+ e.close();
768
+ } catch {}
769
+ }
770
+ }), e.pc) {
771
+ e.pc.onicecandidate = e.pc.oniceconnectionstatechange = e.pc.onconnectionstatechange = null, e.pc.onsignalingstatechange = e.pc.onicegatheringstatechange = e.pc.onicecandidateerror = null;
772
+ try {
773
+ e.pc.close();
774
+ } catch {}
775
+ }
776
+ I === e && (I = null);
777
+ }
778
+ }, q = () => [
779
+ "waiting_peer",
780
+ "sharing",
781
+ "applying"
782
+ ].includes(B.manualTurn.status), be = (e) => {
783
+ if (q()) {
784
+ H("reconnecting", e);
785
+ return;
786
+ }
787
+ if (A || !d || R) return;
788
+ if (L >= se) {
789
+ H("failed", `${e}; sin más reintentos`);
790
+ return;
791
+ }
792
+ let t = Math.min(8e3, 1e3 * 2 ** L);
793
+ L += 1, B.reconnects = L, H("reconnecting", e), R = setTimeout(() => {
794
+ R = null, !A && !I && $();
795
+ }, t);
796
+ }, J = (e, t) => {
797
+ if (e.closed) return;
798
+ let n = e.role === "caller";
799
+ fe = e.sid, K(e, {
800
+ bye: !0,
801
+ recover: !0
802
+ }), n ? be(t) : H(k ? "listening" : "idle", t);
803
+ }, xe = (e) => {
804
+ B.role = e.role, B.sid = e.sid, B.gen = e.gen, B.peerTab = e.peerTab, B.ice = "new", B.connection = "new", B.signalingState = "stable", B.gathering = "new", B.route = null, B.rtt = null, B.statsRtt = null, B.restarts = 0, B.move = ue(), B.connectedAt = null, B.startedAt ?? (B.startedAt = Date.now());
805
+ }, Y = (e) => {
806
+ clearTimeout(e.connectTimer), e.connectTimer = setTimeout(() => {
807
+ e.closed || e.move?.readyState === "open" && e.events?.readyState === "open" && ["connected", "completed"].includes(e.pc?.iceConnectionState) || J(e, "connect_timeout");
808
+ }, ie);
809
+ }, Se = (e) => {
810
+ if (!m) return J(e, "webrtc_unavailable"), null;
811
+ let t;
812
+ try {
813
+ t = new m({
814
+ iceServers: y,
815
+ iceTransportPolicy: b
816
+ });
817
+ } catch {
818
+ return J(e, "peer_creation_failed"), null;
819
+ }
820
+ return e.pc = t, t.onicecandidate = ({ candidate: n }) => {
821
+ if (e.closed) return;
822
+ let r = n?.usernameFragment, i = /^a=ice-ufrag:(.+)$/m.exec(t.localDescription?.sdp ?? "")?.[1]?.trim();
823
+ r && i && r !== i || (n && (B.candidates.local++, / typ relay(?: |$)/.test(n.candidate ?? "") && B.candidates.localRelay++), e.localIce.length >= 128 && Ce(e), e.localIce.push({
824
+ gen: e.localGen,
825
+ candidate: n ? n.toJSON?.() ?? n : null
826
+ }), e.iceTimer || (e.iceTimer = setTimeout(() => Ce(e), ne)));
827
+ }, t.onicecandidateerror = (t) => {
828
+ e.closed || (B.iceErrors = [...B.iceErrors.slice(-9), {
829
+ code: Number(t.errorCode) || 0,
830
+ stage: "gathering"
831
+ }], V());
832
+ }, t.onicegatheringstatechange = () => {
833
+ B.gathering = t.iceGatheringState, V();
834
+ }, t.onsignalingstatechange = () => {
835
+ B.signalingState = t.signalingState, V();
836
+ }, t.onconnectionstatechange = () => {
837
+ B.connection = t.connectionState, V();
838
+ }, t.oniceconnectionstatechange = () => Oe(e), e.move = t.createDataChannel("move", {
839
+ negotiated: !0,
840
+ id: 0,
841
+ ordered: !1,
842
+ maxRetransmits: 0
843
+ }), e.events = t.createDataChannel("events", {
844
+ negotiated: !0,
845
+ id: 1,
846
+ ordered: !0
847
+ }), [e.move, e.events].forEach((t) => {
848
+ t.onopen = () => ke(e), t.onclose = () => {
849
+ !e.closed && B.phase === "connected" && Ae(e, "canal cerrado");
850
+ };
851
+ }), e.move.onmessage = (t) => Ne(e, t.data), e.events.onmessage = (t) => Me(e, t.data), Y(e), t;
852
+ }, Ce = (e) => {
853
+ if (clearTimeout(e.iceTimer), e.iceTimer = null, e.closed || !e.localIce.length) return;
854
+ let t = /* @__PURE__ */ new Map();
855
+ for (let n of e.localIce.splice(0)) t.has(n.gen) || t.set(n.gen, []), t.get(n.gen).push(n.candidate);
856
+ for (let [n, r] of t) for (let t = 0; t < r.length; t += 16) W(e, "ice", { c: r.slice(t, t + 16) }, { gen: n });
857
+ }, we = async (e, t) => {
858
+ for (let n of t) try {
859
+ if (e.closed) return;
860
+ await e.pc.addIceCandidate(n), n && B.candidates.accepted++, V();
861
+ } catch {
862
+ B.candidates.rejected++, B.iceErrors = [...B.iceErrors.slice(-9), {
863
+ code: 0,
864
+ stage: "remote_candidate"
865
+ }], V();
866
+ }
867
+ }, Te = (e) => {
868
+ let t = e.pendingIce.filter((t) => t.gen === e.gen);
869
+ e.pendingIce = e.pendingIce.filter((t) => t.gen > e.gen), t.forEach((t) => void we(e, t.c));
870
+ }, Ee = async (e, t = !1) => {
871
+ if (!(e.closed || e.makingOffer)) {
872
+ e.makingOffer = !0;
873
+ try {
874
+ let n = await e.pc.createOffer(t ? { iceRestart: !0 } : void 0);
875
+ if (e.closed || (await e.pc.setLocalDescription(n), e.closed)) return;
876
+ e.localGen = e.gen, W(e, "offer", { sdp: e.pc.localDescription.sdp });
877
+ } catch {
878
+ J(e, "offer_failed");
879
+ } finally {
880
+ e.makingOffer = !1;
881
+ }
882
+ }
883
+ }, X = (e, { manualCommit: t = !1 } = {}) => {
884
+ q() && !t ? e.deferredRestart = !0 : e.closed || e.role !== "caller" || e.makingOffer || e.pc?.signalingState !== "stable" || (x != null && x <= Date.now() ? J(e, "turn_credentials_expired") : e.restarts >= oe ? Ae(e, "ICE no se recupera") : (Ce(e), e.restarts += 1, B.restarts = e.restarts, e.gen += 1, B.gen = e.gen, B.connectedAt = null, B.route = null, Y(e), H("restarting"), Ee(e, !0)));
885
+ }, De = (e) => {
886
+ !e.closed && I === e && ["connected", "completed"].includes(e.pc?.iceConnectionState) && e.move?.readyState === "open" && e.events?.readyState === "open" && (clearTimeout(e.connectTimer), B.phase !== "connected" && (B.connectedAt = Date.now(), H("connected")));
887
+ }, Oe = (e) => {
888
+ if (e.closed) return;
889
+ let t = e.pc.iceConnectionState;
890
+ B.ice = t, clearTimeout(e.disconnectTimer), t === "connected" || t === "completed" ? (De(e), Q(e)) : t === "disconnected" ? (B.phase === "connected" && H("reconnecting"), q() || Y(e), e.disconnectTimer = setTimeout(() => X(e), re)) : t === "failed" && (B.phase === "connected" && H("reconnecting", "ice_failed"), q() || Y(e), X(e)), V();
891
+ }, ke = (e) => {
892
+ e.closed || e.move?.readyState !== "open" || e.events?.readyState !== "open" || e.open !== 2 && (e.open = 2, B.connectedAt = Date.now(), clearTimeout(e.connectTimer), L = 0, e.lastSeen = Date.now(), e.pingTimer = setInterval(() => je(e), ae), e.statsTimer = setInterval(() => void Q(e), 2e3), e.tickTimer = setInterval(() => Pe(e), 1e3), H("connected"), Q(e));
893
+ }, Ae = (e, t) => J(e, t), je = (e) => {
894
+ if (Date.now() - e.lastSeen > F) {
895
+ if (q()) {
896
+ e.deferredRestart = !0;
897
+ return;
898
+ }
899
+ Ae(e, "heartbeat_timeout");
900
+ } else Z(e.events, JSON.stringify({
901
+ k: "ping",
902
+ n: ++e.pingSeq,
903
+ ts: performance.now()
904
+ }));
905
+ }, Z = (e, t) => {
906
+ if (e?.readyState !== "open") return !1;
907
+ try {
908
+ return e.send(t), !0;
909
+ } catch {
910
+ return !1;
911
+ }
912
+ }, Me = (e, t) => {
913
+ e.lastSeen = Date.now();
914
+ let n;
915
+ try {
916
+ n = JSON.parse(t);
917
+ } catch {
918
+ return;
919
+ }
920
+ n?.k === "ping" ? Z(e.events, JSON.stringify({
921
+ k: "pong",
922
+ ts: n.ts
923
+ })) : n?.k === "pong" ? B.rtt = Math.round((performance.now() - n.ts) * 10) / 10 : n?.k === "app" && (B.events.received += 1, _(n.d));
924
+ }, Ne = (e, t) => {
925
+ e.lastSeen = Date.now();
926
+ let n;
927
+ try {
928
+ n = JSON.parse(t);
929
+ } catch {
930
+ return;
931
+ }
932
+ if (!Array.isArray(n) || !Number.isInteger(n[0])) return;
933
+ let [r, , i] = n, a = B.move;
934
+ a.received += 1, a.windowIn += 1, a.firstSeq ?? (a.firstSeq = r), r < a.maxSeq ? a.outOfOrder += 1 : (a.maxSeq = r, g(i, { seq: r }));
935
+ }, Pe = (e) => {
936
+ let t = B.move;
937
+ t.hzIn = t.windowIn, t.hzOut = t.windowOut, t.windowIn = 0, t.windowOut = 0;
938
+ let n = t.firstSeq == null ? 0 : t.maxSeq - t.firstSeq + 1;
939
+ t.lossPct = n > 0 ? Math.max(0, Math.round((1 - t.received / n) * 1e3) / 10) : 0, e.closed || V();
940
+ }, Q = async (e) => {
941
+ if (!e.closed && e.pc?.getStats) try {
942
+ let t = await e.pc.getStats(), n = /* @__PURE__ */ new Map();
943
+ t.forEach((e) => n.set(e.id, e));
944
+ let r = null;
945
+ if (t.forEach((e) => {
946
+ e.type === "transport" && e.selectedCandidatePairId && (r = n.get(e.selectedCandidatePairId));
947
+ }), r || t.forEach((e) => {
948
+ e.type === "candidate-pair" && (e.selected || e.nominated) && e.state === "succeeded" && (r = e);
949
+ }), !r) return;
950
+ let i = n.get(r.localCandidateId), a = n.get(r.remoteCandidateId), o = i?.candidateType === "relay" || a?.candidateType === "relay", s = o ? "relay" : i?.candidateType ?? "host";
951
+ B.route = {
952
+ local: i?.candidateType ?? null,
953
+ remote: a?.candidateType ?? null,
954
+ protocol: i?.protocol ?? null,
955
+ relayProtocol: i?.relayProtocol ?? null,
956
+ relay: o,
957
+ label: de[s] ?? s
958
+ }, typeof r.currentRoundTripTime == "number" && (B.statsRtt = Math.round(r.currentRoundTripTime * 1e4) / 10), V();
959
+ } catch {}
960
+ }, Fe = (e) => {
961
+ let t = T.get(e.d.of);
962
+ if (t && t.sid === e.sid && t.peerTab === e.from && e.to === i) {
963
+ clearTimeout(t.timer), T.delete(e.d.of);
964
+ return;
965
+ }
966
+ if (I?.sid !== e.sid || I?.peerTab !== e.from) return;
967
+ let n = I?.outbox.get(e.d.of);
968
+ n && n.gen !== e.gen || n && (clearTimeout(n.timer), I.outbox.delete(e.d.of));
969
+ }, Ie = (e) => {
970
+ if (I && I.sid === e.sid) return;
971
+ if (I?.peerTab && I.peerTab !== e.from) {
972
+ B.signals.ignored++;
973
+ return;
974
+ }
975
+ if (I && I.peerTab === e.from && (e.at ?? 0) <= I.peerAt) return;
976
+ let t = I?.role === "caller" && !I.peerTab;
977
+ if (t && i < e.from) return;
978
+ if (!k && !t) {
979
+ B.signals.ignored += 1;
980
+ return;
981
+ }
982
+ I && K(I, {
983
+ bye: !t,
984
+ recover: !0
985
+ });
986
+ let n = ye("answerer", e.sid, e.from);
987
+ I = n, xe(n), _e(e.from, n.sid), Se(n) && (W(n, "ready", null), H("negotiating"));
988
+ }, Le = (e) => {
989
+ let t = I;
990
+ t && t.role === "caller" && t.sid === e.sid && (t.peerTab && t.peerTab !== e.from ? W(t, "bye", null, {
991
+ to: e.from,
992
+ reliable: !1
993
+ }) : t.peerTab || (t.peerTab = e.from, B.peerTab = e.from, _e(e.from, t.sid), clearInterval(t.helloTimer), Se(t) && (H("negotiating"), Ee(t))));
994
+ }, Re = async (e) => {
995
+ let t = I;
996
+ if (!(!t || t.role !== "answerer" || t.sid !== e.sid || t.peerTab !== e.from || e.gen < t.gen)) {
997
+ e.gen > t.gen && (B.route = null, B.connectedAt = null, Y(t), H("restarting")), t.gen = e.gen, B.gen = t.gen;
998
+ try {
999
+ if (await t.pc.setRemoteDescription({
1000
+ type: "offer",
1001
+ sdp: e.d.sdp
1002
+ }), t.closed) return;
1003
+ t.remoteGen = e.gen, Te(t);
1004
+ let n = await t.pc.createAnswer();
1005
+ if (t.closed || (await t.pc.setLocalDescription(n), t.closed)) return;
1006
+ t.localGen = t.gen, W(t, "answer", { sdp: t.pc.localDescription.sdp }), De(t);
1007
+ } catch {
1008
+ J(t, "answer_failed");
1009
+ }
1010
+ }
1011
+ }, ze = async (e) => {
1012
+ let t = I;
1013
+ if (t && t.role === "caller" && t.sid === e.sid && t.peerTab === e.from && e.gen === t.gen && t.pc.signalingState === "have-local-offer") try {
1014
+ if (await t.pc.setRemoteDescription({
1015
+ type: "answer",
1016
+ sdp: e.d.sdp
1017
+ }), t.closed) return;
1018
+ t.remoteGen = e.gen, Te(t), De(t);
1019
+ } catch {
1020
+ J(t, "remote_answer_failed");
1021
+ }
1022
+ }, Be = (e) => {
1023
+ let t = I;
1024
+ if (!(!t || t.sid !== e.sid || t.peerTab !== e.from || e.gen < t.gen)) {
1025
+ if (B.candidates.remote += e.d.c.filter(Boolean).length, B.candidates.remoteRelay += e.d.c.filter((e) => / typ relay(?: |$)/.test(e?.candidate ?? "")).length, e.gen > t.gen || t.remoteGen !== e.gen || !t.pc?.remoteDescription) {
1026
+ if (t.pendingIce.length >= 64) {
1027
+ J(t, "candidate_queue_full");
1028
+ return;
1029
+ }
1030
+ t.pendingIce.push({
1031
+ gen: e.gen,
1032
+ c: e.d.c
1033
+ }), V();
1034
+ } else we(t, e.d.c);
1035
+ }
1036
+ }, Ve = (e) => {
1037
+ if (e.d?.recover === !0) {
1038
+ let t = I;
1039
+ if (!t || t.sid !== e.sid || t.peerTab !== e.from) return;
1040
+ let n = f === void 0 ? t.role === "caller" : D;
1041
+ fe = t.sid, K(t), n ? be("peer_restarting") : H(k ? "listening" : "idle");
1042
+ return;
1043
+ }
1044
+ if (e.sid === fe && (R || I?.role === "caller" && !I.peerTab)) {
1045
+ clearTimeout(R), R = null, L = 0, I && K(I), H(k ? "listening" : "idle", "el rival cerró la conexión");
1046
+ return;
1047
+ }
1048
+ let t = I;
1049
+ t && t.sid === e.sid && (t.peerTab && t.peerTab !== e.from || (K(t), H(k ? "listening" : "idle", "el rival cerró la conexión")));
1050
+ };
1051
+ function $() {
1052
+ if (A) return;
1053
+ if (clearTimeout(R), R = null, I && K(I, {
1054
+ bye: !0,
1055
+ recover: !0
1056
+ }), x != null && x <= Date.now()) {
1057
+ H("failed", "turn_credentials_expired");
1058
+ return;
1059
+ }
1060
+ let e = ye("caller");
1061
+ I = e, xe(e), H("calling");
1062
+ let t = () => {
1063
+ e.closed || e.peerTab || (Date.now() - e.helloStarted > P ? (K(e), H("failed", "el rival no respondió")) : W(e, "hello", null, {
1064
+ to: null,
1065
+ reliable: !1
1066
+ }));
1067
+ };
1068
+ t(), e.helloTimer = setInterval(t, te);
1069
+ }
1070
+ return k && H("listening"), {
1071
+ tabId: i,
1072
+ configureTurn(e, t) {
1073
+ return w.configure(e, t);
1074
+ },
1075
+ clearManualTurn() {
1076
+ w.destroy(), G(), y = o, b = s, x = null;
1077
+ try {
1078
+ I?.pc?.setConfiguration?.({
1079
+ iceServers: [],
1080
+ iceTransportPolicy: "all"
1081
+ });
1082
+ } catch {}
1083
+ B.manualTurn = {
1084
+ status: "idle",
1085
+ shared: !1,
1086
+ received: !1,
1087
+ expiresAt: null,
1088
+ error: null
1089
+ }, B.turnConfigured = O(o), V();
1090
+ },
1091
+ requestReconnect() {
1092
+ A || B.phase === "connected" || (f === !1 && S && C ? ge(C, { op: "reconnect" }, S) : (L = 0, $()));
1093
+ },
1094
+ connect() {
1095
+ L = 0, $();
1096
+ },
1097
+ setListening(e) {
1098
+ k = !!e, I || H(k ? "listening" : "idle");
1099
+ },
1100
+ sendMove(e) {
1101
+ let t = I;
1102
+ if (!t || t.move?.readyState !== "open") return !1;
1103
+ if (t.move.bufferedAmount > ce) return B.move.dropped += 1, !1;
1104
+ let n = Z(t.move, JSON.stringify([
1105
+ ++t.moveSeq,
1106
+ Date.now(),
1107
+ e
1108
+ ]));
1109
+ return n && (B.move.sent += 1, B.move.windowOut += 1), n;
1110
+ },
1111
+ sendEvent(e) {
1112
+ let t = Z(I?.events, JSON.stringify({
1113
+ k: "app",
1114
+ d: e
1115
+ }));
1116
+ return t && (B.events.sent += 1), t;
1117
+ },
1118
+ restartIce() {
1119
+ I && X(I);
1120
+ },
1121
+ getState: pe,
1122
+ hangup() {
1123
+ clearTimeout(R), R = null, I && K(I, { bye: !0 }), H(k ? "listening" : "idle");
1124
+ },
1125
+ destroy() {
1126
+ if (!A) {
1127
+ clearTimeout(R), I && K(I, { bye: !0 }), A = !0, w.destroy(), G(), y = [], x = null;
1128
+ for (let e of E) clearTimeout(e.timer), e.reject(/* @__PURE__ */ Error("La partida terminó."));
1129
+ E.clear(), ve?.();
1130
+ }
1131
+ }
1132
+ };
1133
+ }
1134
+ export { e as a, a as c, t as i, I as n, l as o, C as r, c as s, j as t };
1135
+
1136
+ //# sourceMappingURL=createPeerLink-DBVs_yvQ.js.map