UNPKG

@laravel/stream-vue

Version:
235 lines (234 loc) 6.3 kB
import { ref as m, onMounted as q, onUnmounted as x, watch as J, readonly as S } from "vue"; const M = "data: ", U = (t, { eventName: e = "update", endSignal: n = "</stream>", glue: a = " ", replace: i = !1, onMessage: F = () => null, onComplete: R = () => null, onError: b = () => null } = {}) => { const d = m(""), h = m([]), v = Array.isArray(e) ? e : [e]; let s = null; const l = () => { d.value = "", h.value = []; }, u = (r = !1) => { v.forEach((o) => { s == null || s.removeEventListener(o, y); }), s == null || s.close(), s = null, r && l(); }, y = (r) => { if ([n, `${M}${n}`].includes(r.data)) { u(), R(); return; } i && l(), h.value.push( r.data.startsWith(M) ? r.data.substring(M.length) : r.data ), d.value = h.value.join(a), F(r); }, j = (r) => { b(r), u(); }, C = () => { l(), s = new EventSource(t), v.forEach((r) => { s.addEventListener(r, y); }), s.addEventListener("error", j); }; return q(() => { C(); }), x(() => { u(); }), J( () => t, (r, o) => { r !== o && (u(), C()); } ), { message: S(d), messageParts: S(h), close: u, clearMessage: l }; }, N = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"; let X = (t = 21) => { let e = "", n = crypto.getRandomValues(new Uint8Array(t |= 0)); for (; t--; ) e += N[n[t] & 63]; return e; }; const w = /* @__PURE__ */ new Map(), K = (t, e) => { w.has(t) || w.set(t, { onData: [], onError: [], onFinish: [], onResponse: [], onCancel: [], onBeforeSend: [] }); const n = w.get(t); return e.onData && n.onData.push(e.onData), e.onError && n.onError.push(e.onError), e.onFinish && n.onFinish.push(e.onFinish), e.onResponse && n.onResponse.push(e.onResponse), e.onCancel && n.onCancel.push(e.onCancel), e.onBeforeSend && n.onBeforeSend.push(e.onBeforeSend), () => { H(t, e); }; }, E = (t, e, ...n) => { const a = w.get(t); return a ? a[e].map((i) => i(...n)) : []; }, T = (t) => { E(t, "onFinish"); }, p = (t, e) => { E(t, "onError", e); }, V = (t, e) => { E(t, "onResponse", e); }, W = (t) => { E(t, "onCancel"); }, $ = (t, e) => { E(t, "onData", e); }, G = (t, e) => { const n = E(t, "onBeforeSend", e); for (const a of n) { if (a === !1) return !1; if (a !== null && typeof a == "object") return a; } return null; }, H = (t, e) => { const n = w.get(t); n && (e.onData && (n.onData = n.onData.filter( (a) => a !== e.onData )), e.onError && (n.onError = n.onError.filter( (a) => a !== e.onError )), e.onFinish && (n.onFinish = n.onFinish.filter( (a) => a !== e.onFinish )), e.onResponse && (n.onResponse = n.onResponse.filter( (a) => a !== e.onResponse )), e.onCancel && (n.onCancel = n.onCancel.filter( (a) => a !== e.onCancel )), e.onBeforeSend && (n.onBeforeSend = n.onBeforeSend.filter( (a) => a !== e.onBeforeSend ))); }, L = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map(), A = (t) => { const e = L.get(t); if (e) return e; const n = { controller: new AbortController(), data: "", isFetching: !1, isStreaming: !1, jsonData: null }; return L.set(t, n), n; }, P = (t) => (f.has(t) || f.set(t, []), f.get(t)), O = (t) => { var e; return f.has(t) && ((e = f.get(t)) == null ? void 0 : e.length); }, Q = (t, e) => (P(t).push(e), () => { f.set( t, P(t).filter((n) => n !== e) ), O(t) || (L.delete(t), f.delete(t)); }), Y = (t, e) => { var a; L.set(t, { ...A(t), ...e }); const n = A(t); (a = f.get(t)) == null || a.forEach((i) => i(n)); }, Z = (t, e = {}) => { const n = e.id ?? X(), a = m(A(n)), i = (() => { var g; const r = { "Content-Type": "application/json", "X-STREAM-ID": n }, o = e.csrfToken ?? ((g = document.querySelector('meta[name="csrf-token"]')) == null ? void 0 : g.getAttribute("content")); return o && (r["X-CSRF-TOKEN"] = o), r; })(), F = m(a.value.data), R = m(a.value.jsonData), b = m(a.value.isFetching), d = m(a.value.isStreaming); let h, v; const s = (r) => { Y(n, r); }, l = () => { a.value.controller.abort(), (b || d) && W(n), s({ isFetching: !1, isStreaming: !1 }); }, u = (r) => { const o = new AbortController(), g = { method: "POST", signal: o.signal, headers: { ...i, ...e.headers ?? {} }, body: JSON.stringify(r ?? {}), credentials: e.credentials ?? "same-origin" }, k = G(n, g); k !== !1 && (s({ isFetching: !0, controller: o }), fetch(t, k ?? g).then(async (c) => { if (!c.ok) { const D = await c.text(); throw new Error(D); } if (!c.body) throw new Error( "ReadableStream not yet supported in this browser." ); return V(n, c), s({ isFetching: !1, isStreaming: !0 }), C(c.body.getReader()); }).catch((c) => { s({ isFetching: !1, isStreaming: !1 }), p(n, c), T(n); })); }, y = (r) => { l(), u(r), j(); }, j = () => { s({ data: "", jsonData: null }); }, C = (r, o = "") => r.read().then(({ done: g, value: k }) => { const c = new TextDecoder("utf-8").decode(k), D = o + c; $(n, c); const B = { data: D }; if (!g) return s(B), C(r, D); if (B.isStreaming = !1, e.json) try { B.jsonData = JSON.parse(D); } catch (I) { p(n, I); } return s(B), T(n), ""; }); return q(() => { h = Q(n, (r) => { a.value = A(n), b.value = r.isFetching, d.value = r.isStreaming, F.value = r.data, R.value = r.jsonData; }), v = K(n, e), window.addEventListener("beforeunload", l), e.initialInput && u(e.initialInput); }), x(() => { h(), v(), window.removeEventListener("beforeunload", l), O(n) || l(); }), { data: S(F), jsonData: S(R), isFetching: S(b), isStreaming: S(d), id: n, send: y, cancel: l, clearData: j }; }, z = (t, e = {}) => { const { jsonData: n, data: a, ...i } = Z(t, { ...e, json: !0 }); return { data: n, strData: a, ...i }; }; export { U as useEventStream, z as useJsonStream, Z as useStream };