@runtimed/node 0.5.6 → 0.6.0-nightly.36693858508

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/src/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Observable } from "rxjs";
2
2
 
3
- export { RelaySession, connectRelay, createRelay, openRelayPath } from "./relay";
3
+ export { RelaySession, connectRelay, createRelay, openRelayPath, queryDaemonInfo } from "./relay";
4
4
  export type {
5
5
  CommentsNotebookRef,
6
6
  CreateRelayOptions,
@@ -11,16 +11,14 @@ export type {
11
11
  RelayInfo,
12
12
  } from "./relay";
13
13
 
14
- export type NotebookDocPhase = "pending" | "syncing" | "interactive";
15
- export type RuntimeStatePhase = "pending" | "syncing" | "ready";
14
+ export type ConnectionState = "Connected" | "Disconnected";
15
+ export type NotebookDocPhase = "Pending" | "Syncing" | "Interactive";
16
+ export type RuntimeStatePhase = "Pending" | "Syncing" | "Ready";
16
17
 
17
- export type InitialLoadPhase =
18
- | { phase: "not_needed" }
19
- | { phase: "streaming" }
20
- | { phase: "ready" }
21
- | { phase: "failed"; reason: string };
18
+ export type InitialLoadPhase = "NotNeeded" | "Streaming" | "Ready" | { Failed: { reason: string } };
22
19
 
23
20
  export interface SessionStatus {
21
+ connection: ConnectionState;
24
22
  notebook_doc: NotebookDocPhase;
25
23
  runtime_state: RuntimeStatePhase;
26
24
  initial_load: InitialLoadPhase;
@@ -32,45 +30,57 @@ export interface ExecutionTransition {
32
30
  execution_count: number | null;
33
31
  }
34
32
 
35
- export interface ExecutionViewSnapshot {
36
- execution_count: number | null;
37
- status: "queued" | "running" | "done" | "error" | (string & {});
38
- success: boolean | null;
39
- output_ids: string[];
40
- submitted_by_actor_label?: string | null;
41
- }
33
+ import type {
34
+ ExecutionViewChangeset,
35
+ ExecutionView,
36
+ NotebookExecutionStore,
37
+ } from "./execution-store.cjs";
38
+ export type {
39
+ ExecutionViewSnapshot,
40
+ ExecutionQueueProjection,
41
+ ExecutionViewChangeset,
42
+ ExecutionSnapshot,
43
+ ExecutionQueueSnapshot,
44
+ ExecutionView,
45
+ NotebookExecutionStore,
46
+ } from "./execution-store.cjs";
42
47
 
43
- export interface ExecutionQueueProjection {
44
- executing_execution_id?: string | null;
45
- queued_execution_ids: string[];
46
- notebook?: {
47
- executing_cell_id?: string | null;
48
- queued_cell_ids: string[];
49
- } | null;
50
- }
48
+ export type RuntimeState = Record<string, unknown>;
51
49
 
52
- export interface ExecutionViewChangeset {
53
- cell_pointer_changes?: Array<[cell_id: string, execution_id: string | null]>;
54
- execution_upserts?: Array<[execution_id: string, snapshot: ExecutionViewSnapshot]>;
55
- removed_execution_ids?: string[];
56
- queue?: ExecutionQueueProjection;
50
+ export type RuntimeKind = "python" | "deno" | (string & {});
51
+
52
+ export interface OpenTelemetryRegistrationOptions {
53
+ /** Explicit daemon endpoint. This API never starts a daemon. */
54
+ socketPath: string;
55
+ /** Stable product slug, not a user, window, session, or installation identifier. */
56
+ hostId: string;
57
+ source: "app" | "mcp";
58
+ /** Host permission only; daemon consent and emission gates still apply. Defaults to false. */
59
+ allowed?: boolean;
57
60
  }
58
61
 
59
- export interface ExecutionView {
62
+ /** One host-lifetime owner. Aggregate active windows before granting permission. */
63
+ export class TelemetryRegistration {
64
+ private constructor();
65
+ /** Await the daemon acknowledgment. Disconnected handles reject, never reconnect. */
66
+ updatePermission(allowed: boolean): Promise<void>;
60
67
  /**
61
- * Current non-null NotebookDoc cell -> execution_id pointers.
62
- *
63
- * Cleared or deleted cells are omitted. Subscribe to `executionViewChanges$`
64
- * when null pointer transitions matter.
68
+ * Await revocation acknowledgment. Idempotent after success; disconnection rejects.
69
+ * Without acknowledgment, remote revocation can take up to the 120-second lease expiry.
65
70
  */
66
- cell_execution_ids: Record<string, string>;
67
- executions: Record<string, ExecutionViewSnapshot>;
68
- queue: ExecutionQueueProjection | null;
71
+ close(): Promise<void>;
69
72
  }
70
73
 
71
- export type RuntimeState = Record<string, unknown>;
72
-
73
- export type RuntimeKind = "python" | "deno" | (string & {});
74
+ /**
75
+ * Return null if host telemetry is unsupported or the capability probe is unavailable.
76
+ * Permission defaults to denied.
77
+ * Keep the handle alive while active and await close() when finished. Garbage collection
78
+ * terminates its socket without awaiting revocation. The handle never reconnects.
79
+ * Older native binaries omit this export; feature-detect it when supporting those binaries.
80
+ */
81
+ export function openTelemetryRegistration(
82
+ options: OpenTelemetryRegistrationOptions,
83
+ ): Promise<TelemetryRegistration | null>;
74
84
 
75
85
  export const PackageManager: {
76
86
  readonly Uv: "uv";
@@ -247,6 +257,14 @@ export class Session {
247
257
  runCell(source: string, options?: RunCellOptions): Promise<CellResult>;
248
258
  saveNotebook(path?: string): Promise<void>;
249
259
  exportSnapshotPair(): Promise<SnapshotPair>;
260
+ /**
261
+ * Return the current NotebookDoc heads after the connected daemon accepts them.
262
+ * Later edits are not covered. Rejects on timeout, close, disconnect, rejection,
263
+ * and unsupported peers (including hosted bridges). Persistent local rooms
264
+ * preserve recovery-journal-before-acceptance; ephemeral rooms promise acceptance
265
+ * only. Does not export an .ipynb or acknowledge runtime, comments, or widgets.
266
+ */
267
+ confirmNotebookSync(): Promise<string[]>;
250
268
  listCells(): Promise<CellSnapshot[]>;
251
269
  getCell(cellId: string): Promise<CellSnapshot | null>;
252
270
  createCell(source: string, options?: CreateCellOptions): Promise<string>;
@@ -265,7 +283,9 @@ export class Session {
265
283
  removeDependencies(packages: string[], options?: DependencyEditOptions): Promise<number>;
266
284
  getDependencyStatus(): Promise<DependencyStatus>;
267
285
  getRuntimeStatus(): Promise<RuntimeStatus>;
286
+ /** Stable immutable state; explicitly copy it if mutable ownership is needed. */
268
287
  getExecutionView(): ExecutionView;
288
+ readonly executions: NotebookExecutionStore;
269
289
  dependencyFingerprint(): Promise<string | null>;
270
290
  approveTrust(observedHeads?: string[]): Promise<void>;
271
291
  syncEnvironment(): Promise<void>;
@@ -276,6 +296,28 @@ export const NativeSession: unknown;
276
296
 
277
297
  export function defaultSocketPath(): string;
278
298
  export function socketPathForChannel(channel: "stable" | "nightly"): string;
299
+
300
+ export interface InitializeEnvironmentYmlOptions {
301
+ /** Existing absolute directory the local host is authorized to write. */
302
+ directory: string;
303
+ /** Optional name containing only letters, numbers, '.', '_' and '-'. */
304
+ name?: string;
305
+ /** Conda match specs. Pip subsections are not supported by this initializer. */
306
+ dependencies: string[];
307
+ /** Python version constraint, e.g. "3.12" or ">=3.11,<3.13". */
308
+ python?: string;
309
+ /** At least one channel, in priority order. No channels are inferred. */
310
+ channels: string[];
311
+ }
312
+
313
+ /**
314
+ * Explicitly create environment.yml using the local host's filesystem authority.
315
+ * Returns its filesystem-canonical absolute path. Rejects existing files/symlinks.
316
+ * Checks for environment.yaml first; hosts must coordinate other writers of it.
317
+ * Does not install packages, approve trust, contact a daemon or change a kernel.
318
+ */
319
+ export function initializeEnvironmentYml(options: InitializeEnvironmentYmlOptions): Promise<string>;
320
+
279
321
  export function createNotebook(options?: CreateNotebookOptions): Promise<Session>;
280
322
  export function openNotebook(notebookId: string, options?: OpenNotebookOptions): Promise<Session>;
281
323
  export function openNotebookPath(path: string, options?: OpenNotebookOptions): Promise<Session>;
package/src/relay.d.ts CHANGED
@@ -32,6 +32,15 @@ export interface QueryDaemonOptions {
32
32
 
33
33
  export interface DaemonInfo {
34
34
  version: string;
35
+ /** Protocol support only. Missing on older native bindings; treat missing as false. */
36
+ hostTelemetry?: boolean;
37
+ /** Daemon rollout/process emission gate, not user consent or host permission. */
38
+ hostTelemetryEnabled?: boolean;
39
+ protocolVersion: number;
40
+ /** Zero means the daemon predates semantic API version reporting. */
41
+ daemonApiVersion: number;
42
+ /** Shared Rust compatibility diagnostic; absent when supported by this client. */
43
+ compatibilityError?: string;
35
44
  socketPath: string;
36
45
  isDevMode: boolean;
37
46
  blobPort?: number;
@@ -82,5 +91,9 @@ export function connectRelay(notebookId: string, options?: OpenRelayOptions): Pr
82
91
  export function defaultSocketPath(): string;
83
92
  /** Resolve a stable or nightly daemon endpoint independently of this package's build channel. */
84
93
  export function socketPathForChannel(channel: "stable" | "nightly"): string;
85
- /** Return null until the selected daemon is ready to answer pool requests. */
94
+ /**
95
+ * Return null when metadata is unavailable. A responding incompatible daemon
96
+ * returns metadata with compatibilityError. This probe does not authenticate
97
+ * a process or guarantee compatibility of a later notebook connection.
98
+ */
86
99
  export function queryDaemonInfo(options?: QueryDaemonOptions): Promise<DaemonInfo | null>;
package/src/session.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
 
3
+ const { createNotebookExecutionStore } = require("./execution-store.cjs");
3
4
  const { Subject } = require("rxjs");
4
5
  const { parseJsonEvent } = require("./napi-observables.cjs");
5
6
 
@@ -7,7 +8,7 @@ class Session {
7
8
  constructor(nativeSession) {
8
9
  this._native = nativeSession;
9
10
  this._subscriptions = [];
10
- this._executionView = emptyExecutionView();
11
+ this.executions = createNotebookExecutionStore();
11
12
  this._runtimeStateSubject = new Subject();
12
13
  this._executionTransitionsSubject = new Subject();
13
14
  this._executionViewChangesSubject = new Subject();
@@ -56,7 +57,7 @@ class Session {
56
57
  this._subscriptions.push(
57
58
  nativeSession.onExecutionViewChange((json) => {
58
59
  const changeset = parseJsonEvent(json);
59
- applyExecutionViewChangeset(this._executionView, changeset);
60
+ this.executions.applyChangeset(changeset);
60
61
  this._executionViewChangesSubject.next(changeset);
61
62
  }),
62
63
  );
@@ -202,7 +203,11 @@ class Session {
202
203
  }
203
204
 
204
205
  getExecutionView() {
205
- return cloneExecutionView(this._executionView);
206
+ return this.executions.getSnapshot();
207
+ }
208
+
209
+ confirmNotebookSync() {
210
+ return this._native.confirmNotebookSync();
206
211
  }
207
212
 
208
213
  close() {
@@ -233,71 +238,6 @@ function normalizeDependencyOptions(options) {
233
238
  return { packageManager: options.packageManager };
234
239
  }
235
240
 
236
- function emptyExecutionView() {
237
- return {
238
- cell_execution_ids: {},
239
- executions: {},
240
- queue: null,
241
- };
242
- }
243
-
244
- function applyExecutionViewChangeset(view, changeset) {
245
- for (const [cellId, executionId] of changeset?.cell_pointer_changes ?? []) {
246
- if (executionId == null) {
247
- delete view.cell_execution_ids[cellId];
248
- } else {
249
- view.cell_execution_ids[cellId] = executionId;
250
- }
251
- }
252
-
253
- for (const [executionId, snapshot] of changeset?.execution_upserts ?? []) {
254
- view.executions[executionId] = cloneExecutionSnapshot(snapshot);
255
- }
256
-
257
- for (const executionId of changeset?.removed_execution_ids ?? []) {
258
- delete view.executions[executionId];
259
- }
260
-
261
- if (Object.hasOwn(changeset ?? {}, "queue")) {
262
- view.queue = cloneQueueProjection(changeset.queue ?? null);
263
- }
264
- }
265
-
266
- function cloneExecutionView(view) {
267
- return {
268
- cell_execution_ids: { ...view.cell_execution_ids },
269
- executions: Object.fromEntries(
270
- Object.entries(view.executions).map(([executionId, snapshot]) => [
271
- executionId,
272
- cloneExecutionSnapshot(snapshot),
273
- ]),
274
- ),
275
- queue: cloneQueueProjection(view.queue),
276
- };
277
- }
278
-
279
- function cloneExecutionSnapshot(snapshot) {
280
- return {
281
- ...snapshot,
282
- output_ids: Array.from(snapshot?.output_ids ?? []),
283
- };
284
- }
285
-
286
- function cloneQueueProjection(queue) {
287
- if (queue == null) return null;
288
- return {
289
- executing_execution_id: queue.executing_execution_id ?? null,
290
- queued_execution_ids: Array.from(queue.queued_execution_ids ?? []),
291
- notebook:
292
- queue.notebook == null
293
- ? queue.notebook
294
- : {
295
- executing_cell_id: queue.notebook.executing_cell_id ?? null,
296
- queued_cell_ids: Array.from(queue.notebook.queued_cell_ids ?? []),
297
- },
298
- };
299
- }
300
-
301
241
  module.exports = {
302
242
  Session,
303
243
  };