@tlockney/cdp-kernel 0.2.0 → 0.4.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.
Files changed (43) hide show
  1. package/README.md +259 -33
  2. package/dist/bun-target.d.ts +60 -0
  3. package/dist/bun-target.js +236 -0
  4. package/dist/celld-target.d.ts +39 -0
  5. package/dist/celld-target.js +274 -0
  6. package/dist/debugger.d.ts +42 -0
  7. package/dist/debugger.js +534 -0
  8. package/dist/history.d.ts +18 -0
  9. package/dist/history.js +45 -0
  10. package/dist/kernel.js +91 -15
  11. package/dist/main.js +8 -6
  12. package/dist/murmur2.d.ts +2 -0
  13. package/dist/murmur2.js +41 -0
  14. package/dist/package.d.ts +16 -2
  15. package/dist/package.js +28 -2
  16. package/dist/sourcemap.d.ts +22 -0
  17. package/dist/sourcemap.js +86 -0
  18. package/dist/target.d.ts +65 -7
  19. package/dist/target.js +57 -6
  20. package/dist/text.d.ts +6 -0
  21. package/dist/text.js +17 -0
  22. package/dist/transform.d.ts +16 -0
  23. package/dist/transform.js +173 -11
  24. package/dist/workerd-target.d.ts +125 -0
  25. package/dist/workerd-target.js +455 -0
  26. package/dist/workers-project.d.ts +27 -0
  27. package/dist/workers-project.js +195 -0
  28. package/dist/ws-client.d.ts +32 -0
  29. package/dist/ws-client.js +166 -0
  30. package/package.json +18 -4
  31. package/runtime/bootstrap.mjs +55 -5
  32. package/runtime/bun-channel.d.mts +3 -0
  33. package/runtime/bun-channel.mjs +58 -0
  34. package/runtime/deno-compat.mjs +3 -1
  35. package/runtime/display.d.mts +2 -0
  36. package/runtime/display.mjs +9 -1
  37. package/runtime/evaluator.d.mts +22 -0
  38. package/runtime/evaluator.mjs +91 -0
  39. package/runtime/introspect.d.mts +13 -0
  40. package/runtime/introspect.mjs +120 -0
  41. package/runtime/node-hooks.d.mts +29 -0
  42. package/runtime/node-hooks.mjs +160 -20
  43. package/runtime/workerd-worker.mjs +194 -0
package/dist/target.js CHANGED
@@ -6,7 +6,7 @@ import process from "node:process";
6
6
  import { spawn } from "node:child_process";
7
7
  import { join } from "node:path";
8
8
  import { asEvaluateResult, CdpAbandoned, CdpSession } from "./cdp.js";
9
- import { SHIM } from "./transform.js";
9
+ import { SHIM, transformCell } from "./transform.js";
10
10
  import { hostRuntime, isInsideNodeModules, runtimeDir } from "./package.js";
11
11
  const BINDING = "__cdpk_send";
12
12
  const MARKER_RE = /\x1b\[cdpk:(\d+)(m?)\]\x1b/;
@@ -41,7 +41,7 @@ export function launchCommand(runtime, bootstrap, { executable, denoConfig } = {
41
41
  const node = hostRuntime() === "node" ? process.execPath : "node";
42
42
  return { cmd: executable ?? node, args: [...inspect, bootstrap] };
43
43
  }
44
- function isTargetMessage(value) {
44
+ export function isTargetMessage(value) {
45
45
  if (typeof value !== "object" || value === null)
46
46
  return false;
47
47
  const kind = value.kind;
@@ -140,7 +140,7 @@ export class PipeDemux {
140
140
  }
141
141
  }
142
142
  /** Promises keyed by barrier number, resolvable before or after first use. */
143
- class Gates {
143
+ export class Gates {
144
144
  #map = new Map();
145
145
  #entry(n) {
146
146
  let entry = this.#map.get(n);
@@ -169,6 +169,7 @@ export class Interrupted extends Error {
169
169
  }
170
170
  export class Target {
171
171
  runtime;
172
+ transform = transformCell;
172
173
  #child;
173
174
  #shell;
174
175
  #control;
@@ -178,6 +179,8 @@ export class Target {
178
179
  #contextId;
179
180
  #messages = Promise.resolve();
180
181
  #interrupted = false;
182
+ #paused = false;
183
+ #baselineGlobals = new Set();
181
184
  versions;
182
185
  constructor(runtime, child, shell, control, stdout, stderr, gates, contextId, versions) {
183
186
  this.runtime = runtime;
@@ -253,7 +256,7 @@ export class Target {
253
256
  await shell.send("Runtime.enable");
254
257
  await shell.send("Runtime.addBinding", { name: BINDING });
255
258
  const contextId = await contextReady;
256
- const target = new Target(runtime, child, shell, control, stdout, stderr, gates, contextId, { runtime: "", v8: "" });
259
+ const target = new Target(runtime, child, shell, control, stdout, stderr, gates, contextId, { runtime: "", engine: "" });
257
260
  shell.on("Runtime.bindingCalled", (params) => {
258
261
  if (params.name !== BINDING || typeof params.payload !== "string")
259
262
  return;
@@ -268,10 +271,28 @@ export class Target {
268
271
  break;
269
272
  await new Promise((r) => setTimeout(r, 25));
270
273
  }
271
- const versions = await target.#evaluateRaw(`JSON.stringify(typeof Deno !== "undefined" ? { runtime: Deno.version.deno, v8: Deno.version.v8 } : { runtime: process.versions.node, v8: process.versions.v8 })`);
274
+ const versions = await target.#evaluateRaw(`JSON.stringify(typeof Deno !== "undefined" ? { runtime: Deno.version.deno, engine: "V8 " + Deno.version.v8 } : { runtime: process.versions.node, engine: "V8 " + process.versions.v8 })`);
272
275
  Object.assign(target.versions, JSON.parse(String(versions.result.value)));
276
+ // The runtime's own enumerable globals, before any cell: the debugger's
277
+ // variable views show only what cells added (#18).
278
+ const globals = asEvaluateResult(await shell.send("Runtime.evaluate", { expression: "Object.keys(globalThis)", contextId, returnByValue: true }));
279
+ const names = globals.result.value;
280
+ if (Array.isArray(names))
281
+ for (const name of names)
282
+ target.#baselineGlobals.add(String(name));
283
+ shell.on("Debugger.paused", () => (target.#paused = true));
284
+ shell.on("Debugger.resumed", () => (target.#paused = false));
273
285
  return target;
274
286
  }
287
+ /** The Debugger domain on this target's session, for src/debugger.ts. */
288
+ get debug() {
289
+ return {
290
+ send: (method, params = {}) => this.#shell.send(method, params),
291
+ on: (method, listener) => this.#shell.on(method, listener),
292
+ contextId: this.#contextId,
293
+ baselineGlobals: this.#baselineGlobals,
294
+ };
295
+ }
275
296
  // Binding messages wait until both pipes have caught up to their marker,
276
297
  // and are delivered strictly in order.
277
298
  #deliver(msg, events) {
@@ -314,6 +335,9 @@ export class Target {
314
335
  */
315
336
  async interrupt() {
316
337
  this.#interrupted = true;
338
+ // A paused isolate runs nothing to terminate: let it go first (#18).
339
+ if (this.#paused)
340
+ await this.#shell.send("Debugger.resume").catch(() => { });
317
341
  await this.#control.send("Runtime.terminateExecution");
318
342
  this.#shell.abandonPending();
319
343
  }
@@ -380,8 +404,18 @@ export class Target {
380
404
  const value = res.result?.value;
381
405
  return JSON.parse(typeof value === "string" ? value : '{"name":"Error","message":"","stack":""}');
382
406
  }
407
+ /**
408
+ * Evaluates without side effects: V8 throws instead of running anything
409
+ * that would change state (a call, a getter that writes), so completing
410
+ * or inspecting `obj.` never runs user code (#10).
411
+ */
412
+ #evaluatePure(expression) {
413
+ return this.#shell
414
+ .send("Runtime.evaluate", { expression, contextId: this.#contextId, replMode: true, throwOnSideEffect: true })
415
+ .then(asEvaluateResult, () => null);
416
+ }
383
417
  async propertyNames(expression) {
384
- const evaluated = await this.#evaluateRaw(`(${expression})`).catch(() => null);
418
+ const evaluated = await this.#evaluatePure(`(${expression})`);
385
419
  const objectId = evaluated?.result.objectId;
386
420
  if (!objectId || evaluated?.exceptionDetails)
387
421
  return [];
@@ -389,6 +423,23 @@ export class Target {
389
423
  const list = props.result;
390
424
  return (list ?? []).map((p) => p.name);
391
425
  }
426
+ async inspect(path, detail) {
427
+ const found = await this.#evaluatePure(path);
428
+ if (!found || found.exceptionDetails)
429
+ return null;
430
+ const value = found.result;
431
+ const arg = value.objectId
432
+ ? { objectId: value.objectId }
433
+ : value.unserializableValue !== undefined
434
+ ? { unserializableValue: value.unserializableValue }
435
+ : { value: value.value };
436
+ const res = await this.callFunctionOn(`function (v, d) { return globalThis.${SHIM}.describeForInspect(v, d); }`, [
437
+ arg,
438
+ { value: detail },
439
+ ]);
440
+ const text = res.result?.value;
441
+ return typeof text === "string" ? text : null;
442
+ }
392
443
  async lexicalNames() {
393
444
  const res = await this.#shell.send("Runtime.globalLexicalScopeNames", { executionContextId: this.#contextId });
394
445
  return res.names ?? [];
package/dist/text.d.ts CHANGED
@@ -10,5 +10,11 @@ export type IsCompleteReply = {
10
10
  export declare function checkIsComplete(code: string): IsCompleteReply;
11
11
  /** The dotted expression ending at the cursor, e.g. "Math.fl". */
12
12
  export declare function exprAtCursor(code: string, cursor: number): string;
13
+ /**
14
+ * The dotted name an inspect_request means (#10): the one the cursor is in
15
+ * or just after, or, right after "name(" while typing a call, that callee.
16
+ * Null when it isn't a plain path; nothing else is evaluated.
17
+ */
18
+ export declare function inspectTarget(code: string, cursor: number): string | null;
13
19
  export declare function codePointToUtf16Index(str: string, cpOffset: number): number;
14
20
  export declare function utf16ToCodePointIndex(str: string, utf16Offset: number): number;
package/dist/text.js CHANGED
@@ -51,6 +51,23 @@ export function exprAtCursor(code, cursor) {
51
51
  const m = /[\w$.]+$/.exec(code.slice(0, cursor));
52
52
  return m ? m[0] : "";
53
53
  }
54
+ /**
55
+ * The dotted name an inspect_request means (#10): the one the cursor is in
56
+ * or just after, or, right after "name(" while typing a call, that callee.
57
+ * Null when it isn't a plain path; nothing else is evaluated.
58
+ */
59
+ export function inspectTarget(code, cursor) {
60
+ let end = cursor;
61
+ // Inside a call's parentheses with nothing typed yet: "add(|".
62
+ const before = code.slice(0, cursor);
63
+ const call = /([\w$.]+)\(\s*$/.exec(before);
64
+ if (call)
65
+ end = cursor - (before.length - before.lastIndexOf("(", cursor));
66
+ const head = /[\w$.]*$/.exec(code.slice(0, end))?.[0] ?? "";
67
+ const tail = call ? "" : (/^[\w$]*/.exec(code.slice(end))?.[0] ?? "");
68
+ const path = (head + tail).replace(/\.$/, "");
69
+ return /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/.test(path) ? path : null;
70
+ }
54
71
  // Jupyter measures cursor_pos in Unicode codepoints; JS strings index UTF-16
55
72
  // code units (denoland/deno#22771).
56
73
  export function codePointToUtf16Index(str, cpOffset) {
@@ -1,3 +1,4 @@
1
+ import { LineMap } from "./sourcemap.ts";
1
2
  export declare const SHIM = "__cdpk";
2
3
  export declare class CellSyntaxError extends Error {
3
4
  name: string;
@@ -23,6 +24,21 @@ export interface CellTransformOptions {
23
24
  /** Rewrites module-only syntax in plain JavaScript into script syntax. */
24
25
  export declare function rewriteModuleSyntax(js: string): string;
25
26
  export declare function transformCell(code: string, options?: CellTransformOptions): string;
27
+ /**
28
+ * transformCell, plus the map between the cell's lines and the script's,
29
+ * for the debugger (#18). The rewrite keeps lines (see applyEdits), so the
30
+ * script's lines are esbuild's, after the prelude's one.
31
+ */
32
+ export declare function transformCellWithLines(code: string, options?: CellTransformOptions): {
33
+ script: string;
34
+ lines: LineMap;
35
+ };
36
+ /**
37
+ * Like transformCell, for a target that evaluates cells itself, as global
38
+ * code (an indirect eval), instead of through the inspector's replMode: see
39
+ * hoistForEval. The script's value is a promise of the boxed result.
40
+ */
41
+ export declare function transformCellForEval(code: string, options?: CellTransformOptions): string;
26
42
  /**
27
43
  * Deno treats a cell like `{ "a": 1 }` as an object literal rather than a
28
44
  * block, as browser consoles do. Returns the wrapped form to try first, or
package/dist/transform.js CHANGED
@@ -16,7 +16,8 @@
16
16
  // callback was not specified").
17
17
  import { transformSync } from "esbuild";
18
18
  import { parse } from "acorn";
19
- import { full } from "acorn-walk";
19
+ import { full, recursive } from "acorn-walk";
20
+ import { LineMap } from "./sourcemap.js";
20
21
  export const SHIM = "__cdpk";
21
22
  // Each cell first yields one macrotask. User code then runs as an ordinary
22
23
  // task instead of nested inside the inspector's dispatch of Runtime.evaluate,
@@ -33,7 +34,8 @@ function jsxSettings(jsx) {
33
34
  }
34
35
  return { jsx: "transform", jsxFactory: jsx?.factory, jsxFragment: jsx?.fragment };
35
36
  }
36
- function stripTypes(code, options) {
37
+ /** esbuild's output, with its source map's `mappings` when asked for. */
38
+ function stripTypesMapped(code, options, sourcemap) {
37
39
  const compilerOptions = {
38
40
  verbatimModuleSyntax: true,
39
41
  ...(options.experimentalDecorators ? { experimentalDecorators: true } : {}),
@@ -42,13 +44,19 @@ function stripTypes(code, options) {
42
44
  let firstError;
43
45
  for (const loader of ["tsx", "ts"]) {
44
46
  try {
45
- return transformSync(code, {
47
+ const result = transformSync(code, {
46
48
  loader,
47
49
  target: "esnext",
48
50
  ...jsxSettings(options.jsx),
49
51
  tsconfigRaw: { compilerOptions },
50
52
  logLevel: "silent",
51
- }).code;
53
+ ...(sourcemap ? { sourcemap: "external" } : {}),
54
+ });
55
+ const map = sourcemap ? JSON.parse(result.map) : null;
56
+ const mappings = typeof map?.mappings === "string"
57
+ ? map.mappings
58
+ : "";
59
+ return { code: result.code, mappings };
52
60
  }
53
61
  catch (err) {
54
62
  firstError ??= err;
@@ -57,6 +65,9 @@ function stripTypes(code, options) {
57
65
  const message = firstError instanceof Error ? firstError.message : String(firstError);
58
66
  throw new CellSyntaxError(message.replace(/^Transform failed with \d+ errors?:\n/, ""));
59
67
  }
68
+ function stripTypes(code, options) {
69
+ return stripTypesMapped(code, options, false).code;
70
+ }
60
71
  function importedName(spec) {
61
72
  const imported = spec.imported;
62
73
  if (!imported)
@@ -80,11 +91,9 @@ function rewriteImport(code, node, index) {
80
91
  });
81
92
  return `var ${ns} = ${load}; var ${bindings.join(", ")};`;
82
93
  }
83
- /** Rewrites module-only syntax in plain JavaScript into script syntax. */
84
- export function rewriteModuleSyntax(js) {
85
- let program;
94
+ function parseCell(js) {
86
95
  try {
87
- program = parse(js, {
96
+ return parse(js, {
88
97
  ecmaVersion: "latest",
89
98
  sourceType: "module",
90
99
  allowAwaitOutsideFunction: true,
@@ -94,6 +103,10 @@ export function rewriteModuleSyntax(js) {
94
103
  catch (err) {
95
104
  throw new CellSyntaxError(err instanceof Error ? err.message : String(err));
96
105
  }
106
+ }
107
+ /** Rewrites module-only syntax in plain JavaScript into script syntax. */
108
+ export function rewriteModuleSyntax(js) {
109
+ const program = parseCell(js);
97
110
  const edits = [];
98
111
  let importIndex = 0;
99
112
  full(program, (node) => {
@@ -136,15 +149,164 @@ export function rewriteModuleSyntax(js) {
136
149
  });
137
150
  // Nested edits can't occur (imports/exports are top level, import()'s
138
151
  // keyword edit doesn't overlap its arguments), so apply back to front.
139
- edits.sort((a, b) => b.start - a.start);
152
+ return applyEdits(js, edits);
153
+ }
154
+ function newlines(text) {
155
+ let count = 0;
156
+ for (const char of text)
157
+ if (char === "\n")
158
+ count++;
159
+ return count;
160
+ }
161
+ function applyEdits(js, edits) {
162
+ // Back to front; at a shared start, a replacement goes before an insertion.
163
+ edits.sort((a, b) => b.start - a.start || b.end - a.end);
140
164
  let out = js;
141
- for (const edit of edits)
142
- out = out.slice(0, edit.start) + edit.text + out.slice(edit.end);
165
+ for (const edit of edits) {
166
+ // Keep every later line where it was, so a cell's lines still map to
167
+ // esbuild's (the debugger relies on it, #18): a multi-line import
168
+ // rewritten to one line is padded with the newlines it replaced.
169
+ const lost = newlines(js.slice(edit.start, edit.end)) - newlines(edit.text);
170
+ const text = lost > 0 ? edit.text + "\n".repeat(lost) : edit.text;
171
+ out = out.slice(0, edit.start) + text + out.slice(edit.end);
172
+ }
143
173
  return out;
144
174
  }
175
+ /** Adds the names a binding pattern declares. */
176
+ function patternNames(pattern, names) {
177
+ switch (pattern.type) {
178
+ case "Identifier":
179
+ names.add(pattern.name);
180
+ break;
181
+ case "ObjectPattern":
182
+ for (const prop of pattern.properties)
183
+ patternNames(prop.type === "Property" ? prop.value : prop, names);
184
+ break;
185
+ case "ArrayPattern":
186
+ for (const element of pattern.elements)
187
+ if (element)
188
+ patternNames(element, names);
189
+ break;
190
+ case "RestElement":
191
+ patternNames(pattern.argument, names);
192
+ break;
193
+ case "AssignmentPattern":
194
+ patternNames(pattern.left, names);
195
+ break;
196
+ }
197
+ }
198
+ /**
199
+ * Makes a cell's declarations global without replMode, the tslab/IJavascript
200
+ * technique: the cell runs inside an async function (for top-level await),
201
+ * and every name it declares at the top level is declared with `var` in the
202
+ * surrounding script, which a global-code eval turns into a property of
203
+ * globalThis. Inside the function the declarations become assignments to
204
+ * those globals:
205
+ * const { a } = o; class K {} -> var a, K;
206
+ * (async () => { ({ a } = o); K = class K {}; })()
207
+ * So later cells, and closures from this one, all see one binding. A `var`
208
+ * in a top-level block or loop head is global too, as in a script; block
209
+ * scoped and function-local declarations stay where they are. Functions
210
+ * keep their in-cell hoisting and are copied to globalThis on entry.
211
+ *
212
+ * A trailing expression statement becomes `return [value]`; the box keeps a
213
+ * promise from being awaited, so the cell's result is the promise itself, as
214
+ * in Deno.
215
+ */
216
+ function hoistForEval(js) {
217
+ const program = parseCell(js);
218
+ const names = new Set();
219
+ const functions = [];
220
+ const edits = [];
221
+ const src = (node) => js.slice(node.start, node.end);
222
+ const replace = (node, text) => edits.push({ start: node.start, end: node.end, text });
223
+ // A declarator without an initializer resets the name, except under var,
224
+ // where redeclaring keeps the value.
225
+ const assignments = (decl) => decl.declarations.flatMap((d) => {
226
+ patternNames(d.id, names);
227
+ if (d.init)
228
+ return [`${src(d.id)} = ${src(d.init)}`];
229
+ return decl.kind === "var" ? [] : [`${src(d.id)} = undefined`];
230
+ });
231
+ const statement = (decl) => {
232
+ const parts = assignments(decl);
233
+ replace(decl, parts.length > 0 ? `(${parts.join(", ")});` : ";");
234
+ };
235
+ const isVar = (node) => node?.type === "VariableDeclaration" && node.kind === "var";
236
+ const loopHead = (left) => {
237
+ if (!isVar(left))
238
+ return;
239
+ const id = left.declarations[0].id;
240
+ patternNames(id, names);
241
+ replace(left, src(id));
242
+ };
243
+ // Expressions can't hold statements outside a function or class, so only
244
+ // statement bodies are walked.
245
+ const nestedVars = (node) => recursive(node, null, {
246
+ Function() { },
247
+ Class() { },
248
+ VariableDeclaration(decl) {
249
+ if (decl.kind === "var")
250
+ statement(decl);
251
+ },
252
+ ForStatement(loop, state, walk) {
253
+ if (isVar(loop.init))
254
+ replace(loop.init, assignments(loop.init).join(", "));
255
+ walk(loop.body, state);
256
+ },
257
+ ForInStatement(loop, state, walk) {
258
+ loopHead(loop.left);
259
+ walk(loop.body, state);
260
+ },
261
+ ForOfStatement(loop, state, walk) {
262
+ loopHead(loop.left);
263
+ walk(loop.body, state);
264
+ },
265
+ });
266
+ program.body.forEach((stmt, i) => {
267
+ if (stmt.type === "VariableDeclaration" && (stmt.kind === "var" || stmt.kind === "let" || stmt.kind === "const")) {
268
+ statement(stmt);
269
+ }
270
+ else if (stmt.type === "FunctionDeclaration") {
271
+ names.add(stmt.id.name);
272
+ functions.push(stmt.id.name);
273
+ }
274
+ else if (stmt.type === "ClassDeclaration") {
275
+ names.add(stmt.id.name);
276
+ edits.push({ start: stmt.start, end: stmt.start, text: `${stmt.id.name} = ` });
277
+ edits.push({ start: stmt.end, end: stmt.end, text: ";" });
278
+ }
279
+ else if (stmt.type === "ExpressionStatement" && i === program.body.length - 1) {
280
+ replace(stmt, `return [${src(stmt.expression)}];`);
281
+ }
282
+ else {
283
+ nestedVars(stmt);
284
+ }
285
+ });
286
+ const declare = names.size > 0 ? `var ${[...names].join(", ")};\n` : "";
287
+ const publish = functions.map((name) => ` globalThis.${name} = ${name};`).join("");
288
+ return `${declare}(async () => { 'use strict';${publish}\n${applyEdits(js, edits)}\n})()`;
289
+ }
145
290
  export function transformCell(code, options = {}) {
146
291
  return PRELUDE + rewriteModuleSyntax(stripTypes(code, options));
147
292
  }
293
+ /**
294
+ * transformCell, plus the map between the cell's lines and the script's,
295
+ * for the debugger (#18). The rewrite keeps lines (see applyEdits), so the
296
+ * script's lines are esbuild's, after the prelude's one.
297
+ */
298
+ export function transformCellWithLines(code, options = {}) {
299
+ const stripped = stripTypesMapped(code, options, true);
300
+ return { script: PRELUDE + rewriteModuleSyntax(stripped.code), lines: new LineMap(stripped.mappings, newlines(PRELUDE)) };
301
+ }
302
+ /**
303
+ * Like transformCell, for a target that evaluates cells itself, as global
304
+ * code (an indirect eval), instead of through the inspector's replMode: see
305
+ * hoistForEval. The script's value is a promise of the boxed result.
306
+ */
307
+ export function transformCellForEval(code, options = {}) {
308
+ return hoistForEval(rewriteModuleSyntax(stripTypes(code, options)));
309
+ }
148
310
  /**
149
311
  * Deno treats a cell like `{ "a": 1 }` as an object literal rather than a
150
312
  * block, as browser consoles do. Returns the wrapped form to try first, or
@@ -0,0 +1,125 @@
1
+ import type { CdpParams, EvaluateResult, RemoteObject } from "./cdp.ts";
2
+ import { transformCellForEval } from "./transform.ts";
3
+ import { type KernelTarget, type TargetEvents } from "./target.ts";
4
+ import { type WsChannel } from "./ws-client.ts";
5
+ /** The driver Worker's modules; the first is its main module. */
6
+ export declare const WORKER_MODULES: string[];
7
+ /** See BunTarget: how long an interrupted cell has to show it isn't busy. */
8
+ export declare const INTERRUPT_GRACE_MS = 500;
9
+ export declare function restartNote(runtime: string): string;
10
+ export declare const RESTART_NOTE: string;
11
+ export declare function workerdConfig({ socket, compatibilityDate }: {
12
+ socket: string;
13
+ compatibilityDate: string;
14
+ }): string;
15
+ /**
16
+ * A Workers project has workerd in its node_modules (wrangler and miniflare
17
+ * depend on it), so look there first, from the notebook's directory up;
18
+ * otherwise use the one on PATH.
19
+ */
20
+ export declare function findWorkerd(cwd: string): string;
21
+ /** "workerd 2026-10-15" -> "2026-10-15": the newest date it supports. */
22
+ export declare function compatibilityDateOf(versionOutput: string): string;
23
+ /** The literal specifiers a transformed cell imports, in order. */
24
+ export declare function importSpecifiers(script: string): string[];
25
+ /**
26
+ * Bundles `specifier`, as imported from `cwd`, into global code whose value
27
+ * is a promise of the module's namespace. npm: and jsr: install into the
28
+ * npm cache, as on a Node target. Builtins stay external and are handed to
29
+ * the bundle as `require` (workerd-worker.mjs's requireFor). A specifier
30
+ * that can't be bundled becomes code that throws when imported, so the
31
+ * error appears in the cell.
32
+ */
33
+ export declare function bundleModule(specifier: string, cwd: string): Promise<string>;
34
+ /** What import.meta says in a cell: the notebook's directory, not workerd's. */
35
+ export declare function cellMeta(cwd: string): {
36
+ url: string;
37
+ dirname: string;
38
+ filename: string;
39
+ };
40
+ /**
41
+ * How the target reaches its driver Worker: a workerd of its own
42
+ * (RawWorkerd, below), or a Workers project's Miniflare
43
+ * (src/workers-project.ts), which adds the project's bindings.
44
+ */
45
+ export interface WorkerHost {
46
+ /** The runtime's name for the banner: workerd's date, or Miniflare's version. */
47
+ readonly runtime: string;
48
+ /** The wrangler config whose bindings the driver has, if any. */
49
+ readonly project?: string;
50
+ /** The open session with the driver. */
51
+ readonly channel: WsChannel;
52
+ /** Stops the runtime; `now` even while a cell is busy. */
53
+ stop(now: boolean): void;
54
+ onExit(listener: (code: number | null) => void): void;
55
+ }
56
+ /** The driver on a workerd of its own, behind a Unix socket. */
57
+ export declare class RawWorkerd implements WorkerHost {
58
+ #private;
59
+ readonly runtime: string;
60
+ readonly channel: WsChannel;
61
+ private constructor();
62
+ static start(cwd: string, executable?: string): Promise<RawWorkerd>;
63
+ stop(now: boolean): void;
64
+ onExit(listener: (code: number | null) => void): void;
65
+ }
66
+ /** A runtime that runs the driver Worker: workerd, or celld (src/celld-target.ts). */
67
+ export type WorkersRuntime = "workerd" | "celld";
68
+ export declare class WorkerdTarget implements KernelTarget {
69
+ #private;
70
+ readonly runtime: WorkersRuntime;
71
+ readonly versions: {
72
+ runtime: string;
73
+ engine: string;
74
+ };
75
+ notice: string | undefined;
76
+ readonly transform: typeof transformCellForEval;
77
+ private constructor();
78
+ /**
79
+ * In a Workers project (a wrangler config at or above `cwd`), the
80
+ * project's own Miniflare runs the driver with the project's bindings;
81
+ * otherwise a workerd of its own does (#26).
82
+ */
83
+ static launch(events: TargetEvents, options?: {
84
+ cwd?: string;
85
+ executable?: string;
86
+ }): Promise<WorkerdTarget>;
87
+ /**
88
+ * A target over a started host's session. `notice` (a project that
89
+ * failed to load) is replaced by the bindings when the host has a project.
90
+ */
91
+ static open(host: WorkerHost, cwd: string, events: TargetEvents, runtime: WorkersRuntime, notice?: string): Promise<WorkerdTarget>;
92
+ evaluate(script: string): Promise<EvaluateResult>;
93
+ /**
94
+ * A cell that's waiting on something leaves the driver free: it answers a
95
+ * ping, and the cell is abandoned with the session intact (its pending
96
+ * work still runs, as on Bun). A busy cell can't be reached, so workerd is
97
+ * stopped and restarts on the next cell.
98
+ */
99
+ interrupt(): Promise<void>;
100
+ /** Output arrives on the session before the reply it precedes. */
101
+ flush(): Promise<void>;
102
+ broadcastResult(executionCount: number, result: RemoteObject): Promise<void>;
103
+ dispatchComm(msgType: string, content: CdpParams, metadata: CdpParams, buffers: Uint8Array[]): Promise<{
104
+ handled: boolean;
105
+ } | {
106
+ error: {
107
+ name: string;
108
+ message: string;
109
+ stack: string;
110
+ };
111
+ }>;
112
+ describeError(exception: RemoteObject): Promise<{
113
+ name: string;
114
+ message: string;
115
+ stack: string;
116
+ }>;
117
+ propertyNames(expression: string): Promise<string[]>;
118
+ /** Resolved by property descriptor in the driver, so nothing runs (#10). */
119
+ inspect(path: string, detail: number): Promise<string | null>;
120
+ /** None: top-level declarations here are properties of globalThis. */
121
+ lexicalNames(): Promise<string[]>;
122
+ /** Never asked for: prompt() in workerd answers null without asking. */
123
+ replyInput(): void;
124
+ kill(): void;
125
+ }