@runtimed/node 0.5.6 → 0.6.0-nightly.36654139751
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 +200 -5
- package/package.json +26 -11
- package/src/binding.cjs +55 -52
- package/src/binding.d.ts +73 -2
- package/src/execution-store.cjs +397 -0
- package/src/execution-store.d.cts +66 -0
- package/src/index.d.ts +81 -39
- package/src/relay.d.ts +14 -1
- package/src/session.cjs +8 -68
package/src/binding.d.ts
CHANGED
|
@@ -40,8 +40,10 @@ export declare class Session {
|
|
|
40
40
|
*
|
|
41
41
|
* Callback receives the same JSON shape as `CellResult`, emitted whenever
|
|
42
42
|
* the RuntimeStateDoc entry for the execution changes. The subscription
|
|
43
|
-
* ends after
|
|
44
|
-
*
|
|
43
|
+
* ends after a terminal execution snapshot, kernel failure after the
|
|
44
|
+
* execution has been observed, or connection close. An execution that
|
|
45
|
+
* never appears stays pending until the subscription is disposed or the
|
|
46
|
+
* connection closes.
|
|
45
47
|
*/
|
|
46
48
|
onExecutionProgress(executionId: string, cellId: string | undefined | null, callback: (arg0: string) => void): EventSubscription
|
|
47
49
|
/**
|
|
@@ -68,6 +70,13 @@ export declare class Session {
|
|
|
68
70
|
* `NotebookDoc` + `RuntimeStateDoc` + `CommsDoc` snapshot triplet.
|
|
69
71
|
*/
|
|
70
72
|
exportSnapshotPair(): Promise<SnapshotPair>
|
|
73
|
+
/**
|
|
74
|
+
* Acknowledge the current NotebookDoc frontier at the connected daemon.
|
|
75
|
+
* Returns the captured heads; later edits are not covered. Rejects on
|
|
76
|
+
* timeout, close, disconnect, unsupported peers, or daemon rejection.
|
|
77
|
+
* This does not save an .ipynb or acknowledge other document streams.
|
|
78
|
+
*/
|
|
79
|
+
confirmNotebookSync(): Promise<Array<string>>
|
|
71
80
|
/** Close the session and release the underlying connection. */
|
|
72
81
|
close(): Promise<void>
|
|
73
82
|
/**
|
|
@@ -154,6 +163,18 @@ export declare class Session {
|
|
|
154
163
|
waitForExecution(executionId: string, options?: WaitExecutionOptions | undefined | null): Promise<CellResult>
|
|
155
164
|
}
|
|
156
165
|
|
|
166
|
+
/** One connection-owned permission registration. Keep it alive while the host is active. */
|
|
167
|
+
export declare class TelemetryRegistration {
|
|
168
|
+
/** Await the daemon's permission acknowledgment. Disconnected handles reject, never reconnect. */
|
|
169
|
+
updatePermission(allowed: boolean): Promise<void>
|
|
170
|
+
/**
|
|
171
|
+
* Fence queued grants synchronously, then await revocation acknowledgment.
|
|
172
|
+
* Idempotent after success; disconnection rejects.
|
|
173
|
+
* Without acknowledgment, remote revocation can take up to the 120-second lease expiry.
|
|
174
|
+
*/
|
|
175
|
+
close(): Promise<void>
|
|
176
|
+
}
|
|
177
|
+
|
|
157
178
|
/** An active notebook room reported by the daemon. */
|
|
158
179
|
export interface ActiveNotebook {
|
|
159
180
|
notebookId: string
|
|
@@ -273,6 +294,15 @@ export interface CreateRelayOptions {
|
|
|
273
294
|
/** Daemon metadata needed by a Node host before it opens a notebook relay. */
|
|
274
295
|
export interface DaemonInfo {
|
|
275
296
|
version: string
|
|
297
|
+
/** Protocol support only; does not imply permission or enabled emission. */
|
|
298
|
+
hostTelemetry?: boolean
|
|
299
|
+
/** Daemon rollout/process emission gate, not user consent or host permission. */
|
|
300
|
+
hostTelemetryEnabled?: boolean
|
|
301
|
+
protocolVersion: number
|
|
302
|
+
/** Zero means the daemon predates semantic API version reporting. */
|
|
303
|
+
daemonApiVersion: number
|
|
304
|
+
/** Shared Rust compatibility diagnostic; absent when supported by this client. */
|
|
305
|
+
compatibilityError?: string
|
|
276
306
|
socketPath: string
|
|
277
307
|
isDevMode: boolean
|
|
278
308
|
blobPort?: number
|
|
@@ -329,6 +359,29 @@ export interface GetExecutionResultOptions {
|
|
|
329
359
|
socketPath?: string
|
|
330
360
|
}
|
|
331
361
|
|
|
362
|
+
/**
|
|
363
|
+
* Create environment.yml without overwriting an existing file or symlink.
|
|
364
|
+
*
|
|
365
|
+
* This uses the local Node process's filesystem authority. It does not contact
|
|
366
|
+
* the daemon, install packages, approve trust, or launch/change a kernel.
|
|
367
|
+
* Returns the absolute path of the newly created manifest.
|
|
368
|
+
*/
|
|
369
|
+
export declare function initializeEnvironmentYml(options: InitializeEnvironmentYmlOptions): Promise<string>
|
|
370
|
+
|
|
371
|
+
/** Options for the local host's explicit manifest creation request. */
|
|
372
|
+
export interface InitializeEnvironmentYmlOptions {
|
|
373
|
+
/** An existing absolute directory the host is authorized to write. */
|
|
374
|
+
directory: string
|
|
375
|
+
/** Optional environment name: letters, numbers, '.', '_' and '-'. */
|
|
376
|
+
name?: string
|
|
377
|
+
/** Conda match specs; pip subsections are not supported by this initializer. */
|
|
378
|
+
dependencies: Array<string>
|
|
379
|
+
/** Optional Python version constraint, e.g. "3.12" or ">=3.11,<3.13". */
|
|
380
|
+
python?: string
|
|
381
|
+
/** At least one channel, in priority order. No channels are inferred. */
|
|
382
|
+
channels: Array<string>
|
|
383
|
+
}
|
|
384
|
+
|
|
332
385
|
/** A notebook cell snapshot. */
|
|
333
386
|
export interface JsCellSnapshot {
|
|
334
387
|
id: string
|
|
@@ -397,6 +450,24 @@ export interface OpenRelayOptions {
|
|
|
397
450
|
/** Open a notebook file and return its native typed-frame relay. */
|
|
398
451
|
export declare function openRelayPath(path: string, options?: OpenRelayOptions | undefined | null): Promise<NativeRelaySession>
|
|
399
452
|
|
|
453
|
+
/**
|
|
454
|
+
* Return null if host telemetry is unsupported or the capability probe is unavailable.
|
|
455
|
+
* Permission defaults to denied.
|
|
456
|
+
* The handle never reconnects; collecting an idle handle terminates its socket without awaiting revocation.
|
|
457
|
+
*/
|
|
458
|
+
export declare function openTelemetryRegistration(options: OpenTelemetryRegistrationOptions): Promise<TelemetryRegistration | null>
|
|
459
|
+
|
|
460
|
+
export interface OpenTelemetryRegistrationOptions {
|
|
461
|
+
/** Explicit daemon endpoint. Opening a registration never starts a daemon. */
|
|
462
|
+
socketPath: string
|
|
463
|
+
/** Stable product slug, not a user, window, session, or installation identifier. */
|
|
464
|
+
hostId: string
|
|
465
|
+
/** Only "app" and "mcp" are accepted. */
|
|
466
|
+
source: 'app' | 'mcp'
|
|
467
|
+
/** Host permission only; daemon consent and emission gates still apply. Defaults to false. */
|
|
468
|
+
allowed?: boolean
|
|
469
|
+
}
|
|
470
|
+
|
|
400
471
|
/**
|
|
401
472
|
* Package manager for Python notebook dependencies.
|
|
402
473
|
*
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
// Generated by scripts/build-execution-store.mjs. Do not edit.
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.createNotebookExecutionStore = createNotebookExecutionStore;
|
|
5
|
+
const EMPTY_NOTEBOOK_QUEUE = Object.freeze({
|
|
6
|
+
executing_cell_id: null,
|
|
7
|
+
queued_cell_ids: Object.freeze([]),
|
|
8
|
+
});
|
|
9
|
+
/** Independent synchronous notebook state. Construction performs no I/O. */
|
|
10
|
+
function createNotebookExecutionStore() {
|
|
11
|
+
const _executionMap = new Map();
|
|
12
|
+
const _runtimeOwnedExecutionIds = new Set();
|
|
13
|
+
/** Per-cell reverse index: cell_id -> latest execution_id. */
|
|
14
|
+
const _cellToExecution = new Map();
|
|
15
|
+
const _executionToCell = new Map();
|
|
16
|
+
let _notebookQueueProjection = EMPTY_NOTEBOOK_QUEUE;
|
|
17
|
+
let _queue = null;
|
|
18
|
+
let _snapshot;
|
|
19
|
+
const _subscribers = new Map();
|
|
20
|
+
const _cellExecutionSubscribers = new Map();
|
|
21
|
+
const _queueProjectionSubscribers = new Set();
|
|
22
|
+
let _executionStructureVersion = 0;
|
|
23
|
+
const _executionStructureVersionSubscribers = new Set();
|
|
24
|
+
function emitExecutionChange(execution_id) {
|
|
25
|
+
const subs = _subscribers.get(execution_id);
|
|
26
|
+
if (!subs)
|
|
27
|
+
return;
|
|
28
|
+
// Snapshot listeners so subscriptions added during delivery wait for the next notification.
|
|
29
|
+
// eslint-disable-next-line unicorn/no-useless-spread
|
|
30
|
+
for (const cb of [...subs]) {
|
|
31
|
+
if (!subs.has(cb))
|
|
32
|
+
continue;
|
|
33
|
+
try {
|
|
34
|
+
cb();
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// subscriber errors must not break the dispatch loop
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function emitCellExecutionPointerChange(cell_id) {
|
|
42
|
+
const subs = _cellExecutionSubscribers.get(cell_id);
|
|
43
|
+
if (!subs)
|
|
44
|
+
return;
|
|
45
|
+
// Snapshot listeners so subscriptions added during delivery wait for the next notification.
|
|
46
|
+
// eslint-disable-next-line unicorn/no-useless-spread
|
|
47
|
+
for (const cb of [...subs]) {
|
|
48
|
+
if (!subs.has(cb))
|
|
49
|
+
continue;
|
|
50
|
+
try {
|
|
51
|
+
cb();
|
|
52
|
+
}
|
|
53
|
+
catch { }
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function emitQueueProjectionChange() {
|
|
57
|
+
// Snapshot listeners so subscriptions added during delivery wait for the next notification.
|
|
58
|
+
// eslint-disable-next-line unicorn/no-useless-spread
|
|
59
|
+
for (const cb of [..._queueProjectionSubscribers]) {
|
|
60
|
+
if (!_queueProjectionSubscribers.has(cb))
|
|
61
|
+
continue;
|
|
62
|
+
try {
|
|
63
|
+
cb();
|
|
64
|
+
}
|
|
65
|
+
catch { }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function emitExecutionStructureChange() {
|
|
69
|
+
_executionStructureVersion = (_executionStructureVersion + 1) | 0;
|
|
70
|
+
// Snapshot listeners so subscriptions added during delivery wait for the next notification.
|
|
71
|
+
// eslint-disable-next-line unicorn/no-useless-spread
|
|
72
|
+
for (const cb of [..._executionStructureVersionSubscribers]) {
|
|
73
|
+
if (!_executionStructureVersionSubscribers.has(cb))
|
|
74
|
+
continue;
|
|
75
|
+
try {
|
|
76
|
+
cb();
|
|
77
|
+
}
|
|
78
|
+
catch { }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// ── Subscription helpers ────────────────────────────────────────────────
|
|
82
|
+
function subscribeExecutionById(execution_id) {
|
|
83
|
+
return (callback) => {
|
|
84
|
+
let subs = _subscribers.get(execution_id);
|
|
85
|
+
if (!subs) {
|
|
86
|
+
subs = new Set();
|
|
87
|
+
_subscribers.set(execution_id, subs);
|
|
88
|
+
}
|
|
89
|
+
const set = subs;
|
|
90
|
+
set.add(callback);
|
|
91
|
+
let active = true;
|
|
92
|
+
return () => {
|
|
93
|
+
if (!active)
|
|
94
|
+
return;
|
|
95
|
+
active = false;
|
|
96
|
+
set.delete(callback);
|
|
97
|
+
if (set.size === 0 && _subscribers.get(execution_id) === set)
|
|
98
|
+
_subscribers.delete(execution_id);
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function getExecutionSnapshotGetter(execution_id) {
|
|
103
|
+
return () => (execution_id ? _executionMap.get(execution_id) : undefined);
|
|
104
|
+
}
|
|
105
|
+
function subscribeCellExecutionPointer(cell_id) {
|
|
106
|
+
return (callback) => {
|
|
107
|
+
let subs = _cellExecutionSubscribers.get(cell_id);
|
|
108
|
+
if (!subs) {
|
|
109
|
+
subs = new Set();
|
|
110
|
+
_cellExecutionSubscribers.set(cell_id, subs);
|
|
111
|
+
}
|
|
112
|
+
const set = subs;
|
|
113
|
+
set.add(callback);
|
|
114
|
+
let active = true;
|
|
115
|
+
return () => {
|
|
116
|
+
if (!active)
|
|
117
|
+
return;
|
|
118
|
+
active = false;
|
|
119
|
+
set.delete(callback);
|
|
120
|
+
if (set.size === 0 && _cellExecutionSubscribers.get(cell_id) === set)
|
|
121
|
+
_cellExecutionSubscribers.delete(cell_id);
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function getCellExecutionIdGetter(cell_id) {
|
|
126
|
+
return () => _cellToExecution.get(cell_id) ?? null;
|
|
127
|
+
}
|
|
128
|
+
function subscribeNotebookQueueProjection(callback) {
|
|
129
|
+
_queueProjectionSubscribers.add(callback);
|
|
130
|
+
let active = true;
|
|
131
|
+
return () => {
|
|
132
|
+
if (!active)
|
|
133
|
+
return;
|
|
134
|
+
active = false;
|
|
135
|
+
_queueProjectionSubscribers.delete(callback);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function getNotebookQueueProjection() {
|
|
139
|
+
return _notebookQueueProjection;
|
|
140
|
+
}
|
|
141
|
+
function subscribeExecutionStructureVersion(callback) {
|
|
142
|
+
_executionStructureVersionSubscribers.add(callback);
|
|
143
|
+
let active = true;
|
|
144
|
+
return () => {
|
|
145
|
+
if (!active)
|
|
146
|
+
return;
|
|
147
|
+
active = false;
|
|
148
|
+
_executionStructureVersionSubscribers.delete(callback);
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function getExecutionStructureVersionSnapshot() {
|
|
152
|
+
return _executionStructureVersion;
|
|
153
|
+
}
|
|
154
|
+
// ── Write operations ────────────────────────────────────────────────────
|
|
155
|
+
/**
|
|
156
|
+
* Upsert an execution snapshot. Notifies only that execution's subscribers.
|
|
157
|
+
*
|
|
158
|
+
* Does NOT update the cell -> execution pointer. `RuntimeStateDoc` keeps
|
|
159
|
+
* historical executions per cell, so iterating it cannot reliably pick
|
|
160
|
+
* the current one. Callers set the cell pointer explicitly via
|
|
161
|
+
* `setCellExecutionPointer`, driven by the canonical `cells/{id}/execution_id`
|
|
162
|
+
* field in the notebook doc.
|
|
163
|
+
*/
|
|
164
|
+
function setExecution(execution_id, snap) {
|
|
165
|
+
const prev = _executionMap.get(execution_id);
|
|
166
|
+
const sameOutputs = prev !== undefined && stringArraysEqual(prev.output_ids, snap.output_ids);
|
|
167
|
+
if (prev &&
|
|
168
|
+
sameOutputs &&
|
|
169
|
+
prev.execution_count === snap.execution_count &&
|
|
170
|
+
prev.status === snap.status &&
|
|
171
|
+
prev.success === snap.success &&
|
|
172
|
+
(prev.submitted_by_actor_label ?? null) === (snap.submitted_by_actor_label ?? null))
|
|
173
|
+
return;
|
|
174
|
+
const owned = Object.freeze({
|
|
175
|
+
...snap,
|
|
176
|
+
output_ids: sameOutputs ? prev.output_ids : Object.freeze([...snap.output_ids]),
|
|
177
|
+
});
|
|
178
|
+
_executionMap.set(execution_id, owned);
|
|
179
|
+
_snapshot = undefined;
|
|
180
|
+
emitExecutionChange(execution_id);
|
|
181
|
+
if (!prev || prev.execution_count !== snap.execution_count || !sameOutputs)
|
|
182
|
+
emitExecutionStructureChange();
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Mark execution snapshots whose authoritative source is RuntimeStateDoc.
|
|
186
|
+
*
|
|
187
|
+
* Projection placeholders can seed the same execution id before runtime sync
|
|
188
|
+
* catches up. Runtime upserts call this even when the snapshot is unchanged so
|
|
189
|
+
* projector cleanup can release ownership without deleting the runtime record.
|
|
190
|
+
*/
|
|
191
|
+
function markExecutionsRuntimeOwned(execution_ids) {
|
|
192
|
+
for (const execution_id of execution_ids) {
|
|
193
|
+
_runtimeOwnedExecutionIds.add(execution_id);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function isExecutionRuntimeOwned(execution_id) {
|
|
197
|
+
return _runtimeOwnedExecutionIds.has(execution_id);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Explicitly set the active execution_id for a cell.
|
|
201
|
+
*
|
|
202
|
+
* Used on execution_started broadcasts and on clearOutputs (pass null).
|
|
203
|
+
*/
|
|
204
|
+
function setCellExecutionPointer(cell_id, execution_id) {
|
|
205
|
+
const prev = _cellToExecution.get(cell_id) ?? null;
|
|
206
|
+
if (prev === execution_id)
|
|
207
|
+
return;
|
|
208
|
+
if (prev !== null && _executionToCell.get(prev) === cell_id) {
|
|
209
|
+
_executionToCell.delete(prev);
|
|
210
|
+
}
|
|
211
|
+
if (execution_id === null) {
|
|
212
|
+
_cellToExecution.delete(cell_id);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
_cellToExecution.set(cell_id, execution_id);
|
|
216
|
+
_executionToCell.set(execution_id, cell_id);
|
|
217
|
+
}
|
|
218
|
+
_snapshot = undefined;
|
|
219
|
+
emitCellExecutionPointerChange(cell_id);
|
|
220
|
+
emitExecutionStructureChange();
|
|
221
|
+
}
|
|
222
|
+
function setNotebookQueueProjection(projection) {
|
|
223
|
+
const next = notebookQueuesEqual(_notebookQueueProjection, projection)
|
|
224
|
+
? _notebookQueueProjection
|
|
225
|
+
: Object.freeze({
|
|
226
|
+
executing_cell_id: projection.executing_cell_id,
|
|
227
|
+
queued_cell_ids: Object.freeze([...projection.queued_cell_ids]),
|
|
228
|
+
});
|
|
229
|
+
// A cell-only projection cannot invent execution queue membership, but it
|
|
230
|
+
// must keep an existing aggregate queue current before notifying readers.
|
|
231
|
+
if (_queue && !notebookQueuesEqual(_queue.notebook, next)) {
|
|
232
|
+
_queue = Object.freeze({ ..._queue, notebook: next });
|
|
233
|
+
_snapshot = undefined;
|
|
234
|
+
}
|
|
235
|
+
updateNotebookQueueProjection(next);
|
|
236
|
+
}
|
|
237
|
+
/** Accept an owned projection; wire updates preserve absent/null adapters. */
|
|
238
|
+
function updateNotebookQueueProjection(projection) {
|
|
239
|
+
if (notebookQueuesEqual(_notebookQueueProjection, projection))
|
|
240
|
+
return;
|
|
241
|
+
_notebookQueueProjection = projection;
|
|
242
|
+
emitQueueProjectionChange();
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Drop a batch of executions from the store.
|
|
246
|
+
*
|
|
247
|
+
* Notifies per-execution subscribers with `undefined` and clears any cell
|
|
248
|
+
* pointer that referenced one of the removed ids. Used by the projection
|
|
249
|
+
* when the daemon trims an execution out of `RuntimeStateDoc` so the
|
|
250
|
+
* store doesn't drift monotonically larger.
|
|
251
|
+
*/
|
|
252
|
+
function deleteExecutions(execution_ids) {
|
|
253
|
+
for (const eid of execution_ids) {
|
|
254
|
+
const existed = _executionMap.delete(eid);
|
|
255
|
+
_runtimeOwnedExecutionIds.delete(eid);
|
|
256
|
+
const cellId = _executionToCell.get(eid);
|
|
257
|
+
_executionToCell.delete(eid);
|
|
258
|
+
const cleared = cellId !== undefined && _cellToExecution.get(cellId) === eid;
|
|
259
|
+
if (cleared)
|
|
260
|
+
_cellToExecution.delete(cellId);
|
|
261
|
+
if (!existed && !cleared)
|
|
262
|
+
continue;
|
|
263
|
+
_snapshot = undefined;
|
|
264
|
+
if (existed)
|
|
265
|
+
emitExecutionChange(eid);
|
|
266
|
+
if (cleared)
|
|
267
|
+
emitCellExecutionPointerChange(cellId);
|
|
268
|
+
emitExecutionStructureChange();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/** Read a snapshot without subscribing. */
|
|
272
|
+
function getExecutionById(execution_id) {
|
|
273
|
+
return _executionMap.get(execution_id);
|
|
274
|
+
}
|
|
275
|
+
/** Read the cell's current execution_id without subscribing. */
|
|
276
|
+
function getCellExecutionId(cell_id) {
|
|
277
|
+
return _cellToExecution.get(cell_id) ?? null;
|
|
278
|
+
}
|
|
279
|
+
/** Read the current cell id for an execution pointer without subscribing. */
|
|
280
|
+
function getCellIdForExecutionId(execution_id) {
|
|
281
|
+
return _executionToCell.get(execution_id) ?? null;
|
|
282
|
+
}
|
|
283
|
+
/** Reset the entire store. Called on notebook switch or full reset. */
|
|
284
|
+
function resetNotebookExecutions() {
|
|
285
|
+
const eids = [..._executionMap.keys()];
|
|
286
|
+
const cells = [..._cellToExecution.keys()];
|
|
287
|
+
_executionMap.clear();
|
|
288
|
+
_runtimeOwnedExecutionIds.clear();
|
|
289
|
+
_cellToExecution.clear();
|
|
290
|
+
_executionToCell.clear();
|
|
291
|
+
_notebookQueueProjection = EMPTY_NOTEBOOK_QUEUE;
|
|
292
|
+
_queue = null;
|
|
293
|
+
_snapshot = undefined;
|
|
294
|
+
for (const eid of eids)
|
|
295
|
+
emitExecutionChange(eid);
|
|
296
|
+
for (const cid of cells)
|
|
297
|
+
emitCellExecutionPointerChange(cid);
|
|
298
|
+
emitQueueProjectionChange();
|
|
299
|
+
if (eids.length > 0 || cells.length > 0) {
|
|
300
|
+
emitExecutionStructureChange();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function stringArraysEqual(a, b) {
|
|
304
|
+
if (a.length !== b.length)
|
|
305
|
+
return false;
|
|
306
|
+
for (let i = 0; i < a.length; i++) {
|
|
307
|
+
if (a[i] !== b[i])
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
/** Lazily materialize a stable, immutable aggregate for headless consumers. */
|
|
313
|
+
function getSnapshot() {
|
|
314
|
+
return (_snapshot ??= Object.freeze({
|
|
315
|
+
cell_execution_ids: Object.freeze(Object.fromEntries(_cellToExecution)),
|
|
316
|
+
executions: Object.freeze(Object.fromEntries(_executionMap)),
|
|
317
|
+
queue: _queue,
|
|
318
|
+
}));
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Apply Rust's projection in frontend order: upserts, removals, pointers, queue.
|
|
322
|
+
* Notifications are synchronous per write, not an atomic changeset batch.
|
|
323
|
+
* Reads inside notifications are current; retained snapshots never change.
|
|
324
|
+
*/
|
|
325
|
+
function applyChangeset(changeset, options = {}) {
|
|
326
|
+
if (!changeset)
|
|
327
|
+
return;
|
|
328
|
+
for (const [id, snapshot] of changeset.execution_upserts ?? []) {
|
|
329
|
+
markExecutionsRuntimeOwned([id]);
|
|
330
|
+
setExecution(id, snapshot);
|
|
331
|
+
options.onExecutionSnapshot?.(id, getExecutionById(id));
|
|
332
|
+
}
|
|
333
|
+
deleteExecutions(changeset.removed_execution_ids ?? []);
|
|
334
|
+
for (const [cell, id] of changeset.cell_pointer_changes ?? [])
|
|
335
|
+
setCellExecutionPointer(cell, id);
|
|
336
|
+
if (Object.prototype.hasOwnProperty.call(changeset, "queue")) {
|
|
337
|
+
const queue = changeset.queue;
|
|
338
|
+
const next = queue == null
|
|
339
|
+
? null
|
|
340
|
+
: Object.freeze({
|
|
341
|
+
executing_execution_id: queue.executing_execution_id ?? null,
|
|
342
|
+
queued_execution_ids: Object.freeze([...queue.queued_execution_ids]),
|
|
343
|
+
notebook: queue.notebook == null
|
|
344
|
+
? queue.notebook
|
|
345
|
+
: Object.freeze({
|
|
346
|
+
executing_cell_id: queue.notebook.executing_cell_id ?? null,
|
|
347
|
+
queued_cell_ids: Object.freeze([...queue.notebook.queued_cell_ids]),
|
|
348
|
+
}),
|
|
349
|
+
});
|
|
350
|
+
if (!queuesEqual(_queue, next)) {
|
|
351
|
+
_queue = next;
|
|
352
|
+
_snapshot = undefined;
|
|
353
|
+
}
|
|
354
|
+
updateNotebookQueueProjection(next?.notebook ?? EMPTY_NOTEBOOK_QUEUE);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function queuesEqual(a, b) {
|
|
358
|
+
if (a === b)
|
|
359
|
+
return true;
|
|
360
|
+
if (!a || !b)
|
|
361
|
+
return false;
|
|
362
|
+
if (a.executing_execution_id !== b.executing_execution_id ||
|
|
363
|
+
!stringArraysEqual(a.queued_execution_ids, b.queued_execution_ids))
|
|
364
|
+
return false;
|
|
365
|
+
return notebookQueuesEqual(a.notebook, b.notebook);
|
|
366
|
+
}
|
|
367
|
+
function notebookQueuesEqual(a, b) {
|
|
368
|
+
if (a === b)
|
|
369
|
+
return true;
|
|
370
|
+
if (!a || !b)
|
|
371
|
+
return false;
|
|
372
|
+
return (a.executing_cell_id === b.executing_cell_id &&
|
|
373
|
+
stringArraysEqual(a.queued_cell_ids, b.queued_cell_ids));
|
|
374
|
+
}
|
|
375
|
+
return {
|
|
376
|
+
subscribeNotebookQueueProjection,
|
|
377
|
+
getNotebookQueueProjection,
|
|
378
|
+
setExecution,
|
|
379
|
+
markExecutionsRuntimeOwned,
|
|
380
|
+
isExecutionRuntimeOwned,
|
|
381
|
+
setCellExecutionPointer,
|
|
382
|
+
setNotebookQueueProjection,
|
|
383
|
+
deleteExecutions,
|
|
384
|
+
getExecutionById,
|
|
385
|
+
getCellExecutionId,
|
|
386
|
+
getCellIdForExecutionId,
|
|
387
|
+
resetNotebookExecutions,
|
|
388
|
+
subscribeExecutionById,
|
|
389
|
+
getExecutionSnapshotGetter,
|
|
390
|
+
subscribeCellExecutionPointer,
|
|
391
|
+
getCellExecutionIdGetter,
|
|
392
|
+
subscribeExecutionStructureVersion,
|
|
393
|
+
getExecutionStructureVersionSnapshot,
|
|
394
|
+
getSnapshot,
|
|
395
|
+
applyChangeset,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Generated by scripts/build-execution-store.mjs. Do not edit.
|
|
2
|
+
export interface ExecutionViewSnapshot {
|
|
3
|
+
execution_count: number | null;
|
|
4
|
+
status: "queued" | "running" | "done" | "error" | "cancelled" | (string & {});
|
|
5
|
+
success: boolean | null;
|
|
6
|
+
output_ids: string[];
|
|
7
|
+
submitted_by_actor_label?: string | null;
|
|
8
|
+
}
|
|
9
|
+
export interface ExecutionQueueProjection {
|
|
10
|
+
executing_execution_id?: string | null;
|
|
11
|
+
queued_execution_ids: string[];
|
|
12
|
+
notebook?: {
|
|
13
|
+
executing_cell_id?: string | null;
|
|
14
|
+
queued_cell_ids: string[];
|
|
15
|
+
} | null;
|
|
16
|
+
}
|
|
17
|
+
export interface ExecutionViewChangeset {
|
|
18
|
+
cell_pointer_changes?: Array<[cell_id: string, execution_id: string | null]>;
|
|
19
|
+
execution_upserts?: Array<[execution_id: string, snapshot: ExecutionViewSnapshot]>;
|
|
20
|
+
removed_execution_ids?: string[];
|
|
21
|
+
queue?: ExecutionQueueProjection | null;
|
|
22
|
+
}
|
|
23
|
+
/** Immutable consumer snapshots; wire payload types above remain mutable. */
|
|
24
|
+
export type ExecutionSnapshot = Readonly<Omit<ExecutionViewSnapshot, "output_ids">> & {
|
|
25
|
+
readonly output_ids: readonly string[];
|
|
26
|
+
};
|
|
27
|
+
export interface NotebookQueueProjectionSnapshot {
|
|
28
|
+
readonly executing_cell_id: string | null;
|
|
29
|
+
readonly queued_cell_ids: readonly string[];
|
|
30
|
+
}
|
|
31
|
+
export interface ExecutionQueueSnapshot {
|
|
32
|
+
readonly executing_execution_id: string | null;
|
|
33
|
+
readonly queued_execution_ids: readonly string[];
|
|
34
|
+
readonly notebook?: NotebookQueueProjectionSnapshot | null;
|
|
35
|
+
}
|
|
36
|
+
export interface ExecutionView {
|
|
37
|
+
readonly cell_execution_ids: Readonly<Record<string, string>>;
|
|
38
|
+
readonly executions: Readonly<Record<string, ExecutionSnapshot>>;
|
|
39
|
+
readonly queue: ExecutionQueueSnapshot | null;
|
|
40
|
+
}
|
|
41
|
+
/** Independent synchronous notebook state. Construction performs no I/O. */
|
|
42
|
+
export declare function createNotebookExecutionStore(): {
|
|
43
|
+
subscribeNotebookQueueProjection: (callback: () => void) => () => void;
|
|
44
|
+
getNotebookQueueProjection: () => NotebookQueueProjectionSnapshot;
|
|
45
|
+
setExecution: (execution_id: string, snap: ExecutionSnapshot) => void;
|
|
46
|
+
markExecutionsRuntimeOwned: (execution_ids: Iterable<string>) => void;
|
|
47
|
+
isExecutionRuntimeOwned: (execution_id: string) => boolean;
|
|
48
|
+
setCellExecutionPointer: (cell_id: string, execution_id: string | null) => void;
|
|
49
|
+
setNotebookQueueProjection: (projection: NotebookQueueProjectionSnapshot) => void;
|
|
50
|
+
deleteExecutions: (execution_ids: Iterable<string>) => void;
|
|
51
|
+
getExecutionById: (execution_id: string) => ExecutionSnapshot | undefined;
|
|
52
|
+
getCellExecutionId: (cell_id: string) => string | null;
|
|
53
|
+
getCellIdForExecutionId: (execution_id: string) => string | null;
|
|
54
|
+
resetNotebookExecutions: () => void;
|
|
55
|
+
subscribeExecutionById: (execution_id: string) => (cb: () => void) => () => void;
|
|
56
|
+
getExecutionSnapshotGetter: (execution_id: string) => () => ExecutionSnapshot | undefined;
|
|
57
|
+
subscribeCellExecutionPointer: (cell_id: string) => (cb: () => void) => () => void;
|
|
58
|
+
getCellExecutionIdGetter: (cell_id: string) => () => string | null;
|
|
59
|
+
subscribeExecutionStructureVersion: (callback: () => void) => () => void;
|
|
60
|
+
getExecutionStructureVersionSnapshot: () => number;
|
|
61
|
+
getSnapshot: () => ExecutionView;
|
|
62
|
+
applyChangeset: (changeset: ExecutionViewChangeset | null | undefined, options?: {
|
|
63
|
+
onExecutionSnapshot?: (id: string, snapshot: ExecutionSnapshot) => void;
|
|
64
|
+
}) => void;
|
|
65
|
+
};
|
|
66
|
+
export type NotebookExecutionStore = ReturnType<typeof createNotebookExecutionStore>;
|