@marimo-team/islands 0.25.3-dev219 → 0.25.3-dev222

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.
@@ -1,6 +1,6 @@
1
1
  import { a as e } from "./rolldown-runtime-Cb76FRpK.js";
2
2
  import { t } from "./react-sHtZdjeP.js";
3
- import { a as n } from "./glide-data-editor-B6g8_luK.js";
3
+ import { a as n } from "./glide-data-editor-09FJOvJw.js";
4
4
  //#region ../node_modules/.pnpm/@glideapps+glide-data-grid@6.0.4-alpha24_lodash@4.17.21_marked@15.0.12_react-dom@19.3.0_27cffe7f1bc30287d59ac27db3240c5b/node_modules/@glideapps/glide-data-grid/dist/esm/internal/data-grid-overlay-editor/private/number-overlay-editor-style.js
5
5
  var r = /* @__PURE__ */ e(t()), i = /*#__PURE__*/ n("div")({
6
6
  name: "NumberOverlayEditorStyle",
@@ -3,7 +3,7 @@ import { c as t, g as n, h as r, m as i, t as a } from "./button-B6RjDKJx.js";
3
3
  import { t as o } from "./react-sHtZdjeP.js";
4
4
  import { t as s } from "./compiler-runtime-CldRdSsv.js";
5
5
  import { m as c, t as l } from "./tooltip-C3UnvsRe.js";
6
- import { $ as u, Q as d, Z as f, an as p, i as m, l as h, ln as g, n as _, on as v, r as y, t as b, u as x } from "./common-kJmPJm8v.js";
6
+ import { $ as u, Q as d, Z as f, an as p, i as m, l as h, ln as g, n as _, on as v, r as y, t as b, u as x } from "./common-DHr2MXY3.js";
7
7
  import { M as S } from "./select-BSxlITBo.js";
8
8
  import { Y as ee } from "./dropdown-menu-CSNdPSnS.js";
9
9
  import { Pt as C } from "./error-entries-CRPfxMqm.js";
@@ -11,7 +11,7 @@ import { t as w } from "./jsx-runtime-3BD1kT0s.js";
11
11
  import { r as T } from "./use-restore-focus-BWO0z1lo.js";
12
12
  import { D as E, t as D, x as O } from "./utils-DXkj82sK.js";
13
13
  import { o as k } from "./static-state-BldGd99T.js";
14
- import { a as A, n as te, t as ne } from "./code-visibility-DYMqimfY.js";
14
+ import { a as A, n as te, t as ne } from "./code-visibility-Dp-DkL1e.js";
15
15
  /* empty css */
16
16
  var j = c("sticky-note", [["path", {
17
17
  d: "M21 9a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 15 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2z",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.25.3-dev219",
3
+ "version": "0.25.3-dev222",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -434,7 +434,7 @@ describe("readExport", () => {
434
434
  expand_output: false,
435
435
  },
436
436
  etag: `embedded:${CELL_1}`,
437
- code_hash: `embedded:${CELL_1}:code`,
437
+ code_fingerprint: `embedded:${CELL_1}:code`,
438
438
  version: 1,
439
439
  });
440
440
  });
@@ -501,7 +501,7 @@ describe("readExport", () => {
501
501
  expand_output: false,
502
502
  },
503
503
  etag: `embedded:${CELL_1}`,
504
- code_hash: `embedded:${CELL_1}:code`,
504
+ code_fingerprint: `embedded:${CELL_1}:code`,
505
505
  version: 1,
506
506
  });
507
507
  });
@@ -540,7 +540,7 @@ describe("readExport", () => {
540
540
  expand_output: false,
541
541
  },
542
542
  etag: `embedded:${SETUP_CELL_ID}`,
543
- code_hash: `embedded:${SETUP_CELL_ID}:code`,
543
+ code_fingerprint: `embedded:${SETUP_CELL_ID}:code`,
544
544
  version: 1,
545
545
  });
546
546
  });
@@ -588,7 +588,7 @@ describe("readExport", () => {
588
588
  expand_output: false,
589
589
  },
590
590
  etag: `embedded:${CELL_1}`,
591
- code_hash: `embedded:${CELL_1}:code`,
591
+ code_fingerprint: `embedded:${CELL_1}:code`,
592
592
  version: 1,
593
593
  });
594
594
  // Null result means no output.
@@ -179,7 +179,7 @@ function cellRecord(cellId: CellId, cell: NotebookCell): Protocol.Cell {
179
179
  expand_output: cell.config?.expand_output ?? false,
180
180
  },
181
181
  etag: `${EMBEDDED}:${cellId}`,
182
- code_hash: cell.code_hash ?? `${EMBEDDED}:${cellId}:code`,
182
+ code_fingerprint: cell.code_hash ?? `${EMBEDDED}:${cellId}:code`,
183
183
  version: 1,
184
184
  };
185
185
  }
@@ -40,7 +40,7 @@ function document(codes: ReadonlyArray<string | null>): Document {
40
40
  expand_output: false,
41
41
  },
42
42
  etag: `etag-${index}`,
43
- code_hash: `hash-${index}`,
43
+ code_fingerprint: `hash-${index}`,
44
44
  version: 1,
45
45
  }));
46
46
  return {
@@ -22,7 +22,7 @@ export function cell(
22
22
  name: "_",
23
23
  config: CONFIG,
24
24
  etag: `${id}-etag`,
25
- code_hash: `${id}-hash`,
25
+ code_fingerprint: `${id}-hash`,
26
26
  version: 1,
27
27
  ...overrides,
28
28
  };
@@ -28,17 +28,17 @@ function record(
28
28
  const cell = Protocol.CellInput.parse(input);
29
29
  const config = Protocol.CellConfigInput.parse(cell.config ?? {});
30
30
  const code = cell.code.replace(/\r\n?/g, "\n");
31
- const codeHash = hash(code);
31
+ const codeFingerprint = hash(code);
32
32
  return {
33
33
  id: cell.id,
34
34
  notebook_id: notebookId,
35
35
  name: cell.name,
36
36
  code,
37
37
  config,
38
- code_hash: codeHash,
38
+ code_fingerprint: codeFingerprint,
39
39
  etag: hash(
40
40
  [
41
- codeHash,
41
+ codeFingerprint,
42
42
  cell.name,
43
43
  ...[
44
44
  config.column,
@@ -203,7 +203,7 @@ export function createTestHost(initial: Document) {
203
203
  ? null
204
204
  : {
205
205
  etag: cell.etag,
206
- code_hash: cell.code_hash,
206
+ code_fingerprint: cell.code_fingerprint,
207
207
  version: cell.version,
208
208
  };
209
209
  }
@@ -223,12 +223,14 @@ describe("NotebookReplica lifetime", () => {
223
223
  const snapshot = fixtureMessages("notebook-events.sse");
224
224
  snapshot.slice(0, -3).forEach(attempt.receive);
225
225
  expect(store.get(client.documentAtom)).toBeNull();
226
+ expect(store.get(client.runtimeAtom)).toBeNull();
226
227
  snapshot.slice(-3).forEach(attempt.receive);
227
228
  expect(store.get(client.documentAtom)?.revision.order).toEqual([
228
229
  "c1",
229
230
  "c3",
230
231
  "k7f2",
231
232
  ]);
233
+ expect(store.get(client.runtimeAtom)?.id).toBe("r1");
232
234
  attempt.drop();
233
235
  await backoff();
234
236
  expect(store.get(client.documentAtom)?.revision.order).toEqual([
@@ -236,6 +238,7 @@ describe("NotebookReplica lifetime", () => {
236
238
  "c3",
237
239
  "k7f2",
238
240
  ]);
241
+ expect(store.get(client.runtimeAtom)).toBeNull();
239
242
  current.abort();
240
243
  expect(store.get(client.documentAtom)).toBeNull();
241
244
  });
@@ -0,0 +1,78 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { describe, expect, it } from "vitest";
4
+ import { runtime } from "../resources/runtime";
5
+ import { createNotebookReducer } from "@marimo-team/client";
6
+ import { fixtureEvents } from "./fixtures";
7
+
8
+ const reducer = createNotebookReducer({ runtime });
9
+ const snapshot = fixtureEvents("notebook-events.sse");
10
+ const confirmed = () => snapshot.reduce(reducer.reduce, reducer.initial);
11
+ const current = (state: ReturnType<typeof confirmed>) =>
12
+ state.resources.runtime;
13
+ const time = "2026-10-01T09:30:00Z";
14
+
15
+ describe("runtime resource", () => {
16
+ it("keeps the latest record and clears when that runtime is removed", () => {
17
+ const state = confirmed();
18
+ const running = current(state);
19
+ expect(running?.id).toBe("r1");
20
+ expect(running?.status).toBe("running");
21
+
22
+ const terminating = reducer.reduce(state, {
23
+ event: "runtime",
24
+ id: "98",
25
+ data: { runtime: { ...running!, status: "terminating" } },
26
+ });
27
+ expect(current(terminating)?.status).toBe("terminating");
28
+ expect(current(state)?.status).toBe("running");
29
+
30
+ const other = reducer.reduce(terminating, {
31
+ event: "runtime.removed",
32
+ id: "99",
33
+ data: { id: "r0", time },
34
+ });
35
+ expect(current(other)).toBe(current(terminating));
36
+
37
+ const removed = reducer.reduce(other, {
38
+ event: "runtime.removed",
39
+ id: "100",
40
+ data: { id: "r1", time },
41
+ });
42
+ expect(current(removed)).toBeNull();
43
+ const repeated = reducer.reduce(removed, {
44
+ event: "runtime.removed",
45
+ id: "101",
46
+ data: { id: "r1", time },
47
+ });
48
+ expect(repeated.resources).toBe(removed.resources);
49
+ });
50
+
51
+ it("follows a restart to the replacement runtime", () => {
52
+ const state = confirmed();
53
+ const removed = reducer.reduce(state, {
54
+ event: "runtime.removed",
55
+ id: "98",
56
+ data: { id: "r1", time },
57
+ });
58
+ const replacement = {
59
+ ...current(state)!,
60
+ id: "r2",
61
+ status: "starting" as const,
62
+ message: "Starting the kernel",
63
+ marimo_version: null,
64
+ started_at: "2026-10-01T09:31:00Z",
65
+ };
66
+ const starting = reducer.reduce(removed, {
67
+ event: "runtime",
68
+ id: "99",
69
+ data: { runtime: replacement },
70
+ });
71
+ expect(current(starting)).toEqual(replacement);
72
+ });
73
+
74
+ it("clears on reset", () => {
75
+ const reset = reducer.reduce(confirmed(), { event: "reset", data: {} });
76
+ expect(current(reset)).toBeNull();
77
+ });
78
+ });
@@ -9,7 +9,11 @@ import {
9
9
  NotebookEvents,
10
10
  StreamStopped,
11
11
  } from "@marimo-team/client";
12
- import type { Attachment, NotebookOutput } from "@marimo-team/client/protocol";
12
+ import type {
13
+ Attachment,
14
+ NotebookOutput,
15
+ Runtime,
16
+ } from "@marimo-team/client/protocol";
13
17
  import { type Atom, atom, type createStore } from "jotai/vanilla";
14
18
  import { z } from "zod";
15
19
  import type { NotebookBackend } from "./backend";
@@ -20,9 +24,17 @@ import {
20
24
  } from "./connection";
21
25
  import { attachments } from "./resources/attachments";
22
26
  import { type Document, document } from "./resources/document";
27
+ import { runtime } from "./resources/runtime";
23
28
 
24
29
  /** The kinds the editor reads, with marimo's own notifications. */
25
- const TYPES = ["notebook", "cell", "document", "attachment", "marimo"] as const;
30
+ const TYPES = [
31
+ "notebook",
32
+ "cell",
33
+ "document",
34
+ "attachment",
35
+ "runtime",
36
+ "marimo",
37
+ ] as const;
26
38
 
27
39
  type EditorEvent = NotebookEvent<(typeof TYPES)[number]>;
28
40
 
@@ -52,6 +64,8 @@ export interface NotebookReplica {
52
64
  readonly backendAtom: Atom<NotebookBackend | null>;
53
65
  /** Live attachments, empty until the stream is ready or while disconnected. */
54
66
  readonly attachmentsAtom: Atom<readonly Attachment[]>;
67
+ /** The notebook's runtime, null while it has none or the stream is not ready. */
68
+ readonly runtimeAtom: Atom<Runtime | null>;
55
69
  /**
56
70
  * Follow a backend, replacing any current connection.
57
71
  *
@@ -110,7 +124,7 @@ export function createNotebookReplica(
110
124
  state: ConnectionState.NOT_STARTED,
111
125
  });
112
126
  // One atom holds the whole stream, which resource atoms derive from.
113
- const reducer = createNotebookReducer({ document, attachments });
127
+ const reducer = createNotebookReducer({ document, attachments, runtime });
114
128
  const streamAtom = atom(reducer.initial);
115
129
  // A resumed stream is live, but presence waits for this connection's ready.
116
130
  const readyAtom = atom(false);
@@ -129,6 +143,9 @@ export function createNotebookReplica(
129
143
  ? get(streamAtom).resources.attachments
130
144
  : attachments.initial,
131
145
  );
146
+ const runtimeAtom = atom((get) =>
147
+ get(presentAtom) ? get(streamAtom).resources.runtime : null,
148
+ );
132
149
  const backendAtom = atom<NotebookBackend | null>(null);
133
150
  /** The connection this replica follows. Connecting again ends it. */
134
151
  let current: { end(): void; reconnect(): Promise<void> } | undefined;
@@ -150,6 +167,7 @@ export function createNotebookReplica(
150
167
  documentAtom,
151
168
  backendAtom,
152
169
  attachmentsAtom,
170
+ runtimeAtom,
153
171
  connect,
154
172
  reconnect: async () => current?.reconnect(),
155
173
  };
@@ -0,0 +1,14 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import type { Runtime } from "@marimo-team/client/protocol";
4
+ import type { NotebookResource } from "@marimo-team/client";
5
+
6
+ /** The notebook's runtime record while it has one. */
7
+ export const runtime: NotebookResource<Runtime | null, "runtime"> = {
8
+ initial: null,
9
+ on: {
10
+ runtime: (_state, { data }) => data.runtime,
11
+ "runtime.removed": (state, { data }) =>
12
+ state !== null && state.id === data.id ? null : state,
13
+ },
14
+ };