@tlockney/cdp-kernel 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -404
- package/THIRD-PARTY-NOTICES +62 -0
- package/dist/bun-target.d.ts +4 -2
- package/dist/bun-target.js +35 -8
- package/dist/cdp.d.ts +6 -1
- package/dist/cdp.js +25 -10
- package/dist/celld-target.d.ts +1 -1
- package/dist/celld-target.js +46 -8
- package/dist/children.d.ts +7 -0
- package/dist/children.js +32 -0
- package/dist/debugger.d.ts +42 -0
- package/dist/debugger.js +545 -0
- package/dist/globals.d.ts +3 -3
- package/dist/globals.js +3 -3
- package/dist/history.d.ts +18 -0
- package/dist/history.js +45 -0
- package/dist/kernel.js +211 -32
- package/dist/main.js +3 -1
- package/dist/mod.d.ts +5 -3
- package/dist/mod.js +5 -3
- package/dist/murmur2.d.ts +2 -0
- package/dist/murmur2.js +41 -0
- package/dist/package.d.ts +16 -2
- package/dist/package.js +26 -3
- package/dist/sourcemap.d.ts +22 -0
- package/dist/sourcemap.js +86 -0
- package/dist/target.d.ts +39 -3
- package/dist/target.js +281 -30
- package/dist/text.d.ts +11 -1
- package/dist/text.js +72 -2
- package/dist/transform.d.ts +19 -0
- package/dist/transform.js +74 -13
- package/dist/wire.d.ts +8 -1
- package/dist/wire.js +3 -1
- package/dist/workerd-target.d.ts +9 -1
- package/dist/workerd-target.js +108 -9
- package/dist/ws-client.d.ts +5 -1
- package/dist/ws-client.js +46 -13
- package/dist/zmtp.d.ts +7 -1
- package/dist/zmtp.js +30 -1
- package/package.json +10 -4
- package/runtime/bootstrap.mjs +138 -12
- package/runtime/bun-channel.d.mts +3 -0
- package/runtime/bun-channel.mjs +2 -2
- package/runtime/comm.mjs +11 -1
- package/runtime/deno-compat.d.mts +2 -0
- package/runtime/deno-compat.mjs +17 -2
- package/runtime/display.d.mts +2 -0
- package/runtime/display.mjs +17 -2
- package/runtime/evaluator.d.mts +4 -0
- package/runtime/evaluator.mjs +8 -0
- package/runtime/introspect.d.mts +13 -0
- package/runtime/introspect.mjs +120 -0
- package/runtime/node-hooks.d.mts +61 -1
- package/runtime/node-hooks.mjs +354 -21
- package/runtime/workerd-worker.mjs +82 -6
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { formatWithOptions, inspect } from "node:util";
|
|
19
19
|
import { createJupyter } from "./display.mjs";
|
|
20
20
|
import { createHandler } from "./evaluator.mjs";
|
|
21
|
+
import { describeValue, inspectPath, resolvePath } from "./introspect.mjs";
|
|
21
22
|
|
|
22
23
|
const BUILTIN = /^(?:node|cloudflare|workerd):/;
|
|
23
24
|
|
|
@@ -50,6 +51,44 @@ Object.assign(console, {
|
|
|
50
51
|
error: stream("stderr"),
|
|
51
52
|
});
|
|
52
53
|
|
|
54
|
+
// An error thrown later by a cell's timer or promise goes to stderr, as on
|
|
55
|
+
// the other targets (runtime/bootstrap.mjs). Workers has no global "error"
|
|
56
|
+
// event, so timer callbacks report their own (#148), and so do the
|
|
57
|
+
// promises they return: celld doesn't dispatch "unhandledrejection".
|
|
58
|
+
function reportUncaught(kind, err) {
|
|
59
|
+
emit({ kind: "stream", name: "stderr", text: `${kind}: ${err instanceof Error ? (err.stack ?? err.message) : inspect(err)}\n` });
|
|
60
|
+
}
|
|
61
|
+
// A rejection both runtimes' events report is shown once.
|
|
62
|
+
const reported = new WeakSet();
|
|
63
|
+
function reportRejection(reason) {
|
|
64
|
+
if (typeof reason === "object" && reason !== null) {
|
|
65
|
+
if (reported.has(reason)) return;
|
|
66
|
+
reported.add(reason);
|
|
67
|
+
}
|
|
68
|
+
reportUncaught("Uncaught (in promise)", reason);
|
|
69
|
+
}
|
|
70
|
+
globalThis.addEventListener("unhandledrejection", (event) => {
|
|
71
|
+
event.preventDefault();
|
|
72
|
+
reportRejection(event.reason);
|
|
73
|
+
});
|
|
74
|
+
globalThis.process?.on?.("unhandledRejection", reportRejection);
|
|
75
|
+
const reporting = (callback) =>
|
|
76
|
+
typeof callback !== "function" ? callback : function (...args) {
|
|
77
|
+
let result;
|
|
78
|
+
try {
|
|
79
|
+
result = callback.apply(this, args);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
reportUncaught("Uncaught", err);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (typeof result?.then === "function") result.then(undefined, reportRejection);
|
|
85
|
+
return result;
|
|
86
|
+
};
|
|
87
|
+
for (const name of ["setTimeout", "setInterval", "queueMicrotask"]) {
|
|
88
|
+
const original = globalThis[name];
|
|
89
|
+
globalThis[name] = { [name]: (callback, ...rest) => original(reporting(callback), ...rest) }[name];
|
|
90
|
+
}
|
|
91
|
+
|
|
53
92
|
const jupyter = createJupyter({
|
|
54
93
|
inspect: (value) => inspect(value, { colors: true, depth: 4 }),
|
|
55
94
|
base64,
|
|
@@ -96,6 +135,10 @@ function install(env) {
|
|
|
96
135
|
import: cellImport,
|
|
97
136
|
meta: { ...meta, resolve: (specifier) => new URL(specifier, meta.url).href },
|
|
98
137
|
requireFor,
|
|
138
|
+
// inspect_request (#10): by descriptor, so nothing runs.
|
|
139
|
+
describeForInspect: (value, detail) => describeValue(value, { inspect: (v) => inspect(v, { colors: false, depth: 2 }), detail }),
|
|
140
|
+
inspectPath: (path, detail) => inspectPath(path, { inspect: (v) => inspect(v, { colors: false, depth: 2 }), detail }),
|
|
141
|
+
resolvePath,
|
|
99
142
|
barrier: () => 0,
|
|
100
143
|
broadcastResult: jupyter.broadcastResult,
|
|
101
144
|
async commDispatch(msgType, content, metadata, buffers64) {
|
|
@@ -126,13 +169,23 @@ function install(env) {
|
|
|
126
169
|
|
|
127
170
|
let evaluate = null;
|
|
128
171
|
|
|
172
|
+
// Modules whose load rejected. Importing one again gives its error again,
|
|
173
|
+
// and the next eval reply names it, so the host bundles it afresh for the
|
|
174
|
+
// next import (#147), which replaces it here.
|
|
175
|
+
const rejected = new Set();
|
|
176
|
+
const unreported = new Set();
|
|
177
|
+
|
|
129
178
|
/** Evaluates the bundles a cell brings, once each. */
|
|
130
179
|
async function loadModules(bundles = {}) {
|
|
131
180
|
for (const [specifier, script] of Object.entries(bundles)) {
|
|
132
|
-
if (modules.has(specifier)) continue;
|
|
181
|
+
if (modules.has(specifier) && !rejected.has(specifier)) continue;
|
|
182
|
+
rejected.delete(specifier);
|
|
133
183
|
const loading = Promise.resolve().then(() => evaluate(script));
|
|
134
|
-
|
|
135
|
-
|
|
184
|
+
loading.catch(() => {
|
|
185
|
+
if (modules.get(specifier) !== loading) return;
|
|
186
|
+
rejected.add(specifier);
|
|
187
|
+
unreported.add(specifier);
|
|
188
|
+
});
|
|
136
189
|
modules.set(specifier, loading);
|
|
137
190
|
}
|
|
138
191
|
}
|
|
@@ -146,8 +199,31 @@ async function answer(req) {
|
|
|
146
199
|
worker: globalThis.worker !== undefined,
|
|
147
200
|
};
|
|
148
201
|
}
|
|
149
|
-
if (req.op
|
|
150
|
-
|
|
202
|
+
if (req.op !== "eval") return await handle(req);
|
|
203
|
+
await loadModules(req.modules);
|
|
204
|
+
const reply = await handle(req);
|
|
205
|
+
// After the cell, so a load that failed in it is counted.
|
|
206
|
+
const failedModules = [...unreported];
|
|
207
|
+
unreported.clear();
|
|
208
|
+
return { ...reply, failedModules };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const encoder = new TextEncoder();
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Compares in constant time: under celld and Miniflare the driver listens on
|
|
215
|
+
* loopback TCP, where any local user can try tokens. The length (fixed by
|
|
216
|
+
* the host) is not secret.
|
|
217
|
+
*/
|
|
218
|
+
function tokenMatches(token, expected) {
|
|
219
|
+
if (typeof token !== "string" || typeof expected !== "string") return false;
|
|
220
|
+
const a = encoder.encode(token);
|
|
221
|
+
const b = encoder.encode(expected);
|
|
222
|
+
if (a.byteLength !== b.byteLength) return false;
|
|
223
|
+
if (typeof crypto.subtle.timingSafeEqual === "function") return crypto.subtle.timingSafeEqual(a, b);
|
|
224
|
+
let diff = 0;
|
|
225
|
+
for (let i = 0; i < a.byteLength; i++) diff |= a[i] ^ b[i];
|
|
226
|
+
return diff === 0;
|
|
151
227
|
}
|
|
152
228
|
|
|
153
229
|
export default {
|
|
@@ -155,7 +231,7 @@ export default {
|
|
|
155
231
|
// A header, or the query string for a WebSocket client that can't set
|
|
156
232
|
// headers (celld's session uses the host's built-in WebSocket).
|
|
157
233
|
const token = request.headers.get("x-cdpk-token") ?? new URL(request.url).searchParams.get("token");
|
|
158
|
-
if (token
|
|
234
|
+
if (!tokenMatches(token, env.TOKEN)) return new Response("forbidden", { status: 403 });
|
|
159
235
|
if (request.headers.get("upgrade") !== "websocket") return new Response("expected a WebSocket", { status: 426 });
|
|
160
236
|
evaluate ??= install(env);
|
|
161
237
|
|