self.addEventListener("install", (e) => e.waitUntil(self.skipWaiting())); self.addEventListener("activate", (e) => e.waitUntil(self.clients.claim())); const ch = new BroadcastChannel("llm-stream"); const streams = /* @__PURE__ */ new Map(); const send = (m) => ch.postMessage(m); const parseSSE = async (res, emit, signal) => { const r = res.body.getReader(), d = new TextDecoder("utf-8"); let buf = ""; const doneOnce = () => emit("", true); for (; ; ) { const { value, done } = await r.read(); if (done) break; buf += d.decode(value, { stream: true }); let i; while ((i = buf.indexOf("\n\n")) !== -1) { const chunk = buf.slice(0, i).trim(); buf = buf.slice(i + 2); if (!chunk) continue; if (chunk.startsWith("data:")) { const data = chunk.slice(5).trim(); if (data === "[DONE]") { doneOnce(); continue; } try { const j = JSON.parse(data); emit(j.choices?.[0]?.delta?.content ?? "", !!j.choices?.[0]?.finish_reason); } catch { } } } } doneOnce(); }; const openStream = (id, req) => { const ac = new AbortController(); let off = 0, buf = "", done = false; const record = { ctrl: ac, get off() { return off; }, get buf() { return buf; }, get done() { return done; } }; streams.set(id, record); const run = (async () => { try { const res = await fetch(req.url, { method: req.method || "POST", headers: req.headers || {}, body: JSON.stringify(req.body || {}), signal: ac.signal }); if (!res.ok) throw new Error(await res.text().catch(() => "") || "HTTP " + res.status); await parseSSE(res, (delta, isDone) => { if (delta) { buf += delta; off = buf.length; send({ id, delta, off }); } if (isDone && !done) { done = true; send({ id, done: true, off }); } }, ac.signal); } catch (e) { send({ id, error: String(e?.message || e) }); } finally { if (!done) { done = true; send({ id, done: true, off }); } streams.delete(id); } })(); return run; }; const cancelStream = (id) => { const r = streams.get(id); if (r) try { r.ctrl.abort(); } catch { } }; const replayStream = (id, from = 0) => { const r = streams.get(id); if (!r) return; const s = r.buf || "", start = Math.max(0, from), CH = 16384; for (let i = start; i < s.length; i += CH) { const b = s.slice(i, Math.min(s.length, i + CH)); send({ id, delta: b, off: i + b.length }); } }; self.addEventListener("message", (e) => { const msg = e.data || {}, port = e.ports?.[0]; const ok = (d) => port && port.postMessage(Object.assign({ ok: true }, d || {})); const err = (m) => port && port.postMessage({ error: String(m) }); if (!msg.type) return; if (msg.type === "hello") return ok({ stream: true }); if (msg.type === "stream-openrouter") { const { id, req } = msg.data || {}; if (!id || !req) return err("bad args"); const p = openStream(id, req); e.waitUntil(p); return ok({}); } if (msg.type === "stream-cancel") { const { id } = msg.data || {}; if (!id) return err("bad args"); cancelStream(id); return ok({}); } if (msg.type === "stream-replay") { const { id, from } = msg.data || {}; if (!id) return err("bad args"); replayStream(id, from | 0); return ok({}); } });