const CH = "chat-stream-v1"; let bc, streams = /* @__PURE__ */ new Map(); self.addEventListener("install", (e) => self.skipWaiting()); self.addEventListener("activate", (e) => e.waitUntil(self.clients.claim())); function send(m) { try { bc || (bc = new BroadcastChannel(CH)); bc.postMessage(m); } catch { } } function hint(x) { x = String(x || ""); if (/401|unauthorized/i.test(x)) return "Unauthorized (check API key)."; if (/429|rate/i.test(x)) return "Rate limited (slow down or upgrade)."; if (/403|forbidden|access/i.test(x)) return "Forbidden (model or key scope)."; return "Request failed."; } async function start(id, p) { bc || (bc = new BroadcastChannel(CH)); const body = typeof p.body === "string" ? p.body : JSON.stringify(p.body || {}), ctrl = new AbortController(); let done = false, buf = ""; streams.set(id, { ctrl, buf: () => buf, done: () => done }); try { const r = await fetch(p.url, { method: "POST", headers: p.headers || {}, body, signal: ctrl.signal }); if (!r.ok) throw new Error(await r.text().catch(() => "") || "HTTP " + r.status); const rd = r.body.getReader(), dc = new TextDecoder("utf-8"); let acc = ""; const doneOnce = () => { if (done) return; done = true; send({ t: "done", id }); }; for (; ; ) { const { value, done: d } = await rd.read(); if (d) break; acc += dc.decode(value, { stream: true }); let i; while ((i = acc.indexOf("\n\n")) !== -1) { const raw = acc.slice(0, i).trim(); acc = acc.slice(i + 2); if (!raw || !raw.startsWith("data:")) continue; const data = raw.slice(5).trim(); if (data === "[DONE]") { doneOnce(); continue; } try { const j = JSON.parse(data); const delta = j.choices?.[0]?.delta?.content ?? ""; if (delta) { buf += delta; send({ t: "delta", id, data: delta }); } const fin = j.choices?.[0]?.finish_reason; if (fin) doneOnce(); } catch { } } } doneOnce(); } catch (e) { const aborted = e?.name === "AbortError" || /abort/i.test(String(e?.message || "")); if (aborted) send({ t: "done", id, aborted: true }); else send({ t: "error", id, hint: hint(e?.message) }); } finally { streams.delete(id); } } function stop(id) { const s = streams.get(id); if (!s) return; try { s.ctrl.abort(); } catch { } finally { streams.delete(id); } } function replay(id, offset = 0) { const s = streams.get(id); if (!s) return; const cur = s.buf(), remain = cur.slice(Math.max(0, offset)); if (remain) send({ t: "delta", id, data: remain }); if (s.done()) send({ t: "done", id }); } bc = new BroadcastChannel(CH); bc.onmessage = (e) => { const m = e.data || {}; if (m.t === "hello") send({ t: "hello-ack" }); else if (m.t === "start" && m.id && m.payload) start(m.id, m.payload); else if (m.t === "stop" && m.id) stop(m.id); else if (m.t === "replay" && m.id) replay(m.id, m.offset | 0); };