@tlockney/cdp-kernel 0.7.1 → 0.8.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/dist/browser/kernel.js +216 -43
- package/dist/browser/kernel.js.map +2 -2
- package/dist/browser/target.d.ts +5 -3
- package/dist/browser/target.js +42 -9
- package/dist/browser/worker.js +47 -4
- package/dist/browser/worker.js.map +2 -2
- package/dist/bun-target.d.ts +5 -1
- package/dist/bun-target.js +32 -7
- package/dist/crash-reports.d.ts +47 -0
- package/dist/crash-reports.js +155 -0
- package/dist/kernel-core.d.ts +7 -0
- package/dist/kernel-core.js +212 -35
- package/dist/kernel.js +10 -0
- package/dist/main.js +31 -14
- package/dist/message.d.ts +1 -1
- package/dist/message.js +1 -1
- package/dist/package.d.ts +2 -2
- package/dist/package.js +2 -2
- package/dist/target-api.d.ts +11 -0
- package/dist/target.d.ts +9 -2
- package/dist/target.js +66 -12
- package/dist/transform.js +3 -1
- package/dist/usage.d.ts +25 -0
- package/dist/usage.js +197 -0
- package/dist/workerd-target.d.ts +23 -2
- package/dist/workerd-target.js +84 -10
- package/dist/workers-project.js +2 -0
- package/package.json +1 -1
- package/runtime/bootstrap.mjs +65 -7
- package/runtime/browser-worker.mjs +6 -2
- package/runtime/display.d.mts +24 -2
- package/runtime/display.mjs +42 -1
- package/runtime/evaluator.d.mts +5 -1
- package/runtime/evaluator.mjs +12 -1
- package/runtime/workerd-worker.mjs +6 -2
package/dist/browser/kernel.js
CHANGED
|
@@ -28376,7 +28376,7 @@ var init_transform = __esm({
|
|
|
28376
28376
|
SHIM = "__cdpk";
|
|
28377
28377
|
YIELD = `await ${SHIM}.tick();
|
|
28378
28378
|
`;
|
|
28379
|
-
PRELUDE = `'use strict'; ${YIELD}`;
|
|
28379
|
+
PRELUDE = `'use strict'; ${SHIM}.startCell(); ${YIELD}`;
|
|
28380
28380
|
SETTLE = `
|
|
28381
28381
|
;let ${SHIM}_settled = await ${SHIM}.tick();`;
|
|
28382
28382
|
CellSyntaxError = class extends Error {
|
|
@@ -28388,7 +28388,7 @@ var init_transform = __esm({
|
|
|
28388
28388
|
});
|
|
28389
28389
|
|
|
28390
28390
|
// src/message.ts
|
|
28391
|
-
var PROTOCOL_VERSION = "5.
|
|
28391
|
+
var PROTOCOL_VERSION = "5.5";
|
|
28392
28392
|
function makeHeader(session, msgType) {
|
|
28393
28393
|
return {
|
|
28394
28394
|
msg_id: crypto.randomUUID(),
|
|
@@ -28758,12 +28758,43 @@ function clip(frames) {
|
|
|
28758
28758
|
|
|
28759
28759
|
// src/kernel-core.ts
|
|
28760
28760
|
var TYPESCRIPT_VERSION = "6";
|
|
28761
|
+
var launchFailures = /* @__PURE__ */ new WeakSet();
|
|
28761
28762
|
function fromBase64(text) {
|
|
28762
28763
|
return Uint8Array.from(atob(text), (c) => c.charCodeAt(0));
|
|
28763
28764
|
}
|
|
28764
28765
|
var INTERRUPT_REPLY_WAIT_MS = 1e3;
|
|
28765
28766
|
var NO_INPUT = { value: null, interrupted: false };
|
|
28767
|
+
var ShellQueue = class {
|
|
28768
|
+
items = [];
|
|
28769
|
+
#wake = null;
|
|
28770
|
+
#closed = false;
|
|
28771
|
+
push(item) {
|
|
28772
|
+
if (this.#closed) return;
|
|
28773
|
+
this.items.push(item);
|
|
28774
|
+
this.#wake?.();
|
|
28775
|
+
}
|
|
28776
|
+
/** The next message; null once closed. */
|
|
28777
|
+
async next() {
|
|
28778
|
+
for (; ; ) {
|
|
28779
|
+
if (this.#closed) return null;
|
|
28780
|
+
const item = this.items.shift();
|
|
28781
|
+
if (item !== void 0) return item;
|
|
28782
|
+
await new Promise((resolve) => this.#wake = resolve);
|
|
28783
|
+
this.#wake = null;
|
|
28784
|
+
}
|
|
28785
|
+
}
|
|
28786
|
+
/** Stops taking messages; returns those still queued. */
|
|
28787
|
+
close() {
|
|
28788
|
+
this.#closed = true;
|
|
28789
|
+
const dropped = this.items.splice(0);
|
|
28790
|
+
this.#wake?.();
|
|
28791
|
+
return dropped;
|
|
28792
|
+
}
|
|
28793
|
+
};
|
|
28766
28794
|
var MAX_CELLS = 1e3;
|
|
28795
|
+
function subshellNotFound(evalue) {
|
|
28796
|
+
return { status: "error", ename: "SubshellNotFound", evalue, traceback: [`SubshellNotFound: ${evalue}`] };
|
|
28797
|
+
}
|
|
28767
28798
|
var SHELL_REPLIES = {
|
|
28768
28799
|
kernel_info_request: "kernel_info_reply",
|
|
28769
28800
|
complete_request: "complete_reply",
|
|
@@ -28815,13 +28846,16 @@ var KernelCore = class {
|
|
|
28815
28846
|
#executionCount = 0;
|
|
28816
28847
|
#parent = {};
|
|
28817
28848
|
#allowStdin = false;
|
|
28818
|
-
|
|
28819
|
-
|
|
28820
|
-
|
|
28821
|
-
|
|
28822
|
-
|
|
28823
|
-
#abortQueued = 0;
|
|
28849
|
+
/** Cells and comm handlers running in the target. */
|
|
28850
|
+
#running = 0;
|
|
28851
|
+
/** A cell is running: its parent header and allow_stdin hold until it ends (#417). */
|
|
28852
|
+
#cellRunning = false;
|
|
28853
|
+
/** stop_on_error (#123): the message being handled was queued behind a failed cell. */
|
|
28824
28854
|
#aborting = false;
|
|
28855
|
+
/** Messages without a subshell_id, in the order they came. */
|
|
28856
|
+
#mainShell = new ShellQueue();
|
|
28857
|
+
/** Kernel subshells (JEP 91, #417): subshell_id -> its queue. */
|
|
28858
|
+
#subshells = /* @__PURE__ */ new Map();
|
|
28825
28859
|
/** The input_request waiting for its input_reply, if any. */
|
|
28826
28860
|
#input = null;
|
|
28827
28861
|
/** An interrupt is waiting on the target. */
|
|
@@ -28846,7 +28880,8 @@ var KernelCore = class {
|
|
|
28846
28880
|
this.#ensureTarget().catch((err) => this.#log(`target failed to start: ${err}`));
|
|
28847
28881
|
if (typeof this.#typeStrip === "string") await loadTypeStripper(this.#typeStrip);
|
|
28848
28882
|
await Promise.all([
|
|
28849
|
-
this.#
|
|
28883
|
+
this.#readShell(),
|
|
28884
|
+
this.#runShell(this.#mainShell),
|
|
28850
28885
|
this.#loop("control", (m, p) => this.#handleControl(m, p)),
|
|
28851
28886
|
this.#loop("stdin", (m) => this.#handleStdin(m))
|
|
28852
28887
|
]);
|
|
@@ -28870,8 +28905,9 @@ var KernelCore = class {
|
|
|
28870
28905
|
if (target?.diagnose) targetState = await target.diagnose().catch((err) => `diagnose failed: ${err}`);
|
|
28871
28906
|
this.#log(`state: ${JSON.stringify({
|
|
28872
28907
|
shell: handling && { msgType: handling.msgType, msgId: handling.msgId, ms: Date.now() - handling.since },
|
|
28873
|
-
queued: this.#channels.shellQueued(),
|
|
28874
|
-
|
|
28908
|
+
queued: this.#mainShell.items.length + this.#channels.shellQueued(),
|
|
28909
|
+
subshells: this.#subshells.size,
|
|
28910
|
+
running: this.#running,
|
|
28875
28911
|
interrupting: this.#interrupting,
|
|
28876
28912
|
awaitingInput: this.#input !== null,
|
|
28877
28913
|
target: targetState
|
|
@@ -28900,25 +28936,28 @@ var KernelCore = class {
|
|
|
28900
28936
|
const type = msg.header.msg_type;
|
|
28901
28937
|
const commId = String(msg.content.comm_id ?? "");
|
|
28902
28938
|
const target = await this.#ensureTarget();
|
|
28903
|
-
this.#
|
|
28904
|
-
|
|
28905
|
-
|
|
28939
|
+
if (!this.#cellRunning) {
|
|
28940
|
+
this.#parent = msg.header;
|
|
28941
|
+
this.#allowStdin = false;
|
|
28942
|
+
}
|
|
28943
|
+
const parent = msg.header;
|
|
28906
28944
|
let handled = false;
|
|
28945
|
+
this.#running++;
|
|
28907
28946
|
try {
|
|
28908
28947
|
const result = await target.dispatchComm(type, msg.content, msg.metadata, msg.buffers);
|
|
28909
28948
|
if ("error" in result) {
|
|
28910
28949
|
const { name, message, stack } = result.error;
|
|
28911
28950
|
this.#publish("stream", { name: "stderr", text: `Error in ${type} handler: ${stack || `${name}: ${message}`}
|
|
28912
|
-
` });
|
|
28951
|
+
` }, { parent });
|
|
28913
28952
|
} else {
|
|
28914
28953
|
handled = result.handled;
|
|
28915
28954
|
}
|
|
28916
28955
|
} catch (err) {
|
|
28917
28956
|
if (!(err instanceof Interrupted)) throw err;
|
|
28918
28957
|
this.#publish("stream", { name: "stderr", text: `${type} handler interrupted
|
|
28919
|
-
` });
|
|
28958
|
+
` }, { parent });
|
|
28920
28959
|
} finally {
|
|
28921
|
-
this.#
|
|
28960
|
+
this.#running--;
|
|
28922
28961
|
}
|
|
28923
28962
|
await target.flush().catch(() => {
|
|
28924
28963
|
});
|
|
@@ -28926,7 +28965,7 @@ var KernelCore = class {
|
|
|
28926
28965
|
if (handled) {
|
|
28927
28966
|
this.#comms.set(commId, String(msg.content.target_name ?? ""));
|
|
28928
28967
|
} else {
|
|
28929
|
-
this.#publish("comm_close", { comm_id: commId, data: {} });
|
|
28968
|
+
this.#publish("comm_close", { comm_id: commId, data: {} }, { parent });
|
|
28930
28969
|
}
|
|
28931
28970
|
} else if (type === "comm_close") {
|
|
28932
28971
|
this.#comms.delete(commId);
|
|
@@ -28942,6 +28981,7 @@ var KernelCore = class {
|
|
|
28942
28981
|
return target;
|
|
28943
28982
|
}, (err) => {
|
|
28944
28983
|
this.#targetStarting = null;
|
|
28984
|
+
if (typeof err === "object" && err !== null) launchFailures.add(err);
|
|
28945
28985
|
throw err;
|
|
28946
28986
|
});
|
|
28947
28987
|
return this.#targetStarting;
|
|
@@ -28961,10 +29001,18 @@ var KernelCore = class {
|
|
|
28961
29001
|
this.#interruptStart = null;
|
|
28962
29002
|
}
|
|
28963
29003
|
}
|
|
29004
|
+
/** Tells the host of a fault in the kernel's own code; a target that failed to launch isn't one (#422). */
|
|
29005
|
+
#fault(err, where) {
|
|
29006
|
+
if (typeof err === "object" && err !== null && launchFailures.has(err)) return;
|
|
29007
|
+
this.#host.fault?.(err, where);
|
|
29008
|
+
}
|
|
28964
29009
|
#targetEvents() {
|
|
28965
29010
|
return {
|
|
28966
29011
|
stream: (name, text) => this.#publish("stream", { name, text }),
|
|
28967
|
-
message: (msg) => void this.#onTargetMessage(msg).catch((err) =>
|
|
29012
|
+
message: (msg) => void this.#onTargetMessage(msg).catch((err) => {
|
|
29013
|
+
this.#log(`error handling target message: ${err}`);
|
|
29014
|
+
this.#fault(err, "target message");
|
|
29015
|
+
}),
|
|
28968
29016
|
exit: (code, note) => {
|
|
28969
29017
|
this.#target = null;
|
|
28970
29018
|
this.#types?.reset();
|
|
@@ -29007,7 +29055,7 @@ ${text}
|
|
|
29007
29055
|
this.#interruptStart();
|
|
29008
29056
|
return;
|
|
29009
29057
|
}
|
|
29010
|
-
if (!this.#target ||
|
|
29058
|
+
if (!this.#target || this.#running === 0) return;
|
|
29011
29059
|
this.#interrupting = true;
|
|
29012
29060
|
try {
|
|
29013
29061
|
await this.#target.interrupt();
|
|
@@ -29037,19 +29085,70 @@ ${text}
|
|
|
29037
29085
|
async #loop(channel, handle) {
|
|
29038
29086
|
while (!this.#shuttingDown) {
|
|
29039
29087
|
const received = await this.#channels.recv(channel);
|
|
29040
|
-
if (
|
|
29041
|
-
|
|
29042
|
-
|
|
29088
|
+
if (received === null) continue;
|
|
29089
|
+
try {
|
|
29090
|
+
await handle(received.msg, received.peer);
|
|
29091
|
+
} catch (err) {
|
|
29092
|
+
this.#log(`error handling message: ${err instanceof Error ? err.stack : err}`);
|
|
29093
|
+
this.#fault(err, `${channel} handler`);
|
|
29043
29094
|
}
|
|
29095
|
+
}
|
|
29096
|
+
}
|
|
29097
|
+
/**
|
|
29098
|
+
* Takes every shell message as it comes and queues it for the main shell
|
|
29099
|
+
* or its subshell, so a subshell's message isn't stuck behind a running
|
|
29100
|
+
* cell (#417).
|
|
29101
|
+
*/
|
|
29102
|
+
async #readShell() {
|
|
29103
|
+
while (!this.#shuttingDown) {
|
|
29104
|
+
const received = await this.#channels.recv("shell");
|
|
29044
29105
|
if (received === null) continue;
|
|
29045
|
-
const
|
|
29106
|
+
const subshellId = received.msg.header.subshell_id;
|
|
29107
|
+
if (typeof subshellId !== "string") {
|
|
29108
|
+
this.#mainShell.push({ ...received, abort: false });
|
|
29109
|
+
continue;
|
|
29110
|
+
}
|
|
29111
|
+
const queue = this.#subshells.get(subshellId);
|
|
29112
|
+
if (queue === void 0) {
|
|
29113
|
+
this.#refuseShell(received, `No subshell with id ${subshellId}`);
|
|
29114
|
+
} else if (received.msg.header.msg_type === "execute_request") {
|
|
29115
|
+
this.#mainShell.push({ ...received, abort: false });
|
|
29116
|
+
} else {
|
|
29117
|
+
queue.push({ ...received, abort: false });
|
|
29118
|
+
}
|
|
29119
|
+
}
|
|
29120
|
+
}
|
|
29121
|
+
/**
|
|
29122
|
+
* Answers a shell message for a subshell that doesn't exist, or was
|
|
29123
|
+
* deleted with the message queued, so the frontend doesn't wait on it.
|
|
29124
|
+
*/
|
|
29125
|
+
#refuseShell({ peer, msg }, evalue) {
|
|
29126
|
+
const type = msg.header.msg_type;
|
|
29127
|
+
this.#log(`refusing ${type}: ${evalue}`);
|
|
29128
|
+
this.#status("busy", msg.header);
|
|
29129
|
+
const replyType = type === "execute_request" ? "execute_reply" : SHELL_REPLIES[type];
|
|
29130
|
+
if (replyType !== void 0) this.#reply("shell", peer, msg, replyType, subshellNotFound(evalue));
|
|
29131
|
+
if (type === "comm_open") this.#publish("comm_close", { comm_id: String(msg.content.comm_id ?? ""), data: {} }, { parent: msg.header });
|
|
29132
|
+
this.#status("idle", msg.header);
|
|
29133
|
+
}
|
|
29134
|
+
/** Handles one queue's messages in turn. */
|
|
29135
|
+
async #runShell(queue) {
|
|
29136
|
+
const main = queue === this.#mainShell;
|
|
29137
|
+
while (!this.#shuttingDown) {
|
|
29138
|
+
const queued = await queue.next();
|
|
29139
|
+
if (queued === null) return;
|
|
29140
|
+
const { peer, msg } = queued;
|
|
29046
29141
|
try {
|
|
29047
|
-
if (
|
|
29048
|
-
|
|
29142
|
+
if (main) {
|
|
29143
|
+
this.#aborting = queued.abort;
|
|
29144
|
+
this.#handling = { msgType: msg.header.msg_type, msgId: msg.header.msg_id, since: Date.now() };
|
|
29145
|
+
}
|
|
29146
|
+
await this.#handleShell(msg, peer);
|
|
29049
29147
|
} catch (err) {
|
|
29050
29148
|
this.#log(`error handling message: ${err instanceof Error ? err.stack : err}`);
|
|
29149
|
+
this.#fault(err, "shell handler");
|
|
29051
29150
|
} finally {
|
|
29052
|
-
if (
|
|
29151
|
+
if (main) this.#handling = null;
|
|
29053
29152
|
}
|
|
29054
29153
|
}
|
|
29055
29154
|
}
|
|
@@ -29063,7 +29162,12 @@ ${text}
|
|
|
29063
29162
|
language_info: {
|
|
29064
29163
|
name: "typescript",
|
|
29065
29164
|
version: this.#host.languageVersion ?? TYPESCRIPT_VERSION,
|
|
29066
|
-
|
|
29165
|
+
// JupyterLab's LSP adapter picks the language server by a language
|
|
29166
|
+
// it derives from this MIME type, not from name: it drops the type
|
|
29167
|
+
// and an "x-" prefix, so "text/x.typescript" became "x.typescript"
|
|
29168
|
+
// and matched no server (#400). This is CodeMirror's MIME type for
|
|
29169
|
+
// TypeScript and in jupyter-lsp's typescript-language-server spec.
|
|
29170
|
+
mimetype: "application/typescript",
|
|
29067
29171
|
file_extension: ".ts",
|
|
29068
29172
|
pygments_lexer: "typescript",
|
|
29069
29173
|
codemirror_mode: "typescript",
|
|
@@ -29075,12 +29179,19 @@ ${text}
|
|
|
29075
29179
|
debugger: this.#debugger !== null,
|
|
29076
29180
|
// What current ipykernel advertises; JupyterLab itself goes by the
|
|
29077
29181
|
// kernelspec's metadata.debugger.
|
|
29078
|
-
supported_features: this.#debugger !== null ? ["debugger"] : [],
|
|
29182
|
+
supported_features: [...this.#debugger !== null ? ["debugger"] : [], "kernel subshells"],
|
|
29079
29183
|
...this.#host.capabilities ? { capabilities: this.#host.capabilities } : {}
|
|
29080
29184
|
};
|
|
29081
29185
|
}
|
|
29082
29186
|
// --- control channel ------------------------------------------------------
|
|
29083
29187
|
async #handleControl(msg, peer) {
|
|
29188
|
+
if (msg.header.msg_type === "usage_request") {
|
|
29189
|
+
void this.#handleControlRequest(msg, peer).catch((err) => this.#log(`usage_request failed: ${err}`));
|
|
29190
|
+
return;
|
|
29191
|
+
}
|
|
29192
|
+
return this.#handleControlRequest(msg, peer);
|
|
29193
|
+
}
|
|
29194
|
+
async #handleControlRequest(msg, peer) {
|
|
29084
29195
|
this.#status("busy", msg.header);
|
|
29085
29196
|
try {
|
|
29086
29197
|
await this.#controlRequest("control", msg, peer);
|
|
@@ -29101,6 +29212,37 @@ ${text}
|
|
|
29101
29212
|
]);
|
|
29102
29213
|
this.#reply(channel, peer, msg, "interrupt_reply", { status: "ok" });
|
|
29103
29214
|
break;
|
|
29215
|
+
case "create_subshell_request": {
|
|
29216
|
+
const subshellId = crypto.randomUUID();
|
|
29217
|
+
const queue = new ShellQueue();
|
|
29218
|
+
this.#subshells.set(subshellId, queue);
|
|
29219
|
+
void this.#runShell(queue);
|
|
29220
|
+
this.#reply(channel, peer, msg, "create_subshell_reply", { status: "ok", subshell_id: subshellId });
|
|
29221
|
+
break;
|
|
29222
|
+
}
|
|
29223
|
+
case "delete_subshell_request": {
|
|
29224
|
+
const subshellId = String(msg.content.subshell_id ?? "");
|
|
29225
|
+
const queue = this.#subshells.get(subshellId);
|
|
29226
|
+
if (queue === void 0) {
|
|
29227
|
+
this.#reply(channel, peer, msg, "delete_subshell_reply", subshellNotFound(`No subshell with id ${subshellId}`));
|
|
29228
|
+
break;
|
|
29229
|
+
}
|
|
29230
|
+
this.#subshells.delete(subshellId);
|
|
29231
|
+
for (const dropped of queue.close()) this.#refuseShell(dropped, `Subshell ${subshellId} was deleted`);
|
|
29232
|
+
this.#reply(channel, peer, msg, "delete_subshell_reply", { status: "ok" });
|
|
29233
|
+
break;
|
|
29234
|
+
}
|
|
29235
|
+
case "list_subshell_request":
|
|
29236
|
+
this.#reply(channel, peer, msg, "list_subshell_reply", { status: "ok", subshell_id: [...this.#subshells.keys()] });
|
|
29237
|
+
break;
|
|
29238
|
+
case "usage_request": {
|
|
29239
|
+
const usage = this.#host.usage?.(this.#target).catch((err) => {
|
|
29240
|
+
this.#log(`usage_request failed: ${err}`);
|
|
29241
|
+
return {};
|
|
29242
|
+
});
|
|
29243
|
+
this.#reply(channel, peer, msg, "usage_reply", await usage ?? {});
|
|
29244
|
+
break;
|
|
29245
|
+
}
|
|
29104
29246
|
case "debug_request": {
|
|
29105
29247
|
let reply;
|
|
29106
29248
|
if (this.#debugger === null) {
|
|
@@ -29375,7 +29517,8 @@ ${expression}
|
|
|
29375
29517
|
let error = null;
|
|
29376
29518
|
let userExpressions = {};
|
|
29377
29519
|
let structured = null;
|
|
29378
|
-
this.#
|
|
29520
|
+
this.#running++;
|
|
29521
|
+
this.#cellRunning = true;
|
|
29379
29522
|
try {
|
|
29380
29523
|
const target = await this.#targetForCell();
|
|
29381
29524
|
if (target.notice !== void 0 && this.#noticeShownFor !== target) {
|
|
@@ -29416,15 +29559,16 @@ ${expression}
|
|
|
29416
29559
|
error = { ename: "KernelError", evalue: message, traceback: [message] };
|
|
29417
29560
|
}
|
|
29418
29561
|
} finally {
|
|
29419
|
-
this.#
|
|
29562
|
+
this.#running--;
|
|
29563
|
+
this.#cellRunning = false;
|
|
29420
29564
|
}
|
|
29421
29565
|
await this.#target?.releaseResults?.();
|
|
29422
29566
|
if (error) {
|
|
29423
29567
|
if (!silent && msg.content.stop_on_error !== false) {
|
|
29424
29568
|
await new Promise((r) => setTimeout(r, 0));
|
|
29425
|
-
|
|
29569
|
+
for (const queued of this.#mainShell.items) queued.abort = true;
|
|
29426
29570
|
}
|
|
29427
|
-
this.#publish("error", error, structured ? { metadata: { [TRACEBACK_MIME]: structured } } : {});
|
|
29571
|
+
this.#publish("error", error, { parent, ...structured ? { metadata: { [TRACEBACK_MIME]: structured } } : {} });
|
|
29428
29572
|
this.#reply("shell", peer, msg, "execute_reply", { status: "error", execution_count: count, ...error });
|
|
29429
29573
|
} else {
|
|
29430
29574
|
this.#reply("shell", peer, msg, "execute_reply", {
|
|
@@ -29439,7 +29583,7 @@ ${expression}
|
|
|
29439
29583
|
};
|
|
29440
29584
|
|
|
29441
29585
|
// stub:package
|
|
29442
|
-
var VERSION = "0.
|
|
29586
|
+
var VERSION = "0.8.0";
|
|
29443
29587
|
|
|
29444
29588
|
// src/browser/channels.ts
|
|
29445
29589
|
var PEER = "page";
|
|
@@ -29558,7 +29702,10 @@ var BrowserTarget = class _BrowserTarget {
|
|
|
29558
29702
|
#hostCalls = /* @__PURE__ */ new Map();
|
|
29559
29703
|
#host;
|
|
29560
29704
|
#nextId = 0;
|
|
29561
|
-
|
|
29705
|
+
/** Counts interrupt() calls: a call that saw one start during it was interrupted (#417). */
|
|
29706
|
+
#interrupts = 0;
|
|
29707
|
+
/** Cells running: a comm handler that starts with none gets its own jupyter.signal (#421). */
|
|
29708
|
+
#cells = 0;
|
|
29562
29709
|
#stopNote;
|
|
29563
29710
|
#exited = false;
|
|
29564
29711
|
constructor(worker, events, host) {
|
|
@@ -29629,6 +29776,15 @@ var BrowserTarget = class _BrowserTarget {
|
|
|
29629
29776
|
(err) => answer({ error: describeHostError(err) })
|
|
29630
29777
|
);
|
|
29631
29778
|
}
|
|
29779
|
+
/** Aborts each host request in flight and rejects it in the Worker. */
|
|
29780
|
+
#cancelHostCalls() {
|
|
29781
|
+
const calls = [...this.#hostCalls];
|
|
29782
|
+
this.#hostCalls.clear();
|
|
29783
|
+
for (const [id, controller] of calls) {
|
|
29784
|
+
controller.abort();
|
|
29785
|
+
this.#worker.postMessage({ op: "host", id, error: { name: "AbortError", message: "interrupted" } });
|
|
29786
|
+
}
|
|
29787
|
+
}
|
|
29632
29788
|
/** Sends `host.onEvent` listeners in the Worker an event (#384). */
|
|
29633
29789
|
notifyHost(event, value) {
|
|
29634
29790
|
if (!this.#exited) this.#worker.postMessage({ op: "host", event, value });
|
|
@@ -29653,25 +29809,33 @@ var BrowserTarget = class _BrowserTarget {
|
|
|
29653
29809
|
});
|
|
29654
29810
|
}
|
|
29655
29811
|
async #interruptibly(op, params, what) {
|
|
29656
|
-
|
|
29812
|
+
const interrupts = this.#interrupts;
|
|
29657
29813
|
try {
|
|
29658
29814
|
return await this.#request(op, params, true);
|
|
29659
29815
|
} catch (err) {
|
|
29660
|
-
if (err instanceof Abandoned || this.#
|
|
29816
|
+
if (err instanceof Abandoned || this.#interrupts !== interrupts) throw new Interrupted(`${what} interrupted`);
|
|
29661
29817
|
throw err;
|
|
29662
29818
|
}
|
|
29663
29819
|
}
|
|
29664
29820
|
async evaluate(script) {
|
|
29665
|
-
|
|
29821
|
+
this.#cells++;
|
|
29822
|
+
try {
|
|
29823
|
+
return asEvaluateResult(await this.#interruptibly("eval", { code: script }, "Execution"));
|
|
29824
|
+
} finally {
|
|
29825
|
+
this.#cells--;
|
|
29826
|
+
}
|
|
29666
29827
|
}
|
|
29667
29828
|
/**
|
|
29668
29829
|
* A cell that's waiting on something leaves the Worker free: it answers a
|
|
29669
|
-
* ping, and the cell is abandoned with its state intact
|
|
29670
|
-
*
|
|
29671
|
-
*
|
|
29830
|
+
* ping, and the cell is abandoned with its state intact; host requests
|
|
29831
|
+
* in flight are cancelled on the page, and reject in the Worker with an
|
|
29832
|
+
* AbortError (#388), and jupyter.signal is aborted (#418). A busy cell
|
|
29833
|
+
* can't be reached, so the Worker is
|
|
29834
|
+
* terminated, and a new one starts on the next cell.
|
|
29672
29835
|
*/
|
|
29673
29836
|
async interrupt() {
|
|
29674
|
-
this.#
|
|
29837
|
+
this.#interrupts++;
|
|
29838
|
+
const cellRunning = this.#cells > 0;
|
|
29675
29839
|
const running = [...this.#interruptible];
|
|
29676
29840
|
const answered = await Promise.race([
|
|
29677
29841
|
this.#request("ping").then(() => true, () => false),
|
|
@@ -29683,6 +29847,9 @@ var BrowserTarget = class _BrowserTarget {
|
|
|
29683
29847
|
this.#pending.delete(id);
|
|
29684
29848
|
this.#interruptible.delete(id);
|
|
29685
29849
|
}
|
|
29850
|
+
this.#cancelHostCalls();
|
|
29851
|
+
void this.#request("abort", { cell: cellRunning }).catch(() => {
|
|
29852
|
+
});
|
|
29686
29853
|
return;
|
|
29687
29854
|
}
|
|
29688
29855
|
this.#stopNote = RESTART_NOTE;
|
|
@@ -29697,7 +29864,13 @@ var BrowserTarget = class _BrowserTarget {
|
|
|
29697
29864
|
await this.#request("broadcast", { count: executionCount, handle: result.objectId });
|
|
29698
29865
|
}
|
|
29699
29866
|
async dispatchComm(msgType, content, metadata, buffers) {
|
|
29700
|
-
const reply = await this.#interruptibly("comm", {
|
|
29867
|
+
const reply = await this.#interruptibly("comm", {
|
|
29868
|
+
msgType,
|
|
29869
|
+
content,
|
|
29870
|
+
metadata,
|
|
29871
|
+
buffers: buffers.map(toBase64),
|
|
29872
|
+
ownSignal: this.#cells === 0
|
|
29873
|
+
}, "Comm handler");
|
|
29701
29874
|
if (isRecord(reply.error)) {
|
|
29702
29875
|
const { name, message, stack } = reply.error;
|
|
29703
29876
|
return { error: { name: String(name), message: String(message), stack: String(stack) } };
|