@statewalker/webrun-devtools
Version:
DevTools Extension for the StateWalker WebRun framework
452 lines (451 loc) • 12.5 kB
JavaScript
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
};