@marimo-team/islands 0.25.3-dev292 → 0.25.3-dev294

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.
@@ -129,7 +129,7 @@ function N(e) {
129
129
  }
130
130
  //#endregion
131
131
  //#region src/components/editor/boundary/ErrorBoundary.tsx
132
- var P = (0, C.lazy)(() => import("./feedback-button-Bk2bqKVK.js").then((e) => ({ default: e.FeedbackModal }))), F = (e) => {
132
+ var P = (0, C.lazy)(() => import("./feedback-button-Ckz1cqbW.js").then((e) => ({ default: e.FeedbackModal }))), F = (e) => {
133
133
  let t = (0, S.c)(2), n;
134
134
  return t[0] === e.children ? n = t[1] : (n = /* @__PURE__ */ (0, k.jsx)(E, {
135
135
  FallbackComponent: I,
@@ -14,7 +14,7 @@ function y() {
14
14
  return e.warn("Failed to get version from mount config"), null;
15
15
  }
16
16
  }
17
- var b = y() || "0.25.3-dev292", x = o(b), S = o(!0);
17
+ var b = y() || "0.25.3-dev294", x = o(b), S = o(!0);
18
18
  o(null);
19
19
  //#endregion
20
20
  //#region src/core/wasm/state.ts
@@ -33,7 +33,7 @@ import { o as ba } from "./dist-DU9ICsWZ.js";
33
33
  import { a as xa, i as Sa, n as Ca, o as wa, r as Ta, t as Ea } from "./dialog-CaYm5imE.js";
34
34
  import { t as Da } from "./useAsyncData-Ci4AvJff.js";
35
35
  import { n as W, t as G } from "./objectWithoutPropertiesLoose-BRDcTsfB.js";
36
- import { t as Oa } from "./ErrorBoundary-ACP46Q1F.js";
36
+ import { t as Oa } from "./ErrorBoundary-DgYnMZjw.js";
37
37
  import { D as ka, n as Aa } from "./vega-loader.browser-B9Pz0EGP.js";
38
38
  import { a as ja, n as Ma, r as Na, t as Pa } from "./loader-DZvtzQoD.js";
39
39
  import { t as Fa } from "./useIframeCapabilities-BXhDDoCG.js";
@@ -2,7 +2,7 @@ import { a as e } from "./rolldown-runtime-Cb76FRpK.js";
2
2
  import { t } from "./react-sHtZdjeP.js";
3
3
  import { t as n } from "./react-dom-DUmH0GXv.js";
4
4
  import { c as r, l as i, u as a } from "./data-grid-types-0PJ-9N5n.js";
5
- import { a as o, i as s, n as c, r as l } from "./glide-data-editor-BKoG60_u.js";
5
+ import { a as o, i as s, n as c, r as l } from "./glide-data-editor-kK37-CHg.js";
6
6
  //#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/data-grid-overlay-editor-style.js
7
7
  var u = /* @__PURE__ */ e(t(), 1), d = /* @__PURE__ */ e(n(), 1), f = /*#__PURE__*/ o("div")({
8
8
  name: "DataGridOverlayEditorStyle",
@@ -4,13 +4,13 @@ import { t as r } from "./react-sHtZdjeP.js";
4
4
  import { t as i } from "./compiler-runtime-CldRdSsv.js";
5
5
  import { t as a } from "./copy-icon-CtllOdmg.js";
6
6
  import { D as o, E as s, F as c, Gt as l, L as u, i as d, j as f, n as p, q as m } from "./error-entries-CQl9aZz1.js";
7
- import { n as h, t as ee } from "./globals-BOFUA33x.js";
7
+ import { n as h, t as ee } from "./globals-BCmvSVeP.js";
8
8
  import { r as g } from "./assertNever-B-YzWzbL.js";
9
9
  import { t as _ } from "./jsx-runtime-3BD1kT0s.js";
10
10
  import { Ft as te, p as v, yt as ne } from "./use-restore-focus-CosX7-gx.js";
11
11
  import { a as re, i as ie, n as ae, r as oe } from "./dialog-CaYm5imE.js";
12
12
  import { t as se } from "./useAsyncData-Ci4AvJff.js";
13
- import { t as ce } from "./code-visibility-Taf_1R1m.js";
13
+ import { t as ce } from "./code-visibility-CIsK9tCk.js";
14
14
  //#region src/components/ui/skeleton.tsx
15
15
  var y = /* @__PURE__ */ e(r(), 1), b = i(), x = _(), S = (e) => {
16
16
  let n = (0, b.c)(8), r, i;
@@ -14,7 +14,7 @@ import { t as P } from "./jsx-runtime-3BD1kT0s.js";
14
14
  import { u as oe } from "./use-restore-focus-CosX7-gx.js";
15
15
  import { t as F } from "./useEvent-BRH-aCqi.js";
16
16
  import { n as I, t as se } from "./objectWithoutPropertiesLoose-BRDcTsfB.js";
17
- import { t as ce } from "./ErrorBoundary-ACP46Q1F.js";
17
+ import { t as ce } from "./ErrorBoundary-DgYnMZjw.js";
18
18
  import { A as le, C as ue, D as de, E as fe, F as pe, I as me, L as he, M as ge, N as _e, O as L, P as ve, R as ye, S as be, T as xe, _ as Se, a as R, b as Ce, c as z, d as we, f as B, g as V, h as Te, i as Ee, j as H, k as U, l as De, m as Oe, n as ke, o as Ae, p as je, r as W, s as Me, t as Ne, u as Pe, v as Fe, w as Ie, x as Le, y as Re, z as ze } from "./data-grid-types-0PJ-9N5n.js";
19
19
  //#region ../node_modules/.pnpm/@emotion+memoize@0.9.0/node_modules/@emotion/memoize/dist/emotion-memoize.esm.js
20
20
  function Be(e) {
@@ -7068,7 +7068,7 @@ function us(e, t, n, r, i) {
7068
7068
  }
7069
7069
  //#endregion
7070
7070
  //#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/data-editor/data-editor.js
7071
- var ds = /* @__PURE__ */ e(wr(), 1), fs = /* @__PURE__ */ e(Or(), 1), ps = G.lazy(async () => await import("./data-grid-overlay-editor-B-z-T6dq.js")), ms = 0;
7071
+ var ds = /* @__PURE__ */ e(wr(), 1), fs = /* @__PURE__ */ e(Or(), 1), ps = G.lazy(async () => await import("./data-grid-overlay-editor-Bq5PEnVL.js")), ms = 0;
7072
7072
  function hs(e) {
7073
7073
  return (0, ds.default)((0, fs.default)((0, fs.default)(e).filter((e) => e.span !== void 0).map((e) => (0, io.default)((e.span?.[0] ?? 0) + 1, (e.span?.[1] ?? 0) + 1))));
7074
7074
  }
@@ -9299,7 +9299,7 @@ function Js(e, t, n, r, i) {
9299
9299
  }
9300
9300
  //#endregion
9301
9301
  //#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/cells/number-cell.js
9302
- var Ys = G.lazy(async () => await import("./number-overlay-editor-BtdL08uF.js")), Xs = {
9302
+ var Ys = G.lazy(async () => await import("./number-overlay-editor-Dc4SupkL.js")), Xs = {
9303
9303
  getAccessibilityString: (e) => e.data?.toString() ?? "",
9304
9304
  kind: W.Number,
9305
9305
  needsHover: (e) => e.hoverEffect === !0,
@@ -1,6 +1,6 @@
1
1
  import { h as e } from "./tooltip-DMMiOn2f.js";
2
2
  import { yt as t } from "./use-restore-focus-CosX7-gx.js";
3
- import { r as n } from "./code-visibility-Taf_1R1m.js";
3
+ import { r as n } from "./code-visibility-CIsK9tCk.js";
4
4
  var r = e("triangle-alert", [
5
5
  ["path", {
6
6
  d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",
package/dist/main.js CHANGED
@@ -6,7 +6,7 @@ import { i as x, n as S, r as C, t as w } from "./copy-icon-CtllOdmg.js";
6
6
  import { B as T, Bt as E, Dt as D, E as O, F as k, Ft as A, Ht as j, I as M, It as N, L as P, Lt as F, M as I, O as L, Ot as R, P as z, Pt as B, R as ee, Rt as te, St as ne, Ut as re, X as ie, Z as ae, _ as oe, _t as se, a as ce, at as le, b as ue, bt as de, c as fe, ct as pe, dt as me, i as he, it as ge, j as _e, jt as ve, lt as ye, mt as be, n as xe, o as Se, ot as Ce, q as we, rt as Te, ut as Ee, vt as De, yt as Oe, z as ke, zt as Ae } from "./html-to-image-DbxMq9QA.js";
7
7
  import { a as je, f as Me, h as Ne, i as Pe, m as Fe, n as Ie, o as Le, r as Re, t as ze } from "./tooltip-DMMiOn2f.js";
8
8
  import { D as Be, E as Ve, O as He, S as Ue, T as We, _ as Ge, a as Ke, c as qe, d as Je, f as Ye, g as Xe, h as Ze, i as Qe, l as $e, m as et, n as tt, o as nt, p as rt, r as it, s as at, t as ot, u as st, v as ct, w as lt, x as ut, y as dt } from "./spec-BZMDxAu7.js";
9
- import { $t as ft, A as pt, At as mt, B as ht, Bt as gt, C as _t, Cn as vt, Ct as yt, D as bt, Dt as xt, E as St, En as Ct, Et as wt, F as Tt, Ft as Et, G as Dt, Gt as Ot, H as kt, Ht as At, I as jt, It as Mt, J as Nt, Jt as Pt, K as Ft, Kt as It, L as Lt, Lt as Rt, M as zt, Mt as Bt, N as Vt, Nt as Ht, O as Ut, Ot as Wt, P as Gt, Pt as Kt, Qt as qt, R as Jt, Rt as Yt, S as Xt, Sn as Zt, T as Qt, Tn as $t, Tt as en, U as tn, Ut as nn, V as rn, Vt as an, W as on, Wt as sn, X as cn, Xt as ln, Y as un, Yt as dn, Z as fn, Zt as pn, _ as mn, _t as hn, an as gn, at as _n, b as vn, bn as yn, bt as bn, c as xn, cn as Sn, ct as Cn, d as wn, dn as Tn, dt as En, en as Dn, f as On, fn as kn, ft as An, g as jn, gn as Mn, gt as Nn, h as Pn, hn as Fn, ht as In, in as Ln, it as Rn, j as zn, jt as Bn, k as Vn, kt as Hn, ln as Un, lt as Wn, m as Gn, mn as Kn, mt as qn, nn as Jn, nt as Yn, on as Xn, ot as Zn, p as Qn, pn as $n, pt as er, q as tr, qt as nr, r as rr, rn as ir, rt as ar, sn as or, st as sr, t as cr, tn as lr, tt as ur, u as dr, un as fr, ut as pr, v as mr, vn as hr, vt as gr, w as _r, wn as vr, wt as yr, x as br, xn as xr, y as Sr, yn as Cr, yt as wr, z as Tr, zt as Er } from "./common-DDryFNVp.js";
9
+ import { $t as ft, A as pt, At as mt, B as ht, Bt as gt, C as _t, Cn as vt, Ct as yt, D as bt, Dt as xt, E as St, En as Ct, Et as wt, F as Tt, Ft as Et, G as Dt, Gt as Ot, H as kt, Ht as At, I as jt, It as Mt, J as Nt, Jt as Pt, K as Ft, Kt as It, L as Lt, Lt as Rt, M as zt, Mt as Bt, N as Vt, Nt as Ht, O as Ut, Ot as Wt, P as Gt, Pt as Kt, Qt as qt, R as Jt, Rt as Yt, S as Xt, Sn as Zt, T as Qt, Tn as $t, Tt as en, U as tn, Ut as nn, V as rn, Vt as an, W as on, Wt as sn, X as cn, Xt as ln, Y as un, Yt as dn, Z as fn, Zt as pn, _ as mn, _t as hn, an as gn, at as _n, b as vn, bn as yn, bt as bn, c as xn, cn as Sn, ct as Cn, d as wn, dn as Tn, dt as En, en as Dn, f as On, fn as kn, ft as An, g as jn, gn as Mn, gt as Nn, h as Pn, hn as Fn, ht as In, in as Ln, it as Rn, j as zn, jt as Bn, k as Vn, kt as Hn, ln as Un, lt as Wn, m as Gn, mn as Kn, mt as qn, nn as Jn, nt as Yn, on as Xn, ot as Zn, p as Qn, pn as $n, pt as er, q as tr, qt as nr, r as rr, rn as ir, rt as ar, sn as or, st as sr, t as cr, tn as lr, tt as ur, u as dr, un as fr, ut as pr, v as mr, vn as hr, vt as gr, w as _r, wn as vr, wt as yr, x as br, xn as xr, y as Sr, yn as Cr, yt as wr, z as Tr, zt as Er } from "./common-BfAMDXQx.js";
10
10
  import { a as Dr, n as Or, s as kr, t as Ar } from "./useLifecycle-SniivYmC.js";
11
11
  import { t as jr } from "./check-XFzZeH-y.js";
12
12
  import { A as Mr, C as Nr, D as Pr, M as Fr, O as Ir, a as Lr, c as Rr, d as zr, i as Br, k as Vr, l as Hr, n as Ur, o as Wr, r as Gr, s as Kr, t as qr, w as Jr, x as Yr } from "./select-DsoP1qe8.js";
@@ -16,7 +16,7 @@ import { A as Ii, At as Li, B as Ri, Ct as zi, E as Bi, Et as Vi, Ft as Hi, H as
16
16
  import { a as wa, c as Ta, d as Ea, f as Da, i as Oa, l as ka, n as Aa, o as ja, r as Ma, s as Na, t as Pa } from "./process-output-BHsfwmw9.js";
17
17
  import { t as Fa } from "./pencil-DYUlSKxZ.js";
18
18
  import { a as Ia, c as La, d as Ra, f as za, i as Ba, l as Va, r as Ha } from "./glide-utils-BSQr4d90.js";
19
- import { n as Ua, t as Wa } from "./globals-BOFUA33x.js";
19
+ import { n as Ua, t as Wa } from "./globals-BCmvSVeP.js";
20
20
  import { a as Ga, i as Ka, n as qa, r as Ja, s as Ya, t as Xa } from "./assertNever-B-YzWzbL.js";
21
21
  import { t as Za } from "./react-dom-DUmH0GXv.js";
22
22
  import { t as Qa } from "./jsx-runtime-3BD1kT0s.js";
@@ -40,10 +40,10 @@ import { n as qs, t as Js } from "./esm-BDqqT86j.js";
40
40
  import { p as Ys } from "./dist-B8pkfkzc.js";
41
41
  import { t as Xs } from "./useAsyncData-Ci4AvJff.js";
42
42
  import { t as Zs } from "./semaphore-89jsoHtS.js";
43
- import { t as Qs } from "./ErrorBoundary-ACP46Q1F.js";
43
+ import { t as Qs } from "./ErrorBoundary-DgYnMZjw.js";
44
44
  import { D as $s, O as ec } from "./vega-loader.browser-B9Pz0EGP.js";
45
45
  import { a as tc, n as nc } from "./loader-DZvtzQoD.js";
46
- import { a as rc, c as ic, i as ac, l as oc, o as sc, s as cc, t as lc } from "./code-visibility-Taf_1R1m.js";
46
+ import { a as rc, c as ic, i as ac, l as oc, o as sc, s as cc, t as lc } from "./code-visibility-CIsK9tCk.js";
47
47
  import { t as uc } from "./useDeepCompareMemoize-NaaWoFlX.js";
48
48
  import { t as dc } from "./esm-BgKjMvWw.js";
49
49
  //#region ../node_modules/.pnpm/iconify-icon@2.3.0/node_modules/iconify-icon/dist/iconify-icon.mjs
@@ -12398,7 +12398,7 @@ function ED(e, t) {
12398
12398
  }
12399
12399
  //#endregion
12400
12400
  //#region src/plugins/impl/DataEditorPlugin.tsx
12401
- var DD = J.lazy(() => import("./glide-data-editor-BKoG60_u.js").then((e) => e.t)), OD = cE("marimo-data-editor", { cssStyles: [jE, ME] }).withData(K({
12401
+ var DD = J.lazy(() => import("./glide-data-editor-kK37-CHg.js").then((e) => e.t)), OD = cE("marimo-data-editor", { cssStyles: [jE, ME] }).withData(K({
12402
12402
  initialValue: K({ edits: H(K({
12403
12403
  rowIdx: U(),
12404
12404
  columnId: W(),
@@ -32188,7 +32188,7 @@ function DH(e) {
32188
32188
  }
32189
32189
  //#endregion
32190
32190
  //#region src/components/editor/renderers/slides-layout/slides-layout.tsx
32191
- var OH = J.lazy(() => import("./reveal-component-7TjyB3GR.js")), kH = (e) => {
32191
+ var OH = J.lazy(() => import("./reveal-component-CdUbWFox.js")), kH = (e) => {
32192
32192
  let t = (0, X.c)(33), { layout: n, setLayout: r, cells: i, mode: a } = e, o = lo(Fs), s = a === "read" || o, c = lo(Qi) > 1, [l, u] = (0, J.useState)(null), d;
32193
32193
  t[0] !== i || t[1] !== n ? (d = TR(i, n), t[0] = i, t[1] = n, t[2] = d) : d = t[2];
32194
32194
  let { slideCells: f, skippedIds: p, noOutputIds: m, slideTypes: h, startCellIndex: g } = d, _;
@@ -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-BKoG60_u.js";
3
+ import { a as n } from "./glide-data-editor-kK37-CHg.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 { g as t, h as n, i as r, m as i, t as a } from "./button-DZuNnIZO.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 { h as c, t as l } from "./tooltip-DMMiOn2f.js";
6
- import { $ as u, Q as d, _n as f, an as p, bn as m, et as h, gn as g, i as _, l as v, n as y, on as b, r as x, t as S, u as C } from "./common-DDryFNVp.js";
6
+ import { $ as u, Q as d, _n as f, an as p, bn as m, et as h, gn as g, i as _, l as v, n as y, on as b, r as x, t as S, u as C } from "./common-BfAMDXQx.js";
7
7
  import { M as w } from "./select-DsoP1qe8.js";
8
8
  import { Y as T } from "./dropdown-menu-Bb0bFOIk.js";
9
9
  import { Ft as E } from "./error-entries-CQl9aZz1.js";
@@ -11,7 +11,7 @@ import { t as D } from "./jsx-runtime-3BD1kT0s.js";
11
11
  import { Ft as O, Rt as k, d as A, r as ee } from "./use-restore-focus-CosX7-gx.js";
12
12
  import { t as j } from "./useEvent-BRH-aCqi.js";
13
13
  import { o as te } from "./static-state-D-Q-Ajaa.js";
14
- import { n as ne, t as re } from "./code-visibility-Taf_1R1m.js";
14
+ import { n as ne, t as re } from "./code-visibility-CIsK9tCk.js";
15
15
  /* empty css */
16
16
  var M = 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-dev292",
3
+ "version": "0.25.3-dev294",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -91,6 +91,107 @@ describe("readExport", () => {
91
91
  cells,
92
92
  });
93
93
 
94
+ describe("results", () => {
95
+ it("carries a data output as a completed execution of the snapshot's source", () => {
96
+ const result = readExport({
97
+ session: createSession([
98
+ createSessionCell(
99
+ "c1",
100
+ [{ type: "data", data: { "text/html": "<b>1</b>" } }],
101
+ [],
102
+ "hash-1",
103
+ ),
104
+ ]),
105
+ notebook: createNotebook([
106
+ createNotebookCell("c1", { code: "1", code_hash: "hash-1" }),
107
+ ]),
108
+ filename: null,
109
+ appConfig: {},
110
+ });
111
+ invariant(result.snapshot, "no snapshot");
112
+ expect(result.snapshot.results).toEqual([
113
+ expect.objectContaining({
114
+ cell_id: "c1",
115
+ code_fingerprint: "hash-1",
116
+ status: "completed",
117
+ outcome: {
118
+ kind: "value",
119
+ display: { mimetype: "text/html", data: "<b>1</b>" },
120
+ },
121
+ }),
122
+ ]);
123
+ });
124
+
125
+ it.each([
126
+ {
127
+ name: "lines without trailing newlines",
128
+ traceback: ["Traceback", "ValueError: bad"],
129
+ expectedTraceback: "Traceback\nValueError: bad",
130
+ },
131
+ {
132
+ name: "lines with trailing newlines",
133
+ traceback: ["Traceback\n", "ValueError: bad"],
134
+ expectedTraceback: "Traceback\nValueError: bad",
135
+ },
136
+ {
137
+ name: "no traceback",
138
+ traceback: [],
139
+ expectedTraceback: null,
140
+ },
141
+ ])(
142
+ "carries an exception with $name, and nothing for an empty cell",
143
+ ({ traceback, expectedTraceback }) => {
144
+ const result = readExport({
145
+ session: createSession([
146
+ createSessionCell(
147
+ "c1",
148
+ [
149
+ {
150
+ type: "error",
151
+ ename: "ValueError",
152
+ evalue: "bad",
153
+ traceback,
154
+ },
155
+ ],
156
+ [],
157
+ "hash-1",
158
+ ),
159
+ createSessionCell("c2", [], [], "hash-2"),
160
+ ]),
161
+ notebook: createNotebook([
162
+ createNotebookCell("c1", { code: "x", code_hash: "hash-1" }),
163
+ createNotebookCell("c2", { code: "", code_hash: "hash-2" }),
164
+ ]),
165
+ filename: null,
166
+ appConfig: {},
167
+ });
168
+ invariant(result.snapshot, "no snapshot");
169
+ expect(result.snapshot.results?.map((r) => r.cell_id)).toEqual(["c1"]);
170
+ expect(result.snapshot.results?.[0]?.outcome).toEqual({
171
+ kind: "error",
172
+ error: expect.objectContaining({
173
+ kind: "exception",
174
+ name: "ValueError",
175
+ message: "bad",
176
+ traceback:
177
+ expectedTraceback === null
178
+ ? null
179
+ : { mimetype: "text/plain", data: expectedTraceback },
180
+ }),
181
+ });
182
+ expect(result.cellRuntime[cellId("c1")].output?.data).toEqual([
183
+ {
184
+ type: "exception",
185
+ exception_type: "ValueError",
186
+ msg: "bad",
187
+ raising_cell: null,
188
+ traceback: expectedTraceback,
189
+ },
190
+ ]);
191
+ },
192
+ );
193
+ });
194
+
94
195
  describe("validation", () => {
95
196
  it("logs error for both session and notebook null/undefined", () => {
96
197
  const result = readExport({
@@ -184,6 +184,90 @@ function cellRecord(cellId: CellId, cell: NotebookCell): Protocol.Cell {
184
184
  };
185
185
  }
186
186
 
187
+ /** The output a cell shows, preferring data to an error. */
188
+ function primaryOutputOf(sessionCell: SessionCell | null | undefined) {
189
+ const outputs = sessionCell?.outputs ?? [];
190
+ return (
191
+ outputs.find((output) => output.type === "data") ??
192
+ outputs.find((output) => output.type === "error") ??
193
+ outputs[0]
194
+ );
195
+ }
196
+
197
+ function normalizeTraceback(lines: readonly string[]): string | null {
198
+ if (lines.length === 0) {
199
+ return null;
200
+ }
201
+ return lines
202
+ .map((line, index) =>
203
+ index < lines.length - 1 && !line.endsWith("\n") ? `${line}\n` : line,
204
+ )
205
+ .join("");
206
+ }
207
+
208
+ /**
209
+ * The cell's last result as a host would report it.
210
+ *
211
+ * A completed execution of the snapshot's own source, so it reads as
212
+ * current, with no runtime behind it.
213
+ */
214
+ function resultRecord(
215
+ cell: Protocol.Cell,
216
+ sessionCell: SessionCell | null | undefined,
217
+ ): Protocol.Execution | null {
218
+ const primary = primaryOutputOf(sessionCell);
219
+ let outcome: Protocol.Outcome;
220
+ if (primary === undefined) {
221
+ return null;
222
+ } else if (primary.type === "error") {
223
+ const traceback = normalizeTraceback(primary.traceback);
224
+ outcome = {
225
+ kind: "error",
226
+ error: {
227
+ kind: "exception",
228
+ name: primary.ename,
229
+ message: primary.evalue,
230
+ source: "marimo",
231
+ severity: "error",
232
+ range: null,
233
+ traceback:
234
+ traceback === null
235
+ ? null
236
+ : { mimetype: "text/plain", data: traceback },
237
+ related: [],
238
+ },
239
+ };
240
+ } else if (primary.type === "data") {
241
+ const [mimetype, data] = Object.entries(primary.data)[0] ?? [];
242
+ outcome = {
243
+ kind: "value",
244
+ display:
245
+ mimetype === undefined
246
+ ? null
247
+ : {
248
+ mimetype,
249
+ data: typeof data === "string" ? data : JSON.stringify(data),
250
+ },
251
+ };
252
+ } else {
253
+ return null;
254
+ }
255
+ return {
256
+ id: `${EMBEDDED}:${cell.id}:result`,
257
+ run_id: `${EMBEDDED}:run`,
258
+ runtime_id: EMBEDDED,
259
+ caused_by: null,
260
+ cell_id: cell.id,
261
+ code: null,
262
+ code_fingerprint: cell.code_fingerprint,
263
+ depends_on: {},
264
+ status: "completed",
265
+ outcome,
266
+ started_at: null,
267
+ completed_at: null,
268
+ };
269
+ }
270
+
187
271
  function createCellRuntimeFromSession(
188
272
  sessionCell: SessionCell | null | undefined,
189
273
  ): CellRuntimeState {
@@ -193,12 +277,7 @@ function createCellRuntimeFromSession(
193
277
  return runtimeState;
194
278
  }
195
279
 
196
- // Handle outputs - prioritize by type and use first available
197
- const outputs = sessionCell.outputs || [];
198
- const primaryOutput =
199
- outputs.find((output) => output.type === "data") ||
200
- outputs.find((output) => output.type === "error") ||
201
- outputs[0];
280
+ const primaryOutput = primaryOutputOf(sessionCell);
202
281
 
203
282
  if (primaryOutput) {
204
283
  if (primaryOutput.type === "error") {
@@ -210,16 +289,7 @@ function createCellRuntimeFromSession(
210
289
  exception_type: primaryOutput.ename,
211
290
  msg: primaryOutput.evalue,
212
291
  raising_cell: null,
213
- traceback:
214
- primaryOutput.traceback.length === 0
215
- ? null
216
- : primaryOutput.traceback
217
- .map((line, index, lines) =>
218
- index < lines.length - 1 && !line.endsWith("\n")
219
- ? `${line}\n`
220
- : line,
221
- )
222
- .join(""),
292
+ traceback: normalizeTraceback(primaryOutput.traceback),
223
293
  },
224
294
  ],
225
295
  mimetype: "application/vnd.marimo+error",
@@ -306,14 +376,18 @@ export function readExport({
306
376
  }
307
377
 
308
378
  const cells: Protocol.Cell[] = [];
379
+ const results: Protocol.Execution[] = [];
309
380
  const cellRuntime: Record<CellId, CellRuntimeState> = {};
310
381
  for (const cellId of cellIds) {
311
- cells.push(
312
- cellRecord(
313
- cellId,
314
- notebookCellData.get(cellId) ?? createEmptyNotebookCell(),
315
- ),
382
+ const cell = cellRecord(
383
+ cellId,
384
+ notebookCellData.get(cellId) ?? createEmptyNotebookCell(),
316
385
  );
386
+ cells.push(cell);
387
+ const result = resultRecord(cell, sessionCellData.get(cellId));
388
+ if (result !== null) {
389
+ results.push(result);
390
+ }
317
391
  cellRuntime[cellId] = createCellRuntimeFromSession(
318
392
  sessionCellData.get(cellId),
319
393
  );
@@ -339,6 +413,7 @@ export function readExport({
339
413
  version: 1,
340
414
  },
341
415
  cells,
416
+ results,
342
417
  },
343
418
  cellRuntime,
344
419
  };
@@ -3,8 +3,10 @@
3
3
  import { createNotebookReducer, NotebookEvents } from "@marimo-team/client";
4
4
  import * as Protocol from "@marimo-team/client/protocol";
5
5
  import { afterEach, assert, describe, expect, it, vi } from "vitest";
6
+ import { MockExecutions } from "@/__mocks__/executions";
6
7
  import type { NotebookBackend } from "../../notebook/replica";
7
8
  import { document as documentResource } from "../../notebook/replica/resources/document";
9
+ import { results as resultsResource } from "../../notebook/replica/resources/results";
8
10
  import {
9
11
  createStaticNotebookBackend,
10
12
  emptySnapshot,
@@ -26,6 +28,7 @@ function snapshot(): StaticNotebookSnapshot {
26
28
  cells: events.flatMap((event) =>
27
29
  event.event === "cell" ? [event.data.cell] : [],
28
30
  ),
31
+ results: [],
29
32
  };
30
33
  }
31
34
 
@@ -101,6 +104,37 @@ describe("static notebook backend", () => {
101
104
  expect(stream.status).toBe("connected");
102
105
  });
103
106
 
107
+ it("delivers embedded results as completed executions after the document", async () => {
108
+ const source = snapshot();
109
+ const cell = source.cells[0];
110
+ const result = MockExecutions.completed(cell.id, {
111
+ id: "embedded:result",
112
+ run_id: "embedded:run",
113
+ runtime_id: "embedded",
114
+ code_fingerprint: cell.code_fingerprint,
115
+ outcome: {
116
+ kind: "value",
117
+ display: { mimetype: "text/html", data: "<b>1</b>" },
118
+ },
119
+ started_at: null,
120
+ completed_at: null,
121
+ });
122
+ const { events } = await read(
123
+ createStaticNotebookBackend({ ...source, results: [result] }),
124
+ );
125
+ const reducer = createNotebookReducer({
126
+ document: documentResource,
127
+ results: resultsResource,
128
+ });
129
+ const state = events.reduce(reducer.reduce, reducer.initial);
130
+ expect(events.map((event) => event.event).slice(-3)).toEqual([
131
+ "document",
132
+ "execution",
133
+ "ready",
134
+ ]);
135
+ expect(state.resources.results.get(cell.id)).toEqual(result);
136
+ });
137
+
104
138
  it("preserves withheld source and its revision metadata", async () => {
105
139
  const source = snapshot();
106
140
  const cells = source.cells.map((cell) => ({ ...cell, code: null }));
@@ -11,6 +11,8 @@ export interface StaticNotebookSnapshot {
11
11
  readonly notebook: Omit<Protocol.Notebook, "operations">;
12
12
  readonly document: Protocol.Document;
13
13
  readonly cells: readonly Protocol.Cell[];
14
+ /** What the cells last produced, as completed executions. */
15
+ readonly results: readonly Protocol.Execution[];
14
16
  }
15
17
 
16
18
  /** The events that describe a snapshot, in the order a host sends them. */
@@ -25,6 +27,10 @@ function snapshotFrames(snapshot: StaticNotebookSnapshot): Protocol.Event[] {
25
27
  data: { cell },
26
28
  })),
27
29
  { event: "document", data: { document: snapshot.document } },
30
+ ...snapshot.results.map((execution): Protocol.ExecutionEvent => ({
31
+ event: "execution",
32
+ data: { execution },
33
+ })),
28
34
  ];
29
35
  }
30
36
 
@@ -49,6 +55,7 @@ export function emptySnapshot(notebookId: string): StaticNotebookSnapshot {
49
55
  version: 1,
50
56
  },
51
57
  cells: [],
58
+ results: [],
52
59
  };
53
60
  }
54
61