@minicode-dev/chat 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{BattleshipGameCard-BFqA0cjT.js → BattleshipGameCard-iRk8d4vR.js} +2 -2
- package/dist/chunks/{BattleshipGameCard-BFqA0cjT.js.map → BattleshipGameCard-iRk8d4vR.js.map} +1 -1
- package/dist/chunks/{ChatContext-dty_KPDX.js → ChatContext-DjIEifGY.js} +2 -2
- package/dist/chunks/{ChatContext-dty_KPDX.js.map → ChatContext-DjIEifGY.js.map} +1 -1
- package/dist/chunks/{TanksGameCard-D0n-lzTs.js → TanksGameCard-B47ZQcSr.js} +4 -4
- package/dist/chunks/{TanksGameCard-D0n-lzTs.js.map → TanksGameCard-B47ZQcSr.js.map} +1 -1
- package/dist/chunks/{TanksLiveGameCard-BmNRXP66.js → TanksLiveGameCard-BxQGR8P9.js} +264 -216
- package/dist/chunks/TanksLiveGameCard-BxQGR8P9.js.map +1 -0
- package/dist/chunks/{WebRtcLab-B7xBlJy1.js → WebRtcLab-lijo_Rta.js} +2 -2
- package/dist/chunks/{WebRtcLab-B7xBlJy1.js.map → WebRtcLab-lijo_Rta.js.map} +1 -1
- package/dist/chunks/{connect4Sounds-BN7d_TM2.js → connect4Sounds-Cv0q31VW.js} +527 -517
- package/dist/chunks/connect4Sounds-Cv0q31VW.js.map +1 -0
- package/dist/chunks/{createLiveScene-CtYPcOPo.js → createLiveScene-GkalLsqm.js} +2 -2
- package/dist/chunks/{createLiveScene-CtYPcOPo.js.map → createLiveScene-GkalLsqm.js.map} +1 -1
- package/dist/chunks/{createPeerLink-qei05vpV.js → createPeerLink-CL7VZuHS.js} +5 -3
- package/dist/chunks/createPeerLink-CL7VZuHS.js.map +1 -0
- package/dist/chunks/{tanksSounds-C99OD2xD.js → tanksSounds-CUNDIOal.js} +3 -3
- package/dist/chunks/{tanksSounds-C99OD2xD.js.map → tanksSounds-CUNDIOal.js.map} +1 -1
- package/dist/index.js +1626 -1559
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunks/TanksLiveGameCard-BmNRXP66.js.map +0 -1
- package/dist/chunks/connect4Sounds-BN7d_TM2.js.map +0 -1
- package/dist/chunks/createPeerLink-qei05vpV.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createPeerLink-qei05vpV.js","names":["WEBRTC_PREFIX","MAX_SIGNAL_LENGTH","SIGNAL_TYPES","ID","MAX_CANDIDATES","isWebrtcMessage","text","validData","d","t","c","isValidSignal","signal","encodeSignal","decodeSignal","newSignalId","DEFAULT_ICE_SERVERS","RETRY_MS","MAX_TRIES","HELLO_EVERY_MS","HELLO_GIVE_UP_MS","ICE_BATCH_MS","DISCONNECTED_GRACE_MS","CONNECT_TIMEOUT_MS","PING_EVERY_MS","HEARTBEAT_TIMEOUT_MS","MAX_RESTARTS","MAX_RECONNECTS","MAX_BUFFERED","MAX_SEEN","emptyMoveStats","ROUTE_LABELS","createPeerLink","signaling","selfId","peerId","listening","listen","destroyed","session","reconnects","reconnectTimer","endedSid","seen","state","emit","onChange","snapshot","setPhase","phase","error","log","rawSend","sendSignal","s","mid","tabId","fail","reliable","entry","retry","remember","key","unsubscribe","frame","roomId","newSession","teardown","bye","timer","channel","scheduleReconnect","autoReconnect","reason","delay","call","wasCaller","bindState","createPc","RTCPeerConnectionImpl","pc","candidate","flushLocalIce","onIceState","onChannelOpen","lose","onMoveMessage","event","onEventMessage","batch","i","addRemoteIce","candidates","flushPendingIce","ready","item","makeOffer","offer","iceRestart","restartIce","ice","refreshStats","ping","tick","sendRaw","message","data","onEvent","packet","seq","payload","m","onMove","expected","report","byId","pair","local","remote","relay","type","onAck","onHello","glare","onReady","onOffer","answer","onAnswer","onIce","onBye","hello","value","sent"],"sources":["../../src/net/webrtc/protocol.js","../../src/net/webrtc/createPeerLink.js"],"sourcesContent":["// WebRTC signaling frames carried inside ordinary CHAT_MESSAGE text, the same idea\n// as LIRA_GAME_V1:. The chat backend only relays them; the sender is the\n// server-stamped user_id of the envelope, never a field of the payload.\n//\n// LIRA_WEBRTC_V1:{\"v\":1,\"t\":\"offer\",\"sid\":\"…\",\"gen\":0,\"mid\":\"…\",\"from\":\"tab\",\"to\":\"tab\",\"d\":{…}}\n//\n// t: hello (call, to = null) | ready (reply to hello) | offer | answer | ice | ack | bye\n// sid: session id chosen by the caller; gen: negotiation round (ICE restarts);\n// mid: message id for ACK/dedupe; from/to: tab ids, so several tabs of one user\n// and the server echo to the sender are told apart; at: sender clock (ms), only\n// compared with earlier frames of the same tab to spot late, stale calls.\n\nexport const WEBRTC_PREFIX = 'LIRA_WEBRTC_V1:';\n// Backend limit for CHAT_MESSAGE.message (Django audit). Frames above it are refused locally.\nexport const MAX_SIGNAL_LENGTH = 10000;\nexport const SIGNAL_TYPES = ['hello', 'ready', 'offer', 'answer', 'ice', 'ack', 'bye'];\n\nconst ID = /^[A-Za-z0-9_-]{4,64}$/;\nconst MAX_CANDIDATES = 32;\n\nexport const isWebrtcMessage = (text) => typeof text === 'string' && text.startsWith(WEBRTC_PREFIX);\n\nconst validData = (t, d) => {\n if (d == null) return ['hello', 'ready', 'ack', 'bye'].includes(t);\n if (typeof d !== 'object' || Array.isArray(d)) return false;\n switch (t) {\n case 'offer':\n case 'answer':\n return typeof d.sdp === 'string' && d.sdp.length > 0;\n case 'ice':\n return Array.isArray(d.c) && d.c.length <= MAX_CANDIDATES\n && d.c.every((c) => c === null || (c && typeof c.candidate === 'string'));\n case 'ack':\n return typeof d.of === 'string' && ID.test(d.of);\n default:\n return true;\n }\n};\n\nexport function isValidSignal(signal) {\n return Boolean(signal) && typeof signal === 'object'\n && signal.v === 1\n && SIGNAL_TYPES.includes(signal.t)\n && typeof signal.sid === 'string' && ID.test(signal.sid)\n && typeof signal.mid === 'string' && ID.test(signal.mid)\n && typeof signal.from === 'string' && ID.test(signal.from)\n && (signal.to == null || (typeof signal.to === 'string' && ID.test(signal.to)))\n && Number.isInteger(signal.gen ?? 0) && (signal.gen ?? 0) >= 0\n && (signal.at == null || Number.isFinite(signal.at))\n && validData(signal.t, signal.d);\n}\n\n/** Returns the frame text, or null when it would exceed MAX_SIGNAL_LENGTH. */\nexport function encodeSignal(signal) {\n const text = WEBRTC_PREFIX + JSON.stringify({ v: 1, ...signal });\n return text.length <= MAX_SIGNAL_LENGTH ? text : null;\n}\n\nexport function decodeSignal(text) {\n if (!isWebrtcMessage(text) || text.length > MAX_SIGNAL_LENGTH) return null;\n try {\n const signal = JSON.parse(text.slice(WEBRTC_PREFIX.length));\n return isValidSignal(signal) ? signal : null;\n } catch {\n return null;\n }\n}\n\nexport const newSignalId = () => {\n try {\n if (globalThis.crypto?.randomUUID) return globalThis.crypto.randomUUID().replace(/-/g, '').slice(0, 20);\n } catch { /* fallback below */ }\n return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 12)}`;\n};\n\n// Normalizes a chat frame (flat or nested in data/payload) to { userId, roomId, text }.\nexport function readChatFrame(frame) {\n if (!frame || typeof frame !== 'object') return null;\n const nested = frame.data ?? frame.payload;\n const body = nested && typeof nested === 'object' ? { ...nested, ...frame } : frame;\n const text = frame.message ?? frame.text ?? nested?.message ?? nested?.text;\n if (typeof text !== 'string') return null;\n return { userId: String(body.user_id ?? ''), roomId: String(body.room_id ?? ''), text };\n}\n","// One WebRTC link between two chat users, signaled through the chat itself.\n//\n// Signaling: LIRA_WEBRTC_V1: frames (protocol.js) sent as ordinary CHAT_MESSAGE\n// text in the users' private room. The relay echoes frames to every tab of both\n// users, may duplicate them after a reconnect and gives no delivery guarantee, so:\n// - frames carry tab ids (from/to): own echoes and other tabs are ignored;\n// - every frame except hello/ack is ACKed and retransmitted until ACKed;\n// - duplicates are dropped by message id; ICE that arrives before its\n// description waits in a queue; stale sessions/generations are ignored.\n// Session: caller sends hello (repeated until answered); the first tab of the\n// peer that answers ready is bound, gets the offer and the others a bye.\n// Simultaneous calls resolve by tab id (the lower one keeps calling).\n//\n// Data: two negotiated DataChannels (no ondatachannel race):\n// move id 0, unordered, maxRetransmits 0 — latest position wins;\n// events id 1, ordered and reliable — pings, hits, game events.\n// Recovery: ICE 'failed' (or 'disconnected' for 3 s) triggers an ICE restart by\n// the caller; no traffic for HEARTBEAT_TIMEOUT_MS ends the session and the caller\n// starts a new one (autoReconnect, with backoff).\n\nimport { encodeSignal, decodeSignal, isWebrtcMessage, newSignalId } from './protocol.js';\n\nexport const DEFAULT_ICE_SERVERS = [{ urls: ['stun:stun.l.google.com:19302', 'stun:stun.cloudflare.com:3478'] }];\n\nconst RETRY_MS = 1200;\nconst MAX_TRIES = 6;\nconst HELLO_EVERY_MS = 2000;\nconst HELLO_GIVE_UP_MS = 30000;\nconst ICE_BATCH_MS = 80;\nconst DISCONNECTED_GRACE_MS = 3000;\nconst CONNECT_TIMEOUT_MS = 20000;\nconst PING_EVERY_MS = 1000;\nconst HEARTBEAT_TIMEOUT_MS = 10000;\nconst MAX_RESTARTS = 2;\nconst MAX_RECONNECTS = 5;\nconst MAX_BUFFERED = 16 * 1024;\nconst MAX_SEEN = 500;\n\nconst emptyMoveStats = () => ({ sent: 0, dropped: 0, received: 0, firstSeq: null, maxSeq: 0, outOfOrder: 0, lossPct: 0, hzIn: 0, hzOut: 0, windowIn: 0, windowOut: 0 });\n\nconst ROUTE_LABELS = { host: 'directa (red local)', srflx: 'directa (NAT vía STUN)', prflx: 'directa (NAT)', relay: 'TURN (relay)' };\n\nexport function createPeerLink({\n signaling,\n selfId,\n peerId,\n roomId = null,\n tabId = newSignalId(),\n iceServers = DEFAULT_ICE_SERVERS,\n iceTransportPolicy = 'all',\n autoReconnect = true,\n listen = true,\n RTCPeerConnectionImpl = globalThis.RTCPeerConnection,\n onChange = () => {},\n onMove = () => {},\n onEvent = () => {},\n log = () => {},\n} = {}) {\n if (!signaling?.send || !signaling?.subscribe) throw new Error('createPeerLink: signaling { send, subscribe } requerido');\n selfId = String(selfId);\n peerId = String(peerId);\n\n let listening = listen;\n let destroyed = false;\n let session = null;\n let reconnects = 0;\n let reconnectTimer = null;\n let endedSid = null; // last session that ended without the peer's bye\n const seen = new Set();\n const state = {\n phase: 'idle', role: null, sid: null, gen: 0, tabId, peerTab: null,\n ice: 'new', connection: 'new', signalingState: 'stable', gathering: 'new',\n route: null, rtt: null, statsRtt: null, reconnects: 0, restarts: 0, error: null,\n move: emptyMoveStats(),\n signals: { sent: 0, received: 0, retransmits: 0, duplicates: 0, ignored: 0, invalid: 0, tooLarge: 0, maxLength: 0 },\n events: { sent: 0, received: 0 },\n };\n\n const emit = () => { if (!destroyed) onChange(snapshot()); };\n const snapshot = () => ({ ...state, move: { ...state.move }, signals: { ...state.signals }, events: { ...state.events } });\n const setPhase = (phase, error = null) => {\n state.phase = phase;\n state.error = error;\n log(`fase: ${phase}${error ? ` (${error})` : ''}`);\n emit();\n };\n\n // ---- signaling --------------------------------------------------------\n\n const rawSend = (text) => {\n try {\n return Promise.resolve(signaling.send(text)).then(() => true, () => false);\n } catch {\n return Promise.resolve(false);\n }\n };\n\n const sendSignal = (s, t, d, { to = s?.peerTab ?? null, reliable = true, gen = s?.gen ?? 0, sid = s?.sid } = {}) => {\n const mid = newSignalId();\n const text = encodeSignal({ t, sid, gen, mid, at: Date.now(), from: tabId, to, d: d ?? undefined });\n if (!text) {\n state.signals.tooLarge += 1;\n log(`señal ${t} supera el límite y no se envía`);\n if (s) fail(s, 'signal_too_large');\n return null;\n }\n state.signals.sent += 1;\n state.signals.maxLength = Math.max(state.signals.maxLength, text.length);\n void rawSend(text);\n if (reliable && s) {\n const entry = { text, tries: 1, timer: null };\n const retry = () => {\n if (s.closed || !s.outbox.has(mid)) return;\n if (entry.tries >= MAX_TRIES) {\n s.outbox.delete(mid);\n log(`señal ${t} sin ACK tras ${MAX_TRIES} intentos`);\n if (t !== 'bye') fail(s, 'signal_timeout');\n return;\n }\n entry.tries += 1;\n state.signals.retransmits += 1;\n void rawSend(text);\n entry.timer = setTimeout(retry, RETRY_MS);\n };\n entry.timer = setTimeout(retry, RETRY_MS);\n s.outbox.set(mid, entry);\n }\n return mid;\n };\n\n const remember = (key) => {\n if (seen.has(key)) return false;\n seen.add(key);\n if (seen.size > MAX_SEEN) seen.delete(seen.values().next().value);\n return true;\n };\n\n const handleFrame = (frame) => {\n if (destroyed || !frame || !isWebrtcMessage(frame.text)) return;\n if (roomId != null && frame.roomId && String(frame.roomId) !== String(roomId)) return;\n const signal = decodeSignal(frame.text);\n if (!signal) { state.signals.invalid += 1; return; }\n // Own echoes, own other tabs and third parties never drive this link.\n if (String(frame.userId) !== peerId || signal.from === tabId || (signal.to && signal.to !== tabId)) {\n state.signals.ignored += 1;\n return;\n }\n state.signals.received += 1;\n if (signal.t !== 'hello' && signal.t !== 'ack') {\n // ACK even duplicates: the first ACK may be the one that got lost.\n sendSignal(null, 'ack', { of: signal.mid }, { to: signal.from, reliable: false, sid: signal.sid, gen: signal.gen });\n }\n if (!remember(`${signal.from}:${signal.mid}`)) { state.signals.duplicates += 1; emit(); return; }\n switch (signal.t) {\n case 'ack': onAck(signal); break;\n case 'hello': onHello(signal); break;\n case 'ready': onReady(signal); break;\n case 'offer': void onOffer(signal); break;\n case 'answer': void onAnswer(signal); break;\n case 'ice': onIce(signal); break;\n case 'bye': onBye(signal); break;\n default: break;\n }\n // After dispatch, so the frame that binds the peer tab (hello/ready) counts too.\n if (session && signal.sid === session.sid && signal.from === session.peerTab && signal.at) {\n session.peerAt = Math.max(session.peerAt, signal.at);\n }\n };\n\n const unsubscribe = signaling.subscribe(handleFrame);\n\n // ---- session lifecycle ------------------------------------------------\n\n const newSession = (role, sid = newSignalId(), peerTab = null) => ({\n role, sid, peerTab, gen: 0, pc: null, move: null, events: null, closed: false,\n outbox: new Map(), pendingIce: [], localIce: [], iceTimer: null, helloTimer: null, helloStarted: Date.now(),\n disconnectTimer: null, connectTimer: null, pingTimer: null, statsTimer: null, tickTimer: null,\n lastSeen: Date.now(), pingSeq: 0, moveSeq: 0, restarts: 0, open: 0, peerAt: 0,\n });\n\n const teardown = (s, { bye = false } = {}) => {\n if (!s || s.closed) return;\n if (bye && s.peerTab) sendSignal(s, 'bye', null, { reliable: false });\n s.closed = true;\n [s.iceTimer, s.disconnectTimer, s.connectTimer].forEach((timer) => clearTimeout(timer));\n [s.helloTimer, s.pingTimer, s.statsTimer, s.tickTimer].forEach((timer) => clearInterval(timer));\n s.outbox.forEach((entry) => clearTimeout(entry.timer));\n s.outbox.clear();\n [s.move, s.events].forEach((channel) => {\n if (!channel) return;\n channel.onopen = channel.onclose = channel.onmessage = channel.onerror = null;\n try { channel.close(); } catch { /* already closed */ }\n });\n if (s.pc) {\n s.pc.onicecandidate = s.pc.oniceconnectionstatechange = s.pc.onconnectionstatechange = null;\n s.pc.onsignalingstatechange = s.pc.onicegatheringstatechange = null;\n try { s.pc.close(); } catch { /* already closed */ }\n }\n if (session === s) session = null;\n };\n\n const scheduleReconnect = (reason) => {\n if (destroyed || !autoReconnect || reconnectTimer) return;\n if (reconnects >= MAX_RECONNECTS) { setPhase('failed', `${reason}; sin más reintentos`); return; }\n const delay = Math.min(8000, 1000 * 2 ** reconnects);\n reconnects += 1;\n state.reconnects = reconnects;\n setPhase('reconnecting', reason);\n reconnectTimer = setTimeout(() => { reconnectTimer = null; if (!destroyed && !session) call(); }, delay);\n };\n\n const fail = (s, reason) => {\n if (s.closed) return;\n const wasCaller = s.role === 'caller';\n endedSid = s.sid;\n teardown(s, { bye: true });\n if (wasCaller) scheduleReconnect(reason);\n else setPhase(listening ? 'listening' : 'idle', reason);\n };\n\n const bindState = (s) => {\n state.role = s.role;\n state.sid = s.sid;\n state.gen = s.gen;\n state.peerTab = s.peerTab;\n state.ice = 'new';\n state.connection = 'new';\n state.signalingState = 'stable';\n state.gathering = 'new';\n state.route = null;\n state.rtt = null;\n state.statsRtt = null;\n state.restarts = 0;\n state.move = emptyMoveStats();\n };\n\n // ---- peer connection --------------------------------------------------\n\n const createPc = (s) => {\n if (!RTCPeerConnectionImpl) { fail(s, 'webrtc_unavailable'); return null; }\n const pc = new RTCPeerConnectionImpl({ iceServers, iceTransportPolicy });\n s.pc = pc;\n pc.onicecandidate = ({ candidate }) => {\n if (s.closed) return;\n s.localIce.push(candidate ? candidate.toJSON?.() ?? candidate : null);\n if (!s.iceTimer) s.iceTimer = setTimeout(() => flushLocalIce(s), ICE_BATCH_MS);\n };\n pc.onicegatheringstatechange = () => { state.gathering = pc.iceGatheringState; emit(); };\n pc.onsignalingstatechange = () => { state.signalingState = pc.signalingState; emit(); };\n pc.onconnectionstatechange = () => { state.connection = pc.connectionState; emit(); };\n pc.oniceconnectionstatechange = () => onIceState(s);\n s.move = pc.createDataChannel('move', { negotiated: true, id: 0, ordered: false, maxRetransmits: 0 });\n s.events = pc.createDataChannel('events', { negotiated: true, id: 1, ordered: true });\n [s.move, s.events].forEach((channel) => {\n channel.onopen = () => onChannelOpen(s);\n channel.onclose = () => { if (!s.closed && state.phase === 'connected') lose(s, 'canal cerrado'); };\n });\n s.move.onmessage = (event) => onMoveMessage(s, event.data);\n s.events.onmessage = (event) => onEventMessage(s, event.data);\n s.connectTimer = setTimeout(() => { if (state.phase !== 'connected') fail(s, 'connect_timeout'); }, CONNECT_TIMEOUT_MS);\n return pc;\n };\n\n const flushLocalIce = (s) => {\n s.iceTimer = null;\n if (s.closed || !s.localIce.length) return;\n const batch = s.localIce.splice(0, s.localIce.length);\n for (let i = 0; i < batch.length; i += 16) sendSignal(s, 'ice', { c: batch.slice(i, i + 16) });\n };\n\n const addRemoteIce = async (s, candidates) => {\n for (const candidate of candidates) {\n try {\n if (candidate) await s.pc.addIceCandidate(candidate);\n } catch (error) {\n log(`ICE remoto rechazado: ${error?.message ?? error}`);\n }\n }\n };\n\n const flushPendingIce = (s) => {\n const ready = s.pendingIce.filter((item) => item.gen === s.gen);\n s.pendingIce = s.pendingIce.filter((item) => item.gen > s.gen);\n ready.forEach((item) => void addRemoteIce(s, item.c));\n };\n\n const makeOffer = async (s, iceRestart = false) => {\n try {\n const offer = await s.pc.createOffer(iceRestart ? { iceRestart: true } : undefined);\n if (s.closed) return;\n await s.pc.setLocalDescription(offer);\n if (s.closed) return;\n sendSignal(s, 'offer', { sdp: s.pc.localDescription.sdp });\n } catch (error) {\n fail(s, `offer: ${error?.message ?? error}`);\n }\n };\n\n const restartIce = (s) => {\n if (s.closed || s.role !== 'caller') return;\n if (s.restarts >= MAX_RESTARTS) { lose(s, 'ICE no se recupera'); return; }\n s.restarts += 1;\n state.restarts = s.restarts;\n s.gen += 1;\n state.gen = s.gen;\n setPhase('restarting');\n void makeOffer(s, true);\n };\n\n const onIceState = (s) => {\n if (s.closed) return;\n const ice = s.pc.iceConnectionState;\n state.ice = ice;\n clearTimeout(s.disconnectTimer);\n if (ice === 'connected' || ice === 'completed') {\n if (state.phase === 'restarting') setPhase('connected');\n void refreshStats(s);\n } else if (ice === 'disconnected') {\n s.disconnectTimer = setTimeout(() => restartIce(s), DISCONNECTED_GRACE_MS);\n } else if (ice === 'failed') {\n restartIce(s);\n }\n emit();\n };\n\n const onChannelOpen = (s) => {\n s.open += 1;\n if (s.open < 2 || s.closed) return;\n clearTimeout(s.connectTimer);\n reconnects = 0;\n s.lastSeen = Date.now();\n s.pingTimer = setInterval(() => ping(s), PING_EVERY_MS);\n s.statsTimer = setInterval(() => void refreshStats(s), 2000);\n s.tickTimer = setInterval(() => tick(s), 1000);\n setPhase('connected');\n void refreshStats(s);\n };\n\n // A session that stops hearing the peer is over; the caller starts a new one.\n const lose = (s, reason) => fail(s, reason);\n\n // ---- data -------------------------------------------------------------\n\n const ping = (s) => {\n if (Date.now() - s.lastSeen > HEARTBEAT_TIMEOUT_MS) { lose(s, 'sin latido del rival'); return; }\n sendRaw(s.events, JSON.stringify({ k: 'ping', n: ++s.pingSeq, ts: performance.now() }));\n };\n\n const sendRaw = (channel, text) => {\n if (channel?.readyState !== 'open') return false;\n try { channel.send(text); return true; } catch { return false; }\n };\n\n const onEventMessage = (s, data) => {\n s.lastSeen = Date.now();\n let message;\n try { message = JSON.parse(data); } catch { return; }\n if (message?.k === 'ping') sendRaw(s.events, JSON.stringify({ k: 'pong', ts: message.ts }));\n else if (message?.k === 'pong') { state.rtt = Math.round((performance.now() - message.ts) * 10) / 10; }\n else if (message?.k === 'app') { state.events.received += 1; onEvent(message.d); }\n };\n\n const onMoveMessage = (s, data) => {\n s.lastSeen = Date.now();\n let packet;\n try { packet = JSON.parse(data); } catch { return; }\n if (!Array.isArray(packet) || !Number.isInteger(packet[0])) return;\n const [seq, , payload] = packet;\n const m = state.move;\n m.received += 1;\n m.windowIn += 1;\n if (m.firstSeq == null) m.firstSeq = seq;\n if (seq < m.maxSeq) { m.outOfOrder += 1; return; } // stale position: counted, not applied\n m.maxSeq = seq;\n onMove(payload, { seq });\n };\n\n const tick = (s) => {\n const m = state.move;\n m.hzIn = m.windowIn;\n m.hzOut = m.windowOut;\n m.windowIn = 0;\n m.windowOut = 0;\n const expected = m.firstSeq == null ? 0 : m.maxSeq - m.firstSeq + 1;\n m.lossPct = expected > 0 ? Math.max(0, Math.round((1 - m.received / expected) * 1000) / 10) : 0;\n if (!s.closed) emit();\n };\n\n const refreshStats = async (s) => {\n if (s.closed || !s.pc?.getStats) return;\n try {\n const report = await s.pc.getStats();\n const byId = new Map();\n report.forEach((entry) => byId.set(entry.id, entry));\n let pair = null;\n report.forEach((entry) => {\n if (entry.type === 'transport' && entry.selectedCandidatePairId) pair = byId.get(entry.selectedCandidatePairId);\n });\n if (!pair) report.forEach((entry) => { if (entry.type === 'candidate-pair' && (entry.selected || entry.nominated) && entry.state === 'succeeded') pair = entry; });\n if (!pair) return;\n const local = byId.get(pair.localCandidateId);\n const remote = byId.get(pair.remoteCandidateId);\n const relay = local?.candidateType === 'relay' || remote?.candidateType === 'relay';\n const type = relay ? 'relay' : (local?.candidateType ?? 'host');\n state.route = {\n local: local?.candidateType ?? null,\n remote: remote?.candidateType ?? null,\n protocol: local?.protocol ?? null,\n relay,\n label: ROUTE_LABELS[type] ?? type,\n };\n if (typeof pair.currentRoundTripTime === 'number') state.statsRtt = Math.round(pair.currentRoundTripTime * 10000) / 10;\n emit();\n } catch { /* stats are optional */ }\n };\n\n // ---- signal handlers ----------------------------------------------------\n\n const onAck = (signal) => {\n const entry = session?.outbox.get(signal.d.of);\n if (!entry) return;\n clearTimeout(entry.timer);\n session.outbox.delete(signal.d.of);\n };\n\n const onHello = (signal) => {\n if (session && session.sid === signal.sid) return;\n // A late hello from a call the bound tab already dropped (glare, reorder).\n if (session && session.peerTab === signal.from && (signal.at ?? 0) <= session.peerAt) return;\n const glare = session?.role === 'caller' && !session.peerTab;\n // Both called at once: the lower tab id keeps calling, the other answers.\n if (glare && tabId < signal.from) return;\n if (!listening && !glare) { state.signals.ignored += 1; return; }\n // Otherwise the peer started over (reload, lost session): the new call replaces ours.\n if (session) teardown(session, { bye: !glare });\n const s = newSession('answerer', signal.sid, signal.from);\n session = s;\n bindState(s);\n if (!createPc(s)) return;\n sendSignal(s, 'ready', null);\n setPhase('negotiating');\n };\n\n const onReady = (signal) => {\n const s = session;\n if (!s || s.role !== 'caller' || s.sid !== signal.sid) return;\n if (s.peerTab && s.peerTab !== signal.from) {\n // Another tab of the peer answered later: release it.\n sendSignal(s, 'bye', null, { to: signal.from, reliable: false });\n return;\n }\n if (s.peerTab) return;\n s.peerTab = signal.from;\n state.peerTab = signal.from;\n clearInterval(s.helloTimer);\n if (!createPc(s)) return;\n setPhase('negotiating');\n void makeOffer(s);\n };\n\n const onOffer = async (signal) => {\n const s = session;\n if (!s || s.role !== 'answerer' || s.sid !== signal.sid || s.peerTab !== signal.from || signal.gen < s.gen) return;\n s.gen = signal.gen;\n state.gen = s.gen;\n try {\n await s.pc.setRemoteDescription({ type: 'offer', sdp: signal.d.sdp });\n if (s.closed) return;\n flushPendingIce(s);\n const answer = await s.pc.createAnswer();\n if (s.closed) return;\n await s.pc.setLocalDescription(answer);\n if (s.closed) return;\n sendSignal(s, 'answer', { sdp: s.pc.localDescription.sdp });\n } catch (error) {\n fail(s, `answer: ${error?.message ?? error}`);\n }\n };\n\n const onAnswer = async (signal) => {\n const s = session;\n if (!s || s.role !== 'caller' || s.sid !== signal.sid || s.peerTab !== signal.from || signal.gen !== s.gen) return;\n if (s.pc.signalingState !== 'have-local-offer') return;\n try {\n await s.pc.setRemoteDescription({ type: 'answer', sdp: signal.d.sdp });\n if (s.closed) return;\n flushPendingIce(s);\n // An ICE restart over a working path may never leave 'connected'.\n if (state.phase === 'restarting' && ['connected', 'completed'].includes(s.pc.iceConnectionState)) setPhase('connected');\n } catch (error) {\n fail(s, `answer remota: ${error?.message ?? error}`);\n }\n };\n\n const onIce = (signal) => {\n const s = session;\n if (!s || s.sid !== signal.sid || s.peerTab !== signal.from || signal.gen < s.gen) return;\n if (signal.gen > s.gen || !s.pc?.remoteDescription) {\n s.pendingIce.push({ gen: signal.gen, c: signal.d.c }); // arrived before its offer/answer\n return;\n }\n void addRemoteIce(s, signal.d.c);\n };\n\n const onBye = (signal) => {\n // The channel may close before the bye arrives through the chat: the peer left\n // on purpose, so the reconnection that started meanwhile is cancelled.\n if (signal.sid === endedSid && (reconnectTimer || (session?.role === 'caller' && !session.peerTab))) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n reconnects = 0;\n if (session) teardown(session);\n setPhase(listening ? 'listening' : 'idle', 'el rival cerró la conexión');\n return;\n }\n const s = session;\n if (!s || s.sid !== signal.sid) return;\n if (s.peerTab && s.peerTab !== signal.from) return;\n teardown(s);\n setPhase(listening ? 'listening' : 'idle', 'el rival cerró la conexión');\n };\n\n // ---- public API -------------------------------------------------------\n\n function call() {\n if (destroyed) return;\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n if (session) teardown(session, { bye: true });\n const s = newSession('caller');\n session = s;\n bindState(s);\n setPhase('calling');\n const hello = () => {\n if (s.closed || s.peerTab) return;\n if (Date.now() - s.helloStarted > HELLO_GIVE_UP_MS) {\n teardown(s);\n setPhase('failed', 'el rival no respondió');\n return;\n }\n sendSignal(s, 'hello', null, { to: null, reliable: false });\n };\n hello();\n s.helloTimer = setInterval(hello, HELLO_EVERY_MS);\n }\n\n if (listening) setPhase('listening');\n\n return {\n tabId,\n /** Starts a new session as caller (the peer must be listening). */\n connect() { reconnects = 0; call(); },\n /** Accept (true) or ignore (false) incoming calls. */\n setListening(value) {\n listening = Boolean(value);\n if (!session) setPhase(listening ? 'listening' : 'idle');\n },\n /** Latest-wins position update over the unreliable channel. */\n sendMove(payload) {\n const s = session;\n if (!s || s.move?.readyState !== 'open') return false;\n if (s.move.bufferedAmount > MAX_BUFFERED) { state.move.dropped += 1; return false; }\n const sent = sendRaw(s.move, JSON.stringify([++s.moveSeq, Date.now(), payload]));\n if (sent) { state.move.sent += 1; state.move.windowOut += 1; }\n return sent;\n },\n /** Reliable, ordered game event. */\n sendEvent(payload) {\n const sent = sendRaw(session?.events, JSON.stringify({ k: 'app', d: payload }));\n if (sent) state.events.sent += 1;\n return sent;\n },\n /** Forces an ICE restart (caller) — for tests. */\n restartIce() { if (session) restartIce(session); },\n getState: snapshot,\n /** Ends the session (bye to the peer) but keeps listening. */\n hangup() {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n if (session) teardown(session, { bye: true });\n setPhase(listening ? 'listening' : 'idle');\n },\n /** Full cleanup: session, timers and the signaling subscription. */\n destroy() {\n if (destroyed) return;\n clearTimeout(reconnectTimer);\n if (session) teardown(session, { bye: true });\n destroyed = true;\n unsubscribe?.();\n },\n };\n}\n\nexport default createPeerLink;\n"],"mappings":"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"}
|