@tlockney/cdp-kernel 0.6.0 → 0.7.1
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 +5 -3
- package/dist/browser/channels.d.ts +27 -0
- package/dist/browser/channels.js +90 -0
- package/dist/browser/kernel.js +29800 -0
- package/dist/browser/kernel.js.map +7 -0
- package/dist/browser/mod.d.ts +25 -0
- package/dist/browser/mod.js +41 -0
- package/dist/browser/target.d.ts +94 -0
- package/dist/browser/target.js +264 -0
- package/dist/browser/worker.js +1071 -0
- package/dist/browser/worker.js.map +7 -0
- package/dist/bun-target.d.ts +2 -0
- package/dist/bun-target.js +15 -2
- package/dist/cdp.d.ts +11 -0
- package/dist/cdp.js +34 -7
- package/dist/celld-target.js +3 -2
- package/dist/debugger.d.ts +2 -0
- package/dist/debugger.js +63 -11
- package/dist/kernel-core.d.ts +78 -0
- package/dist/kernel-core.js +824 -0
- package/dist/kernel.d.ts +6 -1
- package/dist/kernel.js +104 -723
- package/dist/main.js +11 -4
- package/dist/message.d.ts +34 -0
- package/dist/message.js +14 -0
- package/dist/package.d.ts +2 -2
- package/dist/package.js +2 -2
- package/dist/target-api.d.ts +92 -0
- package/dist/target-api.js +48 -0
- package/dist/target.d.ts +5 -76
- package/dist/target.js +62 -33
- package/dist/traceback.d.ts +75 -0
- package/dist/traceback.js +200 -0
- package/dist/transform.d.ts +1 -0
- package/dist/transform.js +8 -1
- package/dist/wire.d.ts +4 -24
- package/dist/wire.js +3 -12
- package/dist/workerd-target.d.ts +6 -1
- package/dist/workerd-target.js +56 -12
- package/dist/workers-project.d.ts +1 -1
- package/dist/workers-project.js +4 -3
- package/dist/zmq-channels.d.ts +14 -0
- package/dist/zmq-channels.js +59 -0
- package/package.json +9 -2
- package/runtime/bootstrap.mjs +2 -0
- package/runtime/browser-worker.mjs +202 -0
- package/runtime/cdn.d.mts +2 -0
- package/runtime/cdn.mjs +17 -0
- package/runtime/display.mjs +202 -1
- package/runtime/evaluator.mjs +2 -0
- package/runtime/format.d.mts +2 -0
- package/runtime/format.mjs +125 -0
- package/runtime/workerd-worker.mjs +2 -0
package/dist/main.js
CHANGED
|
@@ -31,7 +31,17 @@ function kernelsDir() {
|
|
|
31
31
|
return join(process.env.APPDATA ?? homedir(), "jupyter", "kernels");
|
|
32
32
|
return join(process.env.XDG_DATA_HOME ?? join(homedir(), ".local", "share"), "jupyter", "kernels");
|
|
33
33
|
}
|
|
34
|
+
// Jupyter's kernel names; anything else could point outside the kernels
|
|
35
|
+
// directory.
|
|
36
|
+
const KERNEL_NAME = /^[A-Za-z0-9._-]+$/;
|
|
37
|
+
function isKernelName(name) {
|
|
38
|
+
return KERNEL_NAME.test(name) && name !== "." && name !== "..";
|
|
39
|
+
}
|
|
34
40
|
function install(runtime, denoCompat, typeStrip, languageService, name, display) {
|
|
41
|
+
if (!isKernelName(name)) {
|
|
42
|
+
console.error(`install: invalid kernelspec name ${JSON.stringify(name)}; use letters, digits, '.', '_' and '-'`);
|
|
43
|
+
process.exit(2);
|
|
44
|
+
}
|
|
35
45
|
const dir = join(kernelsDir(), name);
|
|
36
46
|
mkdirSync(dir, { recursive: true });
|
|
37
47
|
const spec = {
|
|
@@ -97,9 +107,6 @@ function list() {
|
|
|
97
107
|
console.log(`${s.name.padEnd(width)} ${s.runtime.padEnd(7)} ${(s.version ?? "-").padEnd(7)} ${s.dir}`);
|
|
98
108
|
}
|
|
99
109
|
}
|
|
100
|
-
// Jupyter's kernel names; anything else could point outside the kernels
|
|
101
|
-
// directory.
|
|
102
|
-
const KERNEL_NAME = /^[A-Za-z0-9._-]+$/;
|
|
103
110
|
function uninstall(names, all) {
|
|
104
111
|
if (all)
|
|
105
112
|
names = installedSpecs().map((s) => s.name);
|
|
@@ -110,7 +117,7 @@ function uninstall(names, all) {
|
|
|
110
117
|
}
|
|
111
118
|
let failed = false;
|
|
112
119
|
for (const name of names) {
|
|
113
|
-
const valid =
|
|
120
|
+
const valid = isKernelName(name);
|
|
114
121
|
const spec = valid ? readOwnSpec(name) : undefined;
|
|
115
122
|
if (!spec) {
|
|
116
123
|
const exists = valid && existsSync(join(kernelsDir(), name));
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare const PROTOCOL_VERSION = "5.3";
|
|
2
|
+
export type JsonObject = {
|
|
3
|
+
[key: string]: unknown;
|
|
4
|
+
};
|
|
5
|
+
export interface Header extends JsonObject {
|
|
6
|
+
msg_id: string;
|
|
7
|
+
session: string;
|
|
8
|
+
date: string;
|
|
9
|
+
username: string;
|
|
10
|
+
msg_type: string;
|
|
11
|
+
version: string;
|
|
12
|
+
}
|
|
13
|
+
/** A header as received: the fields the kernel relies on, plus whatever else came. */
|
|
14
|
+
export interface ReceivedHeader extends JsonObject {
|
|
15
|
+
msg_id: string;
|
|
16
|
+
msg_type: string;
|
|
17
|
+
}
|
|
18
|
+
/** A message from a frontend, decoded (and on ZeroMQ, verified). */
|
|
19
|
+
export interface KernelMessage {
|
|
20
|
+
header: ReceivedHeader;
|
|
21
|
+
parentHeader: JsonObject;
|
|
22
|
+
metadata: JsonObject;
|
|
23
|
+
content: JsonObject;
|
|
24
|
+
buffers: Uint8Array[];
|
|
25
|
+
}
|
|
26
|
+
/** A message the kernel sends. */
|
|
27
|
+
export interface OutgoingMessage {
|
|
28
|
+
header: Header;
|
|
29
|
+
parentHeader: JsonObject;
|
|
30
|
+
metadata: JsonObject;
|
|
31
|
+
content: JsonObject;
|
|
32
|
+
buffers: Uint8Array[];
|
|
33
|
+
}
|
|
34
|
+
export declare function makeHeader(session: string, msgType: string): Header;
|
package/dist/message.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Jupyter message shapes and headers, without the wire format: what the
|
|
2
|
+
// kernel's message handling (src/kernel-core.ts) builds and reads. The
|
|
3
|
+
// framing and HMAC signing that ZeroMQ peers need are in src/wire.ts.
|
|
4
|
+
export const PROTOCOL_VERSION = "5.3";
|
|
5
|
+
export function makeHeader(session, msgType) {
|
|
6
|
+
return {
|
|
7
|
+
msg_id: crypto.randomUUID(),
|
|
8
|
+
session,
|
|
9
|
+
date: new Date().toISOString(),
|
|
10
|
+
username: "kernel",
|
|
11
|
+
msg_type: msgType,
|
|
12
|
+
version: PROTOCOL_VERSION,
|
|
13
|
+
};
|
|
14
|
+
}
|
package/dist/package.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/** Kept equal to package.json and deno.jsonc by test/package.test.ts. */
|
|
2
|
-
export declare const VERSION = "0.
|
|
2
|
+
export declare const VERSION = "0.7.1";
|
|
3
3
|
/**
|
|
4
4
|
* The UTC day this version was released, set with VERSION. The publish
|
|
5
5
|
* workflow refuses a tag unless it's today or yesterday, so it can't go
|
|
6
6
|
* stale: see dependencyCutoff.
|
|
7
7
|
*/
|
|
8
|
-
export declare const RELEASE_DATE = "2026-10-
|
|
8
|
+
export declare const RELEASE_DATE = "2026-10-19";
|
|
9
9
|
/**
|
|
10
10
|
* Deno blocks packages less than 24 hours old (minimum dependency age), so
|
|
11
11
|
* a kernelspec relaunching a release from JSR would fail on release day. It
|
package/dist/package.js
CHANGED
|
@@ -14,13 +14,13 @@ import { join, sep } from "node:path";
|
|
|
14
14
|
import process from "node:process";
|
|
15
15
|
import { fileURLToPath } from "node:url";
|
|
16
16
|
/** Kept equal to package.json and deno.jsonc by test/package.test.ts. */
|
|
17
|
-
export const VERSION = "0.
|
|
17
|
+
export const VERSION = "0.7.1";
|
|
18
18
|
/**
|
|
19
19
|
* The UTC day this version was released, set with VERSION. The publish
|
|
20
20
|
* workflow refuses a tag unless it's today or yesterday, so it can't go
|
|
21
21
|
* stale: see dependencyCutoff.
|
|
22
22
|
*/
|
|
23
|
-
export const RELEASE_DATE = "2026-10-
|
|
23
|
+
export const RELEASE_DATE = "2026-10-19";
|
|
24
24
|
/**
|
|
25
25
|
* Deno blocks packages less than 24 hours old (minimum dependency age), so
|
|
26
26
|
* a kernelspec relaunching a release from JSR would fail on release day. It
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { CdpParams, EvaluateResult, RemoteObject } from "./cdp.ts";
|
|
2
|
+
import type { DebugChannel } from "./debugger.ts";
|
|
3
|
+
import type { CellTransformOptions } from "./transform.ts";
|
|
4
|
+
/** Targets driven over CDP. */
|
|
5
|
+
export type CdpRuntime = "node" | "deno";
|
|
6
|
+
/** Bun, workerd and celld have their own backends: src/bun-target.ts, src/workerd-target.ts, src/celld-target.ts. */
|
|
7
|
+
export type RuntimeName = CdpRuntime | "bun" | "workerd" | "celld";
|
|
8
|
+
/** Every target: the runtimes a kernelspec names, and the browser's Worker (src/browser/). */
|
|
9
|
+
export type TargetRuntime = RuntimeName | "browser";
|
|
10
|
+
/** What the kernel needs from a target runtime. */
|
|
11
|
+
export interface KernelTarget {
|
|
12
|
+
readonly runtime: TargetRuntime;
|
|
13
|
+
readonly versions: {
|
|
14
|
+
runtime: string;
|
|
15
|
+
engine: string;
|
|
16
|
+
};
|
|
17
|
+
/** Shown once, in the first cell: e.g. which project's bindings loaded. */
|
|
18
|
+
readonly notice?: string;
|
|
19
|
+
/** Turns a cell into the script evaluate() takes. */
|
|
20
|
+
transform(code: string, options: CellTransformOptions): string;
|
|
21
|
+
/** Runs a transformed cell. Rejects with Interrupted after interrupt(). */
|
|
22
|
+
evaluate(script: string): Promise<EvaluateResult>;
|
|
23
|
+
interrupt(): Promise<void>;
|
|
24
|
+
/** Resolves once all output and messages sent so far have been delivered. */
|
|
25
|
+
flush(): Promise<void>;
|
|
26
|
+
broadcastResult(executionCount: number, result: RemoteObject): Promise<void>;
|
|
27
|
+
/** A value's MIME bundle, as a cell's result would show it: for user_expressions (#340). */
|
|
28
|
+
format(value: RemoteObject): Promise<CdpParams>;
|
|
29
|
+
dispatchComm(msgType: string, content: CdpParams, metadata: CdpParams, buffers: Uint8Array[]): Promise<{
|
|
30
|
+
handled: boolean;
|
|
31
|
+
} | {
|
|
32
|
+
error: {
|
|
33
|
+
name: string;
|
|
34
|
+
message: string;
|
|
35
|
+
stack: string;
|
|
36
|
+
};
|
|
37
|
+
}>;
|
|
38
|
+
describeError(exception: RemoteObject): Promise<{
|
|
39
|
+
name: string;
|
|
40
|
+
message: string;
|
|
41
|
+
stack: string;
|
|
42
|
+
}>;
|
|
43
|
+
propertyNames(expression: string): Promise<string[]>;
|
|
44
|
+
lexicalNames(): Promise<string[]>;
|
|
45
|
+
/** inspect_request (#10): text describing a dotted path's value, without running anything. */
|
|
46
|
+
inspect(path: string, detail: number): Promise<string | null>;
|
|
47
|
+
/** The Debugger domain, on targets driven over CDP (#18). */
|
|
48
|
+
readonly debug?: DebugChannel;
|
|
49
|
+
/** Answers the target's pending prompt; `interrupted` makes it throw instead (#121). */
|
|
50
|
+
replyInput(value: string | null, interrupted?: boolean): void;
|
|
51
|
+
/** What the host waits on, for a kernel that has stopped answering (#237). */
|
|
52
|
+
diagnose?(): Promise<CdpParams>;
|
|
53
|
+
/** Lets go of the last cell's result and error, once they are shown (#286). */
|
|
54
|
+
releaseResults?(): Promise<void>;
|
|
55
|
+
kill(): void;
|
|
56
|
+
}
|
|
57
|
+
/** Messages the bootstrap sends: message records on stdout, or Bun's channel. */
|
|
58
|
+
export type TargetMessage = {
|
|
59
|
+
kind: "iopub";
|
|
60
|
+
msg_type: string;
|
|
61
|
+
content: CdpParams;
|
|
62
|
+
metadata: CdpParams;
|
|
63
|
+
buffers: string[];
|
|
64
|
+
barrier: number;
|
|
65
|
+
} | {
|
|
66
|
+
kind: "input_request";
|
|
67
|
+
prompt: string;
|
|
68
|
+
password: boolean;
|
|
69
|
+
barrier: number;
|
|
70
|
+
};
|
|
71
|
+
/** A MIME bundle the target sent as JSON text; empty if it isn't one. */
|
|
72
|
+
export declare function parseBundle(text: unknown): CdpParams;
|
|
73
|
+
/** How long a target may take from launch to a usable session. */
|
|
74
|
+
export declare const START_TIMEOUT_MS = 60000;
|
|
75
|
+
/**
|
|
76
|
+
* `start`, or a rejection once `ms` pass without it settling. The caller
|
|
77
|
+
* stops whatever was starting: a runtime that never becomes ready would
|
|
78
|
+
* otherwise wedge the first cell (#52, #336).
|
|
79
|
+
*/
|
|
80
|
+
export declare function withStartTimeout<T>(start: Promise<T>, what: string, ms?: number): Promise<T>;
|
|
81
|
+
/** The parsed value, or undefined for text that isn't JSON. */
|
|
82
|
+
export declare function parseJson(text: string): unknown;
|
|
83
|
+
export declare function isTargetMessage(value: unknown): value is TargetMessage;
|
|
84
|
+
export interface TargetEvents {
|
|
85
|
+
stream(name: "stdout" | "stderr", text: string): void;
|
|
86
|
+
message(msg: TargetMessage): void;
|
|
87
|
+
/** `note` says why, when the target was stopped on purpose. */
|
|
88
|
+
exit(code: number | null, note?: string): void;
|
|
89
|
+
}
|
|
90
|
+
export declare class Interrupted extends Error {
|
|
91
|
+
name: string;
|
|
92
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// What the kernel needs from a target runtime, and what a target sends
|
|
2
|
+
// back: the part of src/target.ts with no Node imports, so the kernel's
|
|
3
|
+
// message handling (src/kernel-core.ts) also loads in a browser.
|
|
4
|
+
/** A MIME bundle the target sent as JSON text; empty if it isn't one. */
|
|
5
|
+
export function parseBundle(text) {
|
|
6
|
+
const bundle = typeof text === "string" ? parseJson(text) : undefined;
|
|
7
|
+
return typeof bundle === "object" && bundle !== null && !Array.isArray(bundle) ? bundle : {};
|
|
8
|
+
}
|
|
9
|
+
/** How long a target may take from launch to a usable session. */
|
|
10
|
+
export const START_TIMEOUT_MS = 60_000;
|
|
11
|
+
/**
|
|
12
|
+
* `start`, or a rejection once `ms` pass without it settling. The caller
|
|
13
|
+
* stops whatever was starting: a runtime that never becomes ready would
|
|
14
|
+
* otherwise wedge the first cell (#52, #336).
|
|
15
|
+
*/
|
|
16
|
+
export async function withStartTimeout(start, what, ms = START_TIMEOUT_MS) {
|
|
17
|
+
// Its own rejection, once the deadline has passed, is the caller's to ignore.
|
|
18
|
+
start.catch(() => { });
|
|
19
|
+
let timer;
|
|
20
|
+
const stalled = new Promise((_, reject) => {
|
|
21
|
+
timer = setTimeout(() => reject(new Error(`${what} did not start within ${ms / 1000}s`)), ms);
|
|
22
|
+
});
|
|
23
|
+
try {
|
|
24
|
+
return await Promise.race([start, stalled]);
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
clearTimeout(timer);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** The parsed value, or undefined for text that isn't JSON. */
|
|
31
|
+
export function parseJson(text) {
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(text);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function isTargetMessage(value) {
|
|
40
|
+
if (typeof value !== "object" || value === null)
|
|
41
|
+
return false;
|
|
42
|
+
const kind = value.kind;
|
|
43
|
+
return (kind === "iopub" || kind === "input_request") &&
|
|
44
|
+
typeof value.barrier === "number";
|
|
45
|
+
}
|
|
46
|
+
export class Interrupted extends Error {
|
|
47
|
+
name = "Interrupted";
|
|
48
|
+
}
|
package/dist/target.d.ts
CHANGED
|
@@ -1,55 +1,9 @@
|
|
|
1
1
|
import { type CdpParams, type EvaluateResult, type RemoteObject } from "./cdp.ts";
|
|
2
|
-
import {
|
|
2
|
+
import { transformCell } from "./transform.ts";
|
|
3
3
|
import type { DebugChannel } from "./debugger.ts";
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
export type RuntimeName = CdpRuntime | "bun" | "workerd" | "celld";
|
|
8
|
-
/** What the kernel needs from a target runtime. */
|
|
9
|
-
export interface KernelTarget {
|
|
10
|
-
readonly runtime: RuntimeName;
|
|
11
|
-
readonly versions: {
|
|
12
|
-
runtime: string;
|
|
13
|
-
engine: string;
|
|
14
|
-
};
|
|
15
|
-
/** Shown once, in the first cell: e.g. which project's bindings loaded. */
|
|
16
|
-
readonly notice?: string;
|
|
17
|
-
/** Turns a cell into the script evaluate() takes. */
|
|
18
|
-
transform(code: string, options: CellTransformOptions): string;
|
|
19
|
-
/** Runs a transformed cell. Rejects with Interrupted after interrupt(). */
|
|
20
|
-
evaluate(script: string): Promise<EvaluateResult>;
|
|
21
|
-
interrupt(): Promise<void>;
|
|
22
|
-
/** Resolves once all output and messages sent so far have been delivered. */
|
|
23
|
-
flush(): Promise<void>;
|
|
24
|
-
broadcastResult(executionCount: number, result: RemoteObject): Promise<void>;
|
|
25
|
-
dispatchComm(msgType: string, content: CdpParams, metadata: CdpParams, buffers: Uint8Array[]): Promise<{
|
|
26
|
-
handled: boolean;
|
|
27
|
-
} | {
|
|
28
|
-
error: {
|
|
29
|
-
name: string;
|
|
30
|
-
message: string;
|
|
31
|
-
stack: string;
|
|
32
|
-
};
|
|
33
|
-
}>;
|
|
34
|
-
describeError(exception: RemoteObject): Promise<{
|
|
35
|
-
name: string;
|
|
36
|
-
message: string;
|
|
37
|
-
stack: string;
|
|
38
|
-
}>;
|
|
39
|
-
propertyNames(expression: string): Promise<string[]>;
|
|
40
|
-
lexicalNames(): Promise<string[]>;
|
|
41
|
-
/** inspect_request (#10): text describing a dotted path's value, without running anything. */
|
|
42
|
-
inspect(path: string, detail: number): Promise<string | null>;
|
|
43
|
-
/** The Debugger domain, on targets driven over CDP (#18). */
|
|
44
|
-
readonly debug?: DebugChannel;
|
|
45
|
-
/** Answers the target's pending prompt; `interrupted` makes it throw instead (#121). */
|
|
46
|
-
replyInput(value: string | null, interrupted?: boolean): void;
|
|
47
|
-
/** What the host waits on, for a kernel that has stopped answering (#237). */
|
|
48
|
-
diagnose?(): Promise<CdpParams>;
|
|
49
|
-
/** Lets go of the last cell's result and error, once they are shown (#286). */
|
|
50
|
-
releaseResults?(): Promise<void>;
|
|
51
|
-
kill(): void;
|
|
52
|
-
}
|
|
4
|
+
import { type CdpRuntime, Interrupted, isTargetMessage, type KernelTarget, parseBundle, parseJson, type TargetEvents, type TargetMessage } from "./target-api.ts";
|
|
5
|
+
export { Interrupted, isTargetMessage, parseBundle, parseJson };
|
|
6
|
+
export type { CdpRuntime, KernelTarget, RuntimeName, TargetEvents, TargetMessage } from "./target-api.ts";
|
|
53
7
|
export interface LaunchOptions {
|
|
54
8
|
/** Runtime binary; defaults to `deno`, or `node` (this one when hosted by Node). */
|
|
55
9
|
executable?: string;
|
|
@@ -68,23 +22,6 @@ export declare function launchCommand(runtime: CdpRuntime, bootstrap: string, {
|
|
|
68
22
|
* install and in Deno's npm cache alike.
|
|
69
23
|
*/
|
|
70
24
|
export declare function esbuildBinary(resolve?: (specifier: string) => string, platform?: string, arch?: string): string | null;
|
|
71
|
-
/** Messages the bootstrap sends: message records on stdout, or Bun's channel. */
|
|
72
|
-
export type TargetMessage = {
|
|
73
|
-
kind: "iopub";
|
|
74
|
-
msg_type: string;
|
|
75
|
-
content: CdpParams;
|
|
76
|
-
metadata: CdpParams;
|
|
77
|
-
buffers: string[];
|
|
78
|
-
barrier: number;
|
|
79
|
-
} | {
|
|
80
|
-
kind: "input_request";
|
|
81
|
-
prompt: string;
|
|
82
|
-
password: boolean;
|
|
83
|
-
barrier: number;
|
|
84
|
-
};
|
|
85
|
-
/** The parsed value, or undefined for text that isn't JSON. */
|
|
86
|
-
export declare function parseJson(text: string): unknown;
|
|
87
|
-
export declare function isTargetMessage(value: unknown): value is TargetMessage;
|
|
88
25
|
/**
|
|
89
26
|
* Splits one output pipe into text and barrier markers, and releases them
|
|
90
27
|
* in order. A gated marker (one that announces a message) pauses
|
|
@@ -134,15 +71,6 @@ export declare class Gates {
|
|
|
134
71
|
open(n: number): void;
|
|
135
72
|
openAll(): void;
|
|
136
73
|
}
|
|
137
|
-
export interface TargetEvents {
|
|
138
|
-
stream(name: "stdout" | "stderr", text: string): void;
|
|
139
|
-
message(msg: TargetMessage): void;
|
|
140
|
-
/** `note` says why, when the target was stopped on purpose. */
|
|
141
|
-
exit(code: number | null, note?: string): void;
|
|
142
|
-
}
|
|
143
|
-
export declare class Interrupted extends Error {
|
|
144
|
-
name: string;
|
|
145
|
-
}
|
|
146
74
|
export declare class Target implements KernelTarget {
|
|
147
75
|
#private;
|
|
148
76
|
readonly runtime: CdpRuntime;
|
|
@@ -188,6 +116,7 @@ export declare class Target implements KernelTarget {
|
|
|
188
116
|
callFunctionOn(functionDeclaration: string, args: CdpParams[]): Promise<CdpParams>;
|
|
189
117
|
/** The broadcastResult step of Deno's execute flow (jupyter/mod.rs). */
|
|
190
118
|
broadcastResult(executionCount: number, result: RemoteObject): Promise<void>;
|
|
119
|
+
format(value: RemoteObject): Promise<CdpParams>;
|
|
191
120
|
/**
|
|
192
121
|
* Hands a frontend comm message to the target's comms. Resolves to
|
|
193
122
|
* whether a comm or registered target took it, or to the error a handler
|
package/dist/target.js
CHANGED
|
@@ -11,6 +11,8 @@ import { asEvaluateResult, CdpAbandoned, CdpError, CdpSession } from "./cdp.js";
|
|
|
11
11
|
import { SHIM, transformCell } from "./transform.js";
|
|
12
12
|
import { hostRuntime, isInsideNodeModules, runtimeDir } from "./package.js";
|
|
13
13
|
import { killOnExit } from "./children.js";
|
|
14
|
+
import { Interrupted, isTargetMessage, parseBundle, parseJson, withStartTimeout, } from "./target-api.js";
|
|
15
|
+
export { Interrupted, isTargetMessage, parseBundle, parseJson };
|
|
14
16
|
/**
|
|
15
17
|
* The inspector keeps every object it returns a remote reference to alive
|
|
16
18
|
* until it is released, so a cell's result would never be collected (#286).
|
|
@@ -19,8 +21,6 @@ import { killOnExit } from "./children.js";
|
|
|
19
21
|
*/
|
|
20
22
|
const CELL_GROUP = "cdpk-cell";
|
|
21
23
|
const LOOKUP_GROUP = "cdpk-lookup";
|
|
22
|
-
/** How long a target may take from spawn to a usable session. */
|
|
23
|
-
const START_TIMEOUT_MS = 60_000;
|
|
24
24
|
const MARKER_RE = /\x1b\[cdpk:(\d+)(m?)\]\x1b/;
|
|
25
25
|
const MAX_MARKER_LEN = 24;
|
|
26
26
|
// Lines the runtimes print to stderr on their own: inspector notices, and
|
|
@@ -84,22 +84,6 @@ export function esbuildBinary(resolve = import.meta.resolve, platform = process.
|
|
|
84
84
|
return null;
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
-
/** The parsed value, or undefined for text that isn't JSON. */
|
|
88
|
-
export function parseJson(text) {
|
|
89
|
-
try {
|
|
90
|
-
return JSON.parse(text);
|
|
91
|
-
}
|
|
92
|
-
catch {
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
export function isTargetMessage(value) {
|
|
97
|
-
if (typeof value !== "object" || value === null)
|
|
98
|
-
return false;
|
|
99
|
-
const kind = value.kind;
|
|
100
|
-
return (kind === "iopub" || kind === "input_request") &&
|
|
101
|
-
typeof value.barrier === "number";
|
|
102
|
-
}
|
|
103
87
|
const MARKER_PREFIX = "\x1b[cdpk:";
|
|
104
88
|
// A message record: the message's JSON, which never holds a raw ESC, between
|
|
105
89
|
// "\x1b[cdpk:<" and "\x1b]" (#271).
|
|
@@ -327,9 +311,6 @@ export class Gates {
|
|
|
327
311
|
this.#map.clear();
|
|
328
312
|
}
|
|
329
313
|
}
|
|
330
|
-
export class Interrupted extends Error {
|
|
331
|
-
name = "Interrupted";
|
|
332
|
-
}
|
|
333
314
|
/** A catch handler: a call interrupt() abandoned becomes Interrupted. */
|
|
334
315
|
function interrupted(what) {
|
|
335
316
|
return (err) => {
|
|
@@ -351,6 +332,9 @@ export class Target {
|
|
|
351
332
|
#undelivered = 0;
|
|
352
333
|
#interrupted = false;
|
|
353
334
|
#paused = false;
|
|
335
|
+
/** What the debugger asked to pause on (#307), and how many kernel calls hold it off. */
|
|
336
|
+
#pauseOnExceptions = "none";
|
|
337
|
+
#unpausable = 0;
|
|
354
338
|
/** Set once the main context is gone: the runtime is exiting (#130). */
|
|
355
339
|
#exiting = false;
|
|
356
340
|
#exited;
|
|
@@ -400,13 +384,8 @@ export class Target {
|
|
|
400
384
|
// A start that fails or stalls must not leave the runtime running: its
|
|
401
385
|
// pipes and inspector sockets would keep this process alive (#52).
|
|
402
386
|
const sessions = [];
|
|
403
|
-
const timeoutMs = options.startTimeoutMs ?? START_TIMEOUT_MS;
|
|
404
|
-
let timer;
|
|
405
|
-
const stalled = new Promise((_, reject) => {
|
|
406
|
-
timer = setTimeout(() => reject(new Error(`${cmd} did not start within ${timeoutMs / 1000}s`)), timeoutMs);
|
|
407
|
-
});
|
|
408
387
|
try {
|
|
409
|
-
return await
|
|
388
|
+
return await withStartTimeout(Target.#start(runtime, events, cmd, child, sessions), cmd, options.startTimeoutMs);
|
|
410
389
|
}
|
|
411
390
|
catch (error) {
|
|
412
391
|
for (const session of sessions)
|
|
@@ -414,9 +393,6 @@ export class Target {
|
|
|
414
393
|
child.kill();
|
|
415
394
|
throw error;
|
|
416
395
|
}
|
|
417
|
-
finally {
|
|
418
|
-
clearTimeout(timer);
|
|
419
|
-
}
|
|
420
396
|
}
|
|
421
397
|
static async #start(runtime, events, cmd, child, sessions) {
|
|
422
398
|
child.stdout.setEncoding("utf8");
|
|
@@ -484,6 +460,15 @@ export class Target {
|
|
|
484
460
|
if (params.executionContextId === contextId && target)
|
|
485
461
|
target.#onExit();
|
|
486
462
|
});
|
|
463
|
+
// A session that closes on its own (e.g. a frame that isn't JSON, #337)
|
|
464
|
+
// leaves a target nothing can drive: stop it, so the next cell starts
|
|
465
|
+
// a fresh one.
|
|
466
|
+
for (const session of [shell, control]) {
|
|
467
|
+
session.onClose(() => {
|
|
468
|
+
if (target)
|
|
469
|
+
target.#onExit();
|
|
470
|
+
});
|
|
471
|
+
}
|
|
487
472
|
// Wait for the bootstrap's top-level await to finish installing the
|
|
488
473
|
// shim. There is no cap here: launch's start timeout bounds the wait and
|
|
489
474
|
// kills the child, so a slow bootstrap never yields a target without
|
|
@@ -511,12 +496,43 @@ export class Target {
|
|
|
511
496
|
/** The Debugger domain on this target's session, for src/debugger.ts. */
|
|
512
497
|
get debug() {
|
|
513
498
|
return {
|
|
514
|
-
send: (method, params = {}) =>
|
|
499
|
+
send: (method, params = {}) => {
|
|
500
|
+
if (method === "Debugger.setPauseOnExceptions") {
|
|
501
|
+
this.#pauseOnExceptions = String(params.state ?? "none");
|
|
502
|
+
// Applied when the kernel's own call in flight finishes.
|
|
503
|
+
if (this.#unpausable > 0)
|
|
504
|
+
return Promise.resolve({});
|
|
505
|
+
}
|
|
506
|
+
if (method === "Debugger.disable")
|
|
507
|
+
this.#pauseOnExceptions = "none";
|
|
508
|
+
return this.#shell.send(method, params);
|
|
509
|
+
},
|
|
515
510
|
on: (method, listener) => this.#shell.on(method, listener),
|
|
516
511
|
contextId: this.#contextId,
|
|
517
512
|
baselineGlobals: this.#baselineGlobals,
|
|
513
|
+
withoutPausing: (call) => this.#withoutPausing(call),
|
|
518
514
|
};
|
|
519
515
|
}
|
|
516
|
+
/**
|
|
517
|
+
* Runs the kernel's own inspector call with pausing on exceptions off. A
|
|
518
|
+
* pause inside a call the inspector dispatches holds that call (Node), or
|
|
519
|
+
* resumes by itself and leaves Deno's event loop stopped for good, so no
|
|
520
|
+
* later cell runs (#307). A cell that throws meanwhile doesn't pause.
|
|
521
|
+
*/
|
|
522
|
+
async #withoutPausing(call) {
|
|
523
|
+
if (this.#pauseOnExceptions === "none" || this.#paused)
|
|
524
|
+
return call();
|
|
525
|
+
if (this.#unpausable++ === 0)
|
|
526
|
+
await this.#shell.send("Debugger.setPauseOnExceptions", { state: "none" });
|
|
527
|
+
try {
|
|
528
|
+
return await call();
|
|
529
|
+
}
|
|
530
|
+
finally {
|
|
531
|
+
if (--this.#unpausable === 0 && !this.#exiting) {
|
|
532
|
+
await this.#shell.send("Debugger.setPauseOnExceptions", { state: this.#pauseOnExceptions }).catch(() => { });
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
520
536
|
// Messages wait until both pipes have caught up to their marker,
|
|
521
537
|
// and are delivered strictly in order.
|
|
522
538
|
#deliver(msg, events) {
|
|
@@ -665,12 +681,12 @@ export class Target {
|
|
|
665
681
|
* even a plain return value in a promise it holds only weakly (#55).
|
|
666
682
|
*/
|
|
667
683
|
callFunctionOn(functionDeclaration, args) {
|
|
668
|
-
return this.#shell.send("Runtime.callFunctionOn", {
|
|
684
|
+
return this.#withoutPausing(() => this.#shell.send("Runtime.callFunctionOn", {
|
|
669
685
|
functionDeclaration,
|
|
670
686
|
arguments: args,
|
|
671
687
|
executionContextId: this.#contextId,
|
|
672
688
|
returnByValue: true,
|
|
673
|
-
});
|
|
689
|
+
}));
|
|
674
690
|
}
|
|
675
691
|
/**
|
|
676
692
|
* For functions that return a promise. The target holds it until after
|
|
@@ -699,6 +715,19 @@ export class Target {
|
|
|
699
715
|
arg,
|
|
700
716
|
]).catch(interrupted("Execution"));
|
|
701
717
|
}
|
|
718
|
+
async format(value) {
|
|
719
|
+
const arg = value.objectId
|
|
720
|
+
? { objectId: value.objectId }
|
|
721
|
+
: value.unserializableValue !== undefined
|
|
722
|
+
? { unserializableValue: value.unserializableValue }
|
|
723
|
+
: { value: value.value };
|
|
724
|
+
const res = await this.#callAsyncFunctionOn(`function (v) { return globalThis.${SHIM}.formatJson(v); }`, [arg])
|
|
725
|
+
.catch(interrupted("Execution"));
|
|
726
|
+
const thrown = res.exceptionDetails;
|
|
727
|
+
if (thrown)
|
|
728
|
+
throw new Error(thrown.exception?.description ?? thrown.text ?? "the value could not be formatted");
|
|
729
|
+
return parseBundle(res.result?.value);
|
|
730
|
+
}
|
|
702
731
|
/**
|
|
703
732
|
* Hands a frontend comm message to the target's comms. Resolves to
|
|
704
733
|
* whether a comm or registered target took it, or to the error a handler
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { LineMap } from "./sourcemap.ts";
|
|
2
|
+
export declare const TRACEBACK_MIME = "application/vnd.nteract.traceback+json";
|
|
3
|
+
/** The //# sourceURL a cell's script runs under while not debugging. */
|
|
4
|
+
export declare function cellName(code: string): string;
|
|
5
|
+
/** A cell that ran: its code, and where the notebook knows it from. */
|
|
6
|
+
export interface CellRecord {
|
|
7
|
+
code: string;
|
|
8
|
+
executionCount: number | null;
|
|
9
|
+
cellId: string | null;
|
|
10
|
+
}
|
|
11
|
+
export interface SourceLine extends Record<string, string | number | boolean> {
|
|
12
|
+
lineno: number;
|
|
13
|
+
source: string;
|
|
14
|
+
}
|
|
15
|
+
export interface TracebackFrame extends Record<string, unknown> {
|
|
16
|
+
filename: string;
|
|
17
|
+
lineno: number;
|
|
18
|
+
colno?: number;
|
|
19
|
+
name: string;
|
|
20
|
+
library: boolean;
|
|
21
|
+
lines: SourceLine[];
|
|
22
|
+
execution_count?: number;
|
|
23
|
+
cell_id?: string;
|
|
24
|
+
}
|
|
25
|
+
/** A frame of CDP's exceptionDetails.stackTrace (0-based positions). */
|
|
26
|
+
export interface CallFrame {
|
|
27
|
+
url: string;
|
|
28
|
+
lineNumber: number;
|
|
29
|
+
columnNumber: number;
|
|
30
|
+
}
|
|
31
|
+
/** A frame as parsed from one line of a stack. */
|
|
32
|
+
export interface StackFrame {
|
|
33
|
+
name: string;
|
|
34
|
+
file: string;
|
|
35
|
+
line: number | null;
|
|
36
|
+
column: number | null;
|
|
37
|
+
}
|
|
38
|
+
/** One line of a stack as a frame, or null for a line that isn't one (the message). */
|
|
39
|
+
export declare function parseFrame(text: string): StackFrame | null;
|
|
40
|
+
/**
|
|
41
|
+
* Frames from packages, runtimes and the kernel itself, which a frontend
|
|
42
|
+
* can dim or fold: a hint, not a boundary.
|
|
43
|
+
*/
|
|
44
|
+
export declare function isLibraryFile(file: string, kernelFiles?: readonly string[]): boolean;
|
|
45
|
+
export interface TracebackSources {
|
|
46
|
+
/** The cell a script name belongs to, if it is one. */
|
|
47
|
+
cell(file: string): (CellRecord & {
|
|
48
|
+
lines: LineMap | null;
|
|
49
|
+
}) | undefined;
|
|
50
|
+
/** Another file's source, when it can be read. */
|
|
51
|
+
readFile?(file: string): string | undefined;
|
|
52
|
+
/** Path or URL prefixes of the kernel's own runtime files. */
|
|
53
|
+
kernelFiles?: readonly string[];
|
|
54
|
+
}
|
|
55
|
+
export interface Traceback {
|
|
56
|
+
/** The classic traceback lines, with cell frames pointing at the cell. */
|
|
57
|
+
lines: string[];
|
|
58
|
+
/** The structured payload. */
|
|
59
|
+
payload: Record<string, unknown>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* `stack` is the error's stack as the target describes it (src/target.ts's
|
|
63
|
+
* describeError), message lines included. `callFrames`, from CDP, name the
|
|
64
|
+
* scripts of frames the stack shows as "<anonymous>": Deno formats stacks
|
|
65
|
+
* itself and doesn't use a script's //# sourceURL.
|
|
66
|
+
*/
|
|
67
|
+
export declare function buildTraceback(error: {
|
|
68
|
+
ename: string;
|
|
69
|
+
evalue: string;
|
|
70
|
+
stack: string;
|
|
71
|
+
callFrames?: readonly CallFrame[];
|
|
72
|
+
}, sources: TracebackSources, execution: {
|
|
73
|
+
executionCount: number | null;
|
|
74
|
+
cellId: string | null;
|
|
75
|
+
}): Traceback;
|