UNPKG

@statewalker/webrun-devtools

Version:

DevTools Extension for the StateWalker WebRun framework

452 lines (451 loc) 12.5 kB
async function* L(e, t = []) { let r, n, o = async (l, w, d) => { const u = { error: l, value: w, done: d }; return u.promise = new Promise((y) => u.notify = y), await t.push(u), n && n(), n = null, u.promise; }; const i = (l) => o(void 0, l, !1), s = () => o(void 0, void 0, !0), a = (l) => o(l, void 0, !0), f = e(Object.assign([i, s, a], { next: i, complete: s, error: a })); let c; try { for (; ; ) if (c = await t.shift(), c) try { if (c.error) throw c.error; if (c.done) break; yield c.value; } finally { c.notify(!0); } else await (r = n ? r : new Promise((l) => n = l)); } finally { for (n && n(), o = () => !1, typeof f == "function" && await f(); c = await t.shift(); ) c.notify(!1); } } function P(e = console.error) { let t = 0; const r = {}, n = (s) => { const a = t++; return r[a] = Object.assign( function(f) { try { return delete r[a], !f && s && s(); } catch (c) { e(c); } }, { action: s } ); }, o = (s) => Object.values(r).map((a) => a.action === s && a(!0)), i = () => Object.values(r).map((s) => s()); return Object.assign([n, i, o], { register: n, clear: i, unregister: o }); } const R = "extension-ready", x = "connection-request", M = "connection-response", A = "connection-error", D = "notifyListener", k = "addListener", $ = "removeListener", V = "init", H = "done", U = "reset"; function v(e = "id-") { return `${e}${Date.now()}-${String(Math.random()).substring(2)}`; } const Y = "0.1.5", N = 0.1; function F(e) { if (e.protocolVersion !== N) { const t = [ "Incompatible version of the WebRun DevTools browser extension protocol." ]; return e.protocolVersion ? (t.push(`The expected extension protocol version is ${e.protocolVersion}.`), e.extensionVersion && (t.push(`Try to use the client library version ${e.extensionVersion}.`), t.push(`For example: https://unpkg.com/@statewalker/webrun-devtools@${e.extensionVersion}.`))) : (t.push("Try to use the client library version 0.0.12."), t.push("For example: https://unpkg.com/@statewalker/webrun-devtools@0.0.12.")), new Error(t.join(` `)); } } async function j({ apiKey: e, timeout: t = 1e3 * 5 }) { await new Promise((s) => { const a = () => setTimeout(s, 10); document.readyState === "complete" ? a() : document.addEventListener("DOMContentLoaded", a); }); let r, n; const o = new Promise((s, a) => { r = setTimeout( () => a( new Error( "Connection timeout. Please check that the WebRun DevTools browser extension is active." ) ), t ); let f = !1; const c = v("call-"); function l() { f || window.postMessage( { type: x, apiKey: e, callId: c, protocolVersion: N, clientApiVersion: Y }, "*" ); } n = (w) => { if (w.source !== window) return; const { data: d, ports: u } = w; try { if ((d == null ? void 0 : d.type) === R) l(); else if ((d == null ? void 0 : d.callId) === c) { if (f = !0, (d == null ? void 0 : d.type) === A) a(new Error(d.message)); else if (d.type === M) { const y = F(d); y ? a(y) : s(u[0]); } } } catch (y) { a(y), u[0] && u[0].close(); } }, window.addEventListener("message", n), l(); }); o.finally(() => clearTimeout(r)), o.finally( () => n && window.removeEventListener("message", n) ); const i = await o; return i.start(), i; } function B(e) { return e ? typeof e == "string" ? e.split(".") : e : []; } function z(e = {}, t, r) { if (t = B(t), t.length === 0) return r; let n = o(e); for (let i = 0, s = n; i < t.length; i++) { const a = t[i]; s = s[a] = i < t.length - 1 ? o(s[a]) : r; } return n; function o(i) { return typeof i == "object" && i !== null ? Array.isArray(i) ? [...i] : Object.assign({}, i) : {}; } } function J(e) { return Object.assign( { message: e, stack: e.stack }, e ); } function W(e) { return typeof e == "string" && (e = { message: e }), Object.assign(new Error(e.message), e); } async function I(e, t, { timeout: r = 1e3, channelName: n = "", log: o = () => { }, // console.log newCallId: i = () => `call-${Date.now()}-${String(Math.random()).substring(2)}` } = {}) { const s = i(); o && o("[callPort]", { channelName: n, callId: s, params: t }); let a, f; const c = new Promise((l, w) => { a = setTimeout(() => w(new Error(`Call timeout. CallId: "${s}".`)), r), f = (d) => { d.data && d.data.channelName === n && d.data.callId === s && (d.data.type === "response:error" ? w(W(d.data.error)) : d.data.type === "response:result" && l(d.data.result)); }, e.addEventListener("message", f); }); return c.finally(() => clearTimeout(a)), c.finally(() => e.removeEventListener("message", f)), e.postMessage({ type: "request", channelName: n, callId: s, params: t }), c; } async function* Q(e) { let t, r = e(async ({ done: n = !0, value: o, error: i } = {}) => { i ? await t.error(i) : n ? await t.complete() : await t.next(o); }); yield* L((n) => (t = n, r)); } function _(e, t, { channelName: r = "", log: n = () => { } // console.log } = {}) { const o = async function(s) { if (!s.data || s.data.channelName !== r || s.data.type !== "request") return; const { callId: a, params: f } = s.data; n && n("[listenPort]", { channelName: r, callId: a, params: f }); let c, l, w; try { c = await t(f), w = "response:result"; } catch (d) { l = J(d), w = "response:error"; } e.postMessage({ callId: a, channelName: r, type: w, result: c, error: l }); }; return e.addEventListener("message", o), () => e.removeEventListener("message", o); } async function* X(e, t = {}) { let r; const n = _( e, async ({ done: o, value: i, error: s }) => { await r({ done: o, value: i, error: s }); }, t ); try { let o = !1; for (; !o; ) yield Q((i) => r = i); } finally { n && await n(); } } async function Z(e, t) { let r; try { for await (let n of t) await e({ done: !1, value: n }); } catch (n) { r = n; } finally { await e({ done: !0, error: r }); } } async function G(e, t, r = {}) { await Z(async ({ done: n, value: o, error: i }) => { await I(e, { done: n, value: o, error: i }, r); }, t); } async function* K(e, t, r) { for await (const n of X(e, r)) { const o = G(e, t, r); try { yield* n; } finally { await o; } break; } } async function* C(e, t) { for await (const r of t) yield e(r); } async function* q(e) { yield* C(te, e); } async function* ee(e) { yield* C(ne, e); } const E = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", b = typeof Uint8Array > "u" ? [] : new Uint8Array(256); for (let e = 0; e < E.length; e++) b[E.charCodeAt(e)] = e; function te(e) { let t = new Uint8Array(e), r, n = t.length, o = ""; for (r = 0; r < n; r += 3) o += E[t[r] >> 2], o += E[(t[r] & 3) << 4 | t[r + 1] >> 4], o += E[(t[r + 1] & 15) << 2 | t[r + 2] >> 6], o += E[t[r + 2] & 63]; return n % 3 === 2 ? o = o.substring(0, o.length - 1) + "=" : n % 3 === 1 && (o = o.substring(0, o.length - 2) + "=="), o; } function ne(e) { let t = e.length * 0.75, r = e.length, n, o = 0, i, s, a, f; e[e.length - 1] === "=" && (t--, e[e.length - 2] === "=" && t--); const c = new ArrayBuffer(t), l = new Uint8Array(c); for (n = 0; n < r; n += 4) i = b[e.charCodeAt(n)], s = b[e.charCodeAt(n + 1)], a = b[e.charCodeAt(n + 2)], f = b[e.charCodeAt(n + 3)], l[o++] = i << 2 | s >> 4, l[o++] = (s & 15) << 4 | a >> 2, l[o++] = (a & 3) << 6 | f & 63; return l; } function re(e) { return new ReadableStream({ type: "bytes", async pull(t) { let r = !1; try { for (; !r; ) { const n = await e.next(); if (!n || n.done) break; t.enqueue(await n.value); } } catch (n) { r = !0, t.error(n); } finally { !r && t.close(); } } }); } async function* oe(e) { const t = await e.getReader(); let r, n; for (; ({ done: r, value: n } = await t.read()) && !r; ) yield await n; } function se(e) { return async (t) => { t = await t; const r = [ "url", "method", "mode", "credentials", "cache", "redirect", "referrer", "referrerPolicy", "integrity", "keepalive" ], n = [...t.headers].map(([c, l]) => [c, l]), o = r.reduce((c, l) => { const w = t[l]; return w !== void 0 && (c[l] = w), c; }, { headers: n }), i = t.body ? oe(t.body) : [], s = await e({ options: o, content: i }); let a = null, f = {}; if (!s) f = { status: 404, statusText: "Error 404: Not Found" }; else { f = s.options; const c = s.content; o.method !== "HEAD" && o.method !== "OPTIONS" ? a = re(c) : c && c.return && c.return(); } return new Response(a, f); }; } async function* ie(e) { const { options: t, content: r } = await e; yield new TextEncoder().encode(JSON.stringify(t)), yield* r; } async function ae(e) { e = await e; const { done: t, value: r } = await e.next(); let n = {}; if (!t && r) { const i = new TextDecoder().decode(r); n = JSON.parse(i); } return { options: n, content: e }; } function ce(e) { return async function(t) { return await se(async (n) => await ae( e(ie(n)) ))(t); }; } async function le(e, { apiKey: t, callTimeout: r = 1e3 * 60 * 5, closeTimeout: n = 1e3 * 5 }) { const [o, i] = P(); let s = {}, a = {}; o(() => { for (let { listener: u, removeListener: y } of Object.values(a)) typeof y == "function" && y(u); a = {}; }); let f; async function c() { if (!f) { const u = Object.entries(a).map( ([y, { listenerMethodName: h }]) => [y, h] ); f = I( e, { method: V, args: [ { apiKey: t, listeners: u } ] }, { timeout: r } ); } return f; } async function l(u, ...y) { return await c(), await I( e, { method: u, args: y }, { timeout: r } ); } const w = _(e, async ({ method: u, args: y } = {}) => { if (u === D) { const [h, ...p] = y, { listener: g } = a[h] || {}; if (g) return await g(...p); } else if (u === U) f = null, await c(); else throw new Error(`Unknown method "${u}"}`); }); o(w); const { methods: d } = await c(); for (let u of d) { const y = u.split("."); let h; if (u === "http.fetch") h = async (p, ...g) => { p instanceof Request || (p = new Request(p, ...g)); const m = `channel-${Date.now()}-${String(Math.random()).substring(2)}`; return l(u, p.url, { channelName: m }), await ce((S) => ee(K(e, q(S), { channelName: m // log: console.warn.bind(console, "CLIENT") })))(p); }; else if (u.match(/\.on[A-Z]/)) { async function p(m) { const T = m.__id; return delete m.__id, delete a[T], await l($, T, u); } async function g(m, ...T) { const O = m.__id = v("listener-"); return a[O] = { listener: m, removeListener: p, listenerMethodName: u }, await l(k, O, u, ...T); } h = async (m) => (await g(m), o(() => p(m))), h.addListener = g, h.removeListener = p; } else h = async (...p) => await l(u, ...p); s = z(s, y, h); } return s.close = async () => { i(), await l(H), setTimeout(() => e.close(), n); }, s; } async function ue({ apiKey: e, timeout: t = 1e3 * 5, callTimeout: r = 1e3 * 60 * 5, closeTimeout: n = 1e3 * 5 }) { const o = await j({ apiKey: e, timeout: t }); return await le(o, { apiKey: e, callTimeout: r, closeTimeout: n }); } export { ue as connectPageToExtension, ue as default, le as initApi, P as newRegistry, j as openPortToExtension };