@marimo-team/islands 0.25.3-dev136 → 0.25.3-dev138

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.
@@ -135,7 +135,7 @@ function F(e) {
135
135
  }
136
136
  //#endregion
137
137
  //#region src/components/editor/boundary/ErrorBoundary.tsx
138
- var I = (0, T.lazy)(() => import("./feedback-button-BgwhkoQn.js").then((e) => ({ default: e.FeedbackModal }))), L = (e) => {
138
+ var I = (0, T.lazy)(() => import("./feedback-button-BTDJO5Gu.js").then((e) => ({ default: e.FeedbackModal }))), L = (e) => {
139
139
  let t = (0, w.c)(2), n;
140
140
  return t[0] === e.children ? n = t[1] : (n = /* @__PURE__ */ (0, j.jsx)(O, {
141
141
  FallbackComponent: R,
@@ -18,7 +18,7 @@ function x() {
18
18
  return e.warn("Failed to get version from mount config"), null;
19
19
  }
20
20
  }
21
- var S = x() || "0.25.3-dev136", C = u(S), w = u(!0);
21
+ var S = x() || "0.25.3-dev138", C = u(S), w = u(!0);
22
22
  u(null);
23
23
  //#endregion
24
24
  //#region src/core/wasm/state.ts
@@ -12,7 +12,7 @@ import { t as ut } from "./check-SpOMoCLP.js";
12
12
  import { A as dt, C as ft, D as pt, M as mt, S as ht, _ as gt, b as _t, c as vt, d as yt, g as bt, h as xt, i as St, l as Ct, m as wt, n as Tt, p as Et, s as Dt, t as Ot, u as kt, v as At, y as jt } from "./select-CkF_GBxO.js";
13
13
  import { $ as Mt, $t as Nt, A as Pt, At as Ft, B as It, Bt as Lt, C as Rt, Ct as zt, D as Bt, Dt as Vt, E as Ht, Et as Ut, F as Wt, Ft as Gt, G as Kt, Gt as qt, H as Jt, Ht as Yt, I as Xt, It as Zt, Jt as Qt, K as $t, Kt as en, L as tn, Lt as nn, M as rn, Mt as an, N as on, Nt as sn, O as cn, Ot as ln, P as un, Pt as dn, Q as fn, Qt as pn, R as mn, Rt as hn, S as gn, St as _n, T as vn, Tt as yn, U as bn, Ut as xn, V as Sn, Vt as Cn, W as wn, Wt as Tn, X as En, Xt as Dn, Y as On, Yt as kn, Z as An, Zt as jn, _ as Mn, _n as Nn, _t as Pn, a as Fn, an as In, at as Ln, b as Rn, bn as zn, bt as Bn, ct as Vn, d as Hn, dt as Un, en as Wn, et as Gn, f as Kn, fn as qn, gn as Jn, gt as Yn, h as Xn, hn as Zn, ht as Qn, i as $n, in as er, it as tr, j as nr, jt as rr, k as ir, kt as ar, l as or, ln as sr, lt as cr, mn as lr, mt as ur, n as dr, nn as fr, nt as pr, o as mr, on as hr, ot as gr, pn as _r, pt as vr, qt as yr, rt as br, s as xr, sn as Sr, st as Cr, t as wr, tn as Tr, tt as Er, u as Dr, un as Or, ut as kr, vn as Ar, vt as jr, wt as Mr, x as Nr, xt as Pr, yn as Fr, yt as Ir, z as Lr, zt as Rr } from "./dropdown-menu-GWcGCcxE.js";
14
14
  import { a as zr, c as Br, d as Vr, i as Hr, l as Ur, n as Wr, o as Gr, r as Kr, t as qr, v as Jr, x as Yr, y as Xr } from "./toDate-DGvRHwTk.js";
15
- import { n as Zr, t as Qr } from "./ErrorBoundary-BuBLWxuk.js";
15
+ import { n as Zr, t as Qr } from "./ErrorBoundary-DN6z0yV4.js";
16
16
  import { t as $r } from "./clsx-CoeGtWvn.js";
17
17
  import { t as ei } from "./react-dom-DUmH0GXv.js";
18
18
  import { t as ti } from "./jsx-runtime-3BD1kT0s.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-CWLd9Tfd.js";
5
+ import { a as o, i as s, n as c, r as l } from "./glide-data-editor-CXzU0Muz.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",
@@ -5,12 +5,12 @@ import { t as i } from "./compiler-runtime-CldRdSsv.js";
5
5
  import { t as a } from "./copy-icon-C1trdvVt.js";
6
6
  import { H as o, K as s, Lt as c, Ot as l, fn as u, h as d, i as f, n as p, q as m, zt as h } from "./error-entries-CmFDQ9CA.js";
7
7
  import { b as g } from "./select-CkF_GBxO.js";
8
- import { n as ee, t as te } from "./globals-CvsmUhAp.js";
8
+ import { n as ee, t as te } from "./globals-D3aosgON.js";
9
9
  import { t as _ } from "./jsx-runtime-3BD1kT0s.js";
10
10
  import { C as v, _ as ne, i as y } from "./useTheme-Bq9pi_vz.js";
11
11
  import { a as re, i as ie, n as ae, r as oe } from "./dialog-DgeqyrEZ.js";
12
12
  import { t as se } from "./useAsyncData-BmVgnMP5.js";
13
- import { t as ce } from "./code-visibility-CwJEaaN5.js";
13
+ import { t as ce } from "./code-visibility-BnpyGDBY.js";
14
14
  //#region src/components/ui/skeleton.tsx
15
15
  var b = /* @__PURE__ */ e(r(), 1), x = i(), S = _(), le = (e) => {
16
16
  let n = (0, x.c)(8), r, i;
@@ -6,7 +6,7 @@ import { i as s, n as c, r as l } from "./copy-icon-C1trdvVt.js";
6
6
  import { C as u, c as d, i as f, n as p, s as m, t as h, x as g } from "./select-CkF_GBxO.js";
7
7
  import { d as _, h as v, i as y, l as b, n as x, o as S, s as C, t as w, u as T } from "./dropdown-menu-GWcGCcxE.js";
8
8
  import { c as E, d as D, l as O, n as k, o as A, s as ee, t as j, u as te } from "./glide-utils-Dz_F4pAY.js";
9
- import { n as ne, t as re } from "./ErrorBoundary-BuBLWxuk.js";
9
+ import { n as ne, t as re } from "./ErrorBoundary-DN6z0yV4.js";
10
10
  import { t as ie } from "./react-dom-DUmH0GXv.js";
11
11
  import { t as M } from "./jsx-runtime-3BD1kT0s.js";
12
12
  import { t as N } from "./label-D9_-zSg-.js";
@@ -7062,7 +7062,7 @@ function rs(e, t, n, r, i) {
7062
7062
  }
7063
7063
  //#endregion
7064
7064
  //#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
7065
- var is = /* @__PURE__ */ e(_r(), 1), as = /* @__PURE__ */ e(xr(), 1), os = K.lazy(async () => await import("./data-grid-overlay-editor-BGhLvQMo.js")), ss = 0;
7065
+ var is = /* @__PURE__ */ e(_r(), 1), as = /* @__PURE__ */ e(xr(), 1), os = K.lazy(async () => await import("./data-grid-overlay-editor-B0Iqui8S.js")), ss = 0;
7066
7066
  function cs(e) {
7067
7067
  return (0, is.default)((0, as.default)((0, as.default)(e).filter((e) => e.span !== void 0).map((e) => (0, Za.default)((e.span?.[0] ?? 0) + 1, (e.span?.[1] ?? 0) + 1))));
7068
7068
  }
@@ -9293,7 +9293,7 @@ function Vs(e, t, n, r, i) {
9293
9293
  }
9294
9294
  //#endregion
9295
9295
  //#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
9296
- var Hs = K.lazy(async () => await import("./number-overlay-editor-DAYzjL3A.js")), Us = {
9296
+ var Hs = K.lazy(async () => await import("./number-overlay-editor-DrEB_dOh.js")), Us = {
9297
9297
  getAccessibilityString: (e) => e.data?.toString() ?? "",
9298
9298
  kind: W.Number,
9299
9299
  needsHover: (e) => e.hoverEffect === !0,
@@ -1,6 +1,6 @@
1
1
  import { m as e } from "./tooltip-CJ4Rqasp.js";
2
2
  import { _ as t } from "./useTheme-Bq9pi_vz.js";
3
- import { r as n } from "./code-visibility-CwJEaaN5.js";
3
+ import { r as n } from "./code-visibility-BnpyGDBY.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
@@ -7,7 +7,7 @@ import { C as T, F as E, G as D, I as O, J as k, K as A, L as j, P as M, R as N,
7
7
  import { a as oe, d as se, i as ce, m as le, n as ue, o as de, p as fe, r as pe, t as me } from "./tooltip-CJ4Rqasp.js";
8
8
  import { $ as he, A as ge, At as _e, B as ve, Bt as ye, D as be, Dt as xe, G as Se, H as Ce, Ht as we, It as Te, J as Ee, Jt as De, Kt as Oe, M as ke, Mt as Ae, N as je, Nt as Me, O as Ne, Ot as Pe, P as Fe, Q as Ie, S as Le, Tt as Re, V as ze, Vt as Be, Wt as Ve, X as He, Xt as Ue, Y as We, Yt as Ge, _ as Ke, _n as qe, _t as Je, an as Ye, b as Xe, cn as Ze, ct as Qe, dn as $e, dt as et, en as tt, f as nt, ft as rt, g as it, gn as at, gt as ot, h as st, it as ct, jt as lt, k as ut, kt as dt, ln as ft, m as pt, mn as mt, nn as ht, o as gt, p as _t, pn as vt, pt as yt, qt as bt, rn as xt, rt as St, s as Ct, tn as wt, u as Tt, un as Et, v as Dt, xt as Ot, y as kt, z as At } from "./error-entries-CmFDQ9CA.js";
9
9
  import { D as jt, E as Mt, O as Nt, S as Pt, T as Ft, _ as It, a as Lt, c as Rt, d as zt, f as Bt, g as Vt, h as Ht, i as Ut, l as Wt, m as Gt, n as Kt, o as qt, p as Jt, r as Yt, s as Xt, t as Zt, u as Qt, v as $t, w as en, x as tn, y as nn } from "./spec-DiSh_qJC.js";
10
- import { $t as rn, A as an, At as on, B as sn, Bt as cn, C as ln, Ct as un, D as dn, Dt as fn, E as pn, Et as mn, F as hn, Ft as gn, G as _n, Gt as vn, H as yn, Ht as bn, I as xn, It as Sn, J as Cn, Jt as wn, K as Tn, Kt as En, L as Dn, Lt as On, M as kn, Mt as An, N as jn, Nt as Mn, O as Nn, Ot as Pn, P as Fn, Pt as In, Qt as Ln, R as Rn, Rt as zn, S as Bn, St as Vn, T as Hn, Tt as Un, U as Wn, Ut as Gn, V as Kn, Vt as qn, W as Jn, Wt as Yn, X as Xn, Xt as Zn, Y as Qn, Yt as $n, Zt as er, _ as tr, _t as nr, an as rr, at as ir, b as ar, c as or, cn as sr, ct as cr, d as lr, dn as ur, dt as dr, en as fr, et as pr, f as mr, fn as hr, ft as gr, g as _r, gt as vr, h as yr, hn as br, ht as xr, in as Sr, it as Cr, j as wr, jt as Tr, k as Er, kt as Dr, ln as Or, lt as kr, m as Ar, mn as jr, mt as Mr, nn as Nr, nt as Pr, ot as Fr, p as Ir, pn as Lr, pt as Rr, q as zr, qt as Br, r as Vr, rn as Hr, rt as Ur, sn as Wr, st as Gr, t as Kr, tn as qr, tt as Jr, u as Yr, un as Xr, ut as Zr, v as Qr, vt as $r, w as ei, wt as ti, x as ni, y as ri, yt as ii, z as ai, zt as oi } from "./common-lvg18mZi.js";
10
+ import { $t as rn, A as an, At as on, B as sn, Bt as cn, C as ln, Ct as un, D as dn, Dt as fn, E as pn, Et as mn, F as hn, Ft as gn, G as _n, Gt as vn, H as yn, Ht as bn, I as xn, It as Sn, J as Cn, Jt as wn, K as Tn, Kt as En, L as Dn, Lt as On, M as kn, Mt as An, N as jn, Nt as Mn, O as Nn, Ot as Pn, P as Fn, Pt as In, Qt as Ln, R as Rn, Rt as zn, S as Bn, St as Vn, T as Hn, Tt as Un, U as Wn, Ut as Gn, V as Kn, Vt as qn, W as Jn, Wt as Yn, X as Xn, Xt as Zn, Y as Qn, Yt as $n, Zt as er, _ as tr, _t as nr, an as rr, at as ir, b as ar, c as or, cn as sr, ct as cr, d as lr, dn as ur, dt as dr, en as fr, et as pr, f as mr, fn as hr, ft as gr, g as _r, gt as vr, h as yr, hn as br, ht as xr, in as Sr, it as Cr, j as wr, jt as Tr, k as Er, kt as Dr, ln as Or, lt as kr, m as Ar, mn as jr, mt as Mr, nn as Nr, nt as Pr, ot as Fr, p as Ir, pn as Lr, pt as Rr, q as zr, qt as Br, r as Vr, rn as Hr, rt as Ur, sn as Wr, st as Gr, t as Kr, tn as qr, tt as Jr, u as Yr, un as Xr, ut as Zr, v as Qr, vt as $r, w as ei, wt as ti, x as ni, y as ri, yt as ii, z as ai, zt as oi } from "./common-DFewtofQ.js";
11
11
  import { c as si, i as ci, n as li, o as ui, t as di } from "./useLifecycle-B5BX921H.js";
12
12
  import { t as fi } from "./check-SpOMoCLP.js";
13
13
  import { A as pi, C as mi, D as hi, E as gi, M as _i, O as vi, S as yi, T as bi, a as xi, b as Si, c as Ci, i as wi, l as Ti, n as Ei, o as Di, r as Oi, s as ki, t as Ai, w as ji, x as Mi } from "./select-CkF_GBxO.js";
@@ -15,8 +15,8 @@ import { B as Ni, C as Pi, J as Fi, Ot as Ii, S as Li, W as Ri, X as zi, Y as Bi
15
15
  import { C as fa, _ as pa, a as ma, b as ha, c as ga, f as _a, h as va, m as ya, p as ba, s as xa, u as Sa, x as Ca, y as wa } from "./toDate-DGvRHwTk.js";
16
16
  import { a as Ta, c as Ea, d as Da, f as Oa, i as ka, l as Aa, n as ja, o as Ma, r as Na, s as Pa, t as Fa } from "./process-output-Bw-vzyoy.js";
17
17
  import { a as Ia, c as La, d as Ra, i as za, l as Ba, r as Va, u as Ha } from "./glide-utils-Dz_F4pAY.js";
18
- import { n as Ua, t as Wa } from "./ErrorBoundary-BuBLWxuk.js";
19
- import { n as Ga, t as Ka } from "./globals-CvsmUhAp.js";
18
+ import { n as Ua, t as Wa } from "./ErrorBoundary-DN6z0yV4.js";
19
+ import { n as Ga, t as Ka } from "./globals-D3aosgON.js";
20
20
  import { t as qa } from "./react-dom-DUmH0GXv.js";
21
21
  import { t as Ja } from "./jsx-runtime-3BD1kT0s.js";
22
22
  import { B as Ya, C as H, Ct as Xa, D as Za, Dt as Qa, E as $a, Et as eo, F as U, G as to, H as no, I as ro, L as io, M as W, N as ao, O as oo, P as so, Q as co, R as lo, S as G, St as uo, Tt as fo, U as po, W as mo, Y as ho, Z as go, _ as _o, _t as vo, a as yo, b as bo, bt as xo, c as So, d as Co, f as wo, g as To, h as Eo, i as Do, j as K, k as Oo, l as ko, m as Ao, n as jo, o as Mo, p as No, r as Po, s as Fo, u as Io, ut as Lo, v as Ro, w as zo, wt as Bo, x as Vo, xt as Ho, y as Uo, yt as Wo } from "./use-restore-focus-CmGwRNId.js";
@@ -39,7 +39,7 @@ import { t as Ps } from "./useAsyncData-BmVgnMP5.js";
39
39
  import { i as Fs, n as Is, r as Ls } from "./formats-CCxaLPNs.js";
40
40
  import { D as Rs, O as zs } from "./vega-loader.browser-B9Pz0EGP.js";
41
41
  import { a as Bs, n as Vs } from "./loader-DOVB0Syl.js";
42
- import { c as Hs, d as Us, i as Ws, l as Gs, o as Ks, s as qs, t as Js, u as Ys } from "./code-visibility-CwJEaaN5.js";
42
+ import { c as Hs, d as Us, i as Ws, l as Gs, o as Ks, s as qs, t as Js, u as Ys } from "./code-visibility-BnpyGDBY.js";
43
43
  import { t as Xs } from "./useDeepCompareMemoize-Ch_AeGu6.js";
44
44
  import { t as Zs } from "./esm-D2gTsXEV.js";
45
45
  //#region ../node_modules/.pnpm/iconify-icon@2.3.0/node_modules/iconify-icon/dist/iconify-icon.mjs
@@ -10635,7 +10635,7 @@ function WC(e, t) {
10635
10635
  }
10636
10636
  //#endregion
10637
10637
  //#region src/plugins/impl/DataEditorPlugin.tsx
10638
- var GC = J.lazy(() => import("./glide-data-editor-CWLd9Tfd.js").then((e) => e.t)), KC = DS("marimo-data-editor", { cssStyles: [XS] }).withData(W({
10638
+ var GC = J.lazy(() => import("./glide-data-editor-CXzU0Muz.js").then((e) => e.t)), KC = DS("marimo-data-editor", { cssStyles: [XS] }).withData(W({
10639
10639
  initialValue: W({ edits: G(W({
10640
10640
  rowIdx: K(),
10641
10641
  columnId: U(),
@@ -30407,7 +30407,7 @@ function WR(e) {
30407
30407
  }
30408
30408
  //#endregion
30409
30409
  //#region src/components/editor/renderers/slides-layout/slides-layout.tsx
30410
- var GR = J.lazy(() => import("./reveal-component-De2-S3OE.js")), KR = (e) => {
30410
+ var GR = J.lazy(() => import("./reveal-component-CWAFHJZM.js")), KR = (e) => {
30411
30411
  let t = (0, X.c)(33), { layout: n, setLayout: r, cells: i, mode: a } = e, o = is(pa), s = a === "read" || o, c = is(Ke) > 1, [l, u] = (0, J.useState)(null), d;
30412
30412
  t[0] !== i || t[1] !== n ? (d = HP(i, n), t[0] = i, t[1] = n, t[2] = d) : d = t[2];
30413
30413
  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-CWLd9Tfd.js";
3
+ import { a as n } from "./glide-data-editor-CXzU0Muz.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",
@@ -4,14 +4,14 @@ 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-CJ4Rqasp.js";
6
6
  import { k as u } from "./error-entries-CmFDQ9CA.js";
7
- import { $ as d, Q as f, Z as p, an as m, i as h, l as g, ln as _, n as v, on as y, r as b, t as x, u as S } from "./common-lvg18mZi.js";
7
+ import { $ as d, Q as f, Z as p, an as m, i as h, l as g, ln as _, n as v, on as y, r as b, t as x, u as S } from "./common-DFewtofQ.js";
8
8
  import { M as C } from "./select-CkF_GBxO.js";
9
9
  import { J as ee } from "./dropdown-menu-GWcGCcxE.js";
10
10
  import { _ as w } from "./toDate-DGvRHwTk.js";
11
11
  import { t as T } from "./jsx-runtime-3BD1kT0s.js";
12
12
  import { q as E } from "./use-restore-focus-CmGwRNId.js";
13
13
  import { A as D, C as O, b as k } from "./useTheme-Bq9pi_vz.js";
14
- import { a as A, n as te, t as ne } from "./code-visibility-CwJEaaN5.js";
14
+ import { a as A, n as te, t as ne } from "./code-visibility-BnpyGDBY.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-dev136",
3
+ "version": "0.25.3-dev138",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -40,7 +40,7 @@ export class ReadonlyWasmController extends DefaultWasmController {
40
40
  public override async startSession(opts: {
41
41
  code: string;
42
42
  filename: string | null;
43
- onMessage: (message: JsonString<NotificationPayload>) => void;
43
+ onMessage?: (message: JsonString<NotificationPayload>) => void;
44
44
  }): Promise<SerializedBridge> {
45
45
  const bridge = super.startSession({
46
46
  queryParameters: {},
@@ -51,7 +51,6 @@ vi.mock("@/core/wasm/rpc", () => ({
51
51
  readNotebook: mockReadNotebook,
52
52
  saveNotebook: mockSaveNotebook,
53
53
  },
54
- send: { consumerReady: vi.fn() },
55
54
  },
56
55
  addMessageListener: (event: string, cb: () => void) => {
57
56
  rpcListeners[event] = cb;
@@ -70,9 +70,6 @@ export class PyodideBridge implements RunRequests, EditRequests {
70
70
  private pendingSessionSave: Promise<unknown> = Promise.resolve();
71
71
  private notebookConsumers = new Map<string, (event: unknown) => void>();
72
72
  private interruptBuffer?: Uint8Array;
73
- private messageConsumer:
74
- | ((message: MessageEvent<string>) => void)
75
- | undefined;
76
73
 
77
74
  public initialized = new Deferred<void>();
78
75
 
@@ -158,9 +155,6 @@ export class PyodideBridge implements RunRequests, EditRequests {
158
155
  store.set(wasmInitStateAtom, { kind: "error", message: error });
159
156
  this.initialized.reject(new Error(error));
160
157
  });
161
- this.rpc.addMessageListener("kernelMessage", ({ message }) => {
162
- this.messageConsumer?.(new MessageEvent("message", { data: message }));
163
- });
164
158
  }
165
159
 
166
160
  private async startSession() {
@@ -212,13 +206,6 @@ export class PyodideBridge implements RunRequests, EditRequests {
212
206
  }
213
207
  }
214
208
 
215
- public attachMessageConsumer(
216
- consumer: (message: MessageEvent<string>) => void,
217
- ) {
218
- this.messageConsumer = consumer;
219
- this.rpc.proxy.send.consumerReady({});
220
- }
221
-
222
209
  public async createNotebookBackend() {
223
210
  await this.initialized.promise;
224
211
  const { id } = await this.rpc.proxy.request.notebookInfo();
@@ -142,7 +142,8 @@ export class DefaultWasmController implements WasmController {
142
142
  queryParameters: Record<string, string | string[]>;
143
143
  code: string;
144
144
  filename: string | null;
145
- onMessage: (message: JsonString<NotificationPayload>) => void;
145
+ /** Receives every notification, for callers that do not follow the notebook's events. */
146
+ onMessage?: (message: JsonString<NotificationPayload>) => void;
146
147
  userConfig: UserConfig;
147
148
  }): Promise<SerializedBridge> {
148
149
  const sessionGeneration = this.sessionGeneration;
@@ -69,7 +69,8 @@ export interface WasmController {
69
69
  code: string;
70
70
  filename: string | null;
71
71
  userConfig: UserConfig;
72
- onMessage: (message: JsonString<NotificationPayload>) => void;
72
+ /** Receives every notification, for callers that do not follow the notebook's events. */
73
+ onMessage?: (message: JsonString<NotificationPayload>) => void;
73
74
  }): Promise<SerializedBridge>;
74
75
  }
75
76
 
@@ -9,14 +9,11 @@ import {
9
9
  type RPCSchema,
10
10
  } from "rpc-anywhere";
11
11
  import type { UserConfig } from "@/core/config/config-schema";
12
- import type { NotificationPayload } from "@/core/kernel/messages";
13
12
  import type {
14
13
  ListPackagesResponse,
15
14
  PackageOperationResponse,
16
15
  SaveNotebookRequest,
17
16
  } from "@/core/network/types";
18
- import type { JsonString } from "@/utils/json/base64";
19
- import { once } from "@/utils/once";
20
17
  import { decodeUtf8 } from "@/utils/strings";
21
18
  import { Deferred } from "../../../utils/Deferred";
22
19
  import { prettyError } from "../../../utils/errors";
@@ -28,7 +25,6 @@ import { TRANSPORT_ID } from "./constants";
28
25
  import { WasmFileSystem } from "./fs";
29
26
  import { getController } from "./getController";
30
27
  import { getPyodideVersion } from "./getPyodideVersion";
31
- import { MessageBuffer } from "./message-buffer";
32
28
  import { t } from "./tracer";
33
29
  import type {
34
30
  BridgePayload,
@@ -73,11 +69,6 @@ async function loadPyodideAndPackages() {
73
69
  }
74
70
  }
75
71
 
76
- const messageBuffer = new MessageBuffer(
77
- (message: JsonString<NotificationPayload>) => {
78
- rpc.send.kernelMessage({ message });
79
- },
80
- );
81
72
  const bridgeReady = new Deferred<SerializedBridge>();
82
73
  let started = false;
83
74
 
@@ -155,12 +146,6 @@ const requestHandler = createRPCRequestHandler({
155
146
  const startSession = t.wrapAsync(
156
147
  self.controller.startSession.bind(self.controller),
157
148
  );
158
- const initializeOnce = once(() => {
159
- rpc.send.initializingMessage({
160
- message: "Initializing notebook...",
161
- });
162
- rpc.send.initialized({});
163
- });
164
149
  rpc.send.initializingMessage({
165
150
  message: "Loading notebook and dependencies...",
166
151
  });
@@ -169,12 +154,12 @@ const requestHandler = createRPCRequestHandler({
169
154
  filename: opts.filename,
170
155
  queryParameters: opts.queryParameters,
171
156
  userConfig: opts.userConfig,
172
- onMessage: (msg) => {
173
- initializeOnce();
174
- messageBuffer.push(msg);
175
- },
176
157
  });
177
158
  bridgeReady.resolve(bridge);
159
+ rpc.send.initializingMessage({
160
+ message: "Initializing notebook...",
161
+ });
162
+ rpc.send.initialized({});
178
163
  workerInitSpan.end("ok");
179
164
  } catch (error) {
180
165
  rpc.send.initializedError({
@@ -385,8 +370,6 @@ export type WorkerSchema = RPCSchema<
385
370
  notebookEvent: { id: string; event: string };
386
371
  // Emitted when the worker is ready
387
372
  ready: {};
388
- // Emitted when the kernel sends a message
389
- kernelMessage: { message: JsonString<NotificationPayload> };
390
373
  // Emitted when the Pyodide is initialized
391
374
  initialized: {};
392
375
  // Emitted when the Pyodide is initializing, with new messages
@@ -409,13 +392,6 @@ rpc.addMessageListener("bootstrap", (config) => runtimeConfig.resolve(config));
409
392
 
410
393
  rpc.send("ready", {});
411
394
 
412
- /// Listeners
413
- // When the consumer is ready, start the message buffer
414
- rpc.addMessageListener("consumerReady", async () => {
415
- await pyodideReadyPromise; // Make sure loading is done
416
- messageBuffer.start();
417
- });
418
-
419
395
  const namesThatRequireSync = new Set<keyof RawBridge>([
420
396
  "save",
421
397
  "save_app_config",
@@ -1,22 +1,23 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- import { NotebookEvents } from "@marimo-team/client";
3
+ import { NotebookEvents, StreamStopped } from "@marimo-team/client";
4
4
  import { createStore } from "jotai/vanilla";
5
5
  import { afterEach, describe, expect, it, onTestFinished, vi } from "vitest";
6
6
  import { Deferred } from "@/utils/Deferred";
7
7
  import { ConnectionState } from "../../host/connection";
8
+ import { type FakeEdit, fakeBackend } from "../../host/__tests__/fixtures";
8
9
  import { createNotebookReplica } from "../../host/replica";
9
10
  import { createEditorBackend } from "../backend";
10
11
 
11
- const wasm = vi.hoisted(() => ({ enabled: false, consumer: vi.fn() }));
12
+ const wasm = vi.hoisted(() => ({ enabled: false, create: vi.fn() }));
12
13
  vi.mock("../../wasm/utils", () => ({ isWasm: () => wasm.enabled }));
13
14
  vi.mock("../../wasm/bridge", () => ({
14
- PyodideBridge: { INSTANCE: { attachMessageConsumer: wasm.consumer } },
15
+ PyodideBridge: { INSTANCE: { createNotebookBackend: wasm.create } },
15
16
  }));
16
17
 
17
18
  afterEach(() => {
18
19
  wasm.enabled = false;
19
- wasm.consumer.mockReset();
20
+ wasm.create.mockReset();
20
21
  vi.unstubAllGlobals();
21
22
  });
22
23
 
@@ -55,6 +56,8 @@ describe("createEditorBackend", () => {
55
56
  ["the default", options, "socket"],
56
57
  ] as const)("follows %s", async (_name, chosen, expected) => {
57
58
  wasm.enabled = expected === "wasm";
59
+ const worker = vi.fn(() => new Promise<void>(() => undefined));
60
+ wasm.create.mockResolvedValue(fakeBackend({ transport: worker }));
58
61
  const fetch = vi.fn(() => new Promise<Response>(() => undefined));
59
62
  const opened = sockets();
60
63
  vi.stubGlobal("fetch", fetch);
@@ -62,9 +65,8 @@ describe("createEditorBackend", () => {
62
65
  await vi.waitFor(() =>
63
66
  expect(
64
67
  {
65
- idle:
66
- events.status === "connected" && !wasm.consumer.mock.calls.length,
67
- wasm: wasm.consumer.mock.calls.length === 1,
68
+ idle: events.status === "connected" && !wasm.create.mock.calls.length,
69
+ wasm: worker.mock.calls.length === 1,
68
70
  fetch: fetch.mock.calls.length === 1,
69
71
  socket: opened.length === 1,
70
72
  }[expected],
@@ -107,19 +109,45 @@ describe("createEditorBackend", () => {
107
109
  expect(headers.get("Idempotency-Key")).toBe("edit-1");
108
110
  });
109
111
 
110
- it.each([
111
- ["a static notebook", { ...options, static: true }, false],
112
- ["WASM", options, true],
113
- ] as const)("does not edit %s", async (_name, chosen, isWasm) => {
114
- wasm.enabled = isWasm;
112
+ it("does not edit a static notebook", async () => {
115
113
  const fetch = vi.fn();
116
114
  vi.stubGlobal("fetch", fetch);
117
- const result = await createEditorBackend(chosen)
115
+ const result = await createEditorBackend({ ...options, static: true })
118
116
  .notebook("n1")
119
117
  .edit([], { idempotencyKey: "edit-1" });
120
118
  expect(result).toMatchObject({ ok: false, status: 501 });
121
119
  expect(fetch).not.toHaveBeenCalled();
122
120
  });
121
+
122
+ it("edits the WASM notebook through the worker once its stream starts", async () => {
123
+ wasm.enabled = true;
124
+ const edit = vi.fn<FakeEdit>();
125
+ const transport = vi.fn(async () => undefined);
126
+ wasm.create.mockResolvedValue(fakeBackend({ transport, edit }));
127
+ const backend = createEditorBackend(options);
128
+ expect(wasm.create).not.toHaveBeenCalled();
129
+ expect(() => backend.notebook("n1")).toThrow("has not started");
130
+
131
+ const attempt = { cursor: null, signal: new AbortController().signal };
132
+ const handlers = { open: vi.fn(), message: vi.fn() };
133
+ await backend.transport(attempt, handlers);
134
+ await backend.transport(attempt, handlers);
135
+ expect(wasm.create).toHaveBeenCalledOnce();
136
+ expect(transport).toHaveBeenCalledWith(attempt, handlers);
137
+ await backend.notebook("n1").edit([], { idempotencyKey: "edit-1" });
138
+ expect(edit).toHaveBeenCalledWith("n1", [], { idempotencyKey: "edit-1" });
139
+ });
140
+
141
+ it("stops following WASM when the worker does not start", async () => {
142
+ wasm.enabled = true;
143
+ wasm.create.mockRejectedValue(new Error("Initialization failed"));
144
+ await expect(
145
+ createEditorBackend(options).transport(
146
+ { cursor: null, signal: new AbortController().signal },
147
+ { open: vi.fn(), message: vi.fn() },
148
+ ),
149
+ ).rejects.toBeInstanceOf(StreamStopped);
150
+ });
123
151
  });
124
152
 
125
153
  describe("the session backend's startup", () => {
@@ -9,7 +9,6 @@ import { PyodideBridge } from "../wasm/bridge";
9
9
  import { isWasm } from "../wasm/utils";
10
10
  import {
11
11
  idle,
12
- pyodide,
13
12
  sessionSse,
14
13
  websocket,
15
14
  withHeaders,
@@ -61,6 +60,36 @@ function afterStartup({
61
60
  };
62
61
  }
63
62
 
63
+ /**
64
+ * Follow the notebook running in the WASM worker.
65
+ *
66
+ * The worker's backend exists once the worker has started, so the first
67
+ * connection creates it. Commands are only for a notebook its stream reported.
68
+ */
69
+ function wasm(): NotebookBackend {
70
+ let backend: Promise<NotebookBackend> | undefined;
71
+ let started: NotebookBackend | undefined;
72
+ return {
73
+ transport: async (attempt, handlers) => {
74
+ backend ??= PyodideBridge.INSTANCE.createNotebookBackend();
75
+ try {
76
+ started = await backend;
77
+ } catch (error) {
78
+ throw new StreamStopped("The WASM notebook did not start", {
79
+ cause: error,
80
+ });
81
+ }
82
+ return started.transport(attempt, handlers);
83
+ },
84
+ notebook: (id) => {
85
+ if (started === undefined) {
86
+ throw new Error("The WASM notebook has not started");
87
+ }
88
+ return started.notebook(id);
89
+ },
90
+ };
91
+ }
92
+
64
93
  /** Commands for a notebook the editor cannot change through its backend. */
65
94
  function uneditable(): ReturnType<NotebookBackend["notebook"]> {
66
95
  return {
@@ -84,12 +113,7 @@ export function createEditorBackend(
84
113
  return { transport: idle, notebook: uneditable };
85
114
  }
86
115
  if (isWasm()) {
87
- return {
88
- transport: pyodide((consumer) =>
89
- PyodideBridge.INSTANCE.attachMessageConsumer(consumer),
90
- ),
91
- notebook: uneditable,
92
- };
116
+ return wasm();
93
117
  }
94
118
  const url = afterStartup(options);
95
119
  return {
@@ -11,7 +11,7 @@ import { createNotebookReplica } from "../../../host/replica";
11
11
  import { fakeBackend, fixtureMessages } from "../../../host/__tests__/fixtures";
12
12
  import { ConnectionState } from "../../../host/connection";
13
13
  import { Deferred } from "@/utils/Deferred";
14
- import { pyodide, sessionSse, websocket } from "../notebook";
14
+ import { sessionSse, websocket } from "../notebook";
15
15
 
16
16
  const encoder = new TextEncoder();
17
17
 
@@ -403,43 +403,3 @@ describe.each(["websocket", "sse"] as const)(
403
403
  });
404
404
  },
405
405
  );
406
-
407
- describe("pyodide", () => {
408
- it("delivers worker notifications as marimo events and host events as they are", async () => {
409
- let consumer: ((message: MessageEvent<string>) => void) | undefined;
410
- const events = new NotebookEvents(
411
- pyodide((next) => {
412
- consumer = next;
413
- }),
414
- { types: ["notebook", "marimo"] },
415
- );
416
- const received = collect(events);
417
- await vi.waitFor(() => expect(consumer).toBeDefined());
418
- const send = (data: string) =>
419
- consumer?.(new MessageEvent("message", { data }));
420
- send('{"data":{"op":"kernel-ready"}}');
421
- send('{"event":"marimo","id":"3","data":{"marimo":{"op":"reconnected"}}}');
422
- expect(received).toMatchInlineSnapshot(`
423
- [
424
- {
425
- "data": {
426
- "marimo": {
427
- "op": "kernel-ready",
428
- },
429
- },
430
- "event": "marimo",
431
- },
432
- {
433
- "data": {
434
- "marimo": {
435
- "op": "reconnected",
436
- },
437
- },
438
- "event": "marimo",
439
- "id": "3",
440
- },
441
- ]
442
- `);
443
- events.close();
444
- });
445
- });
@@ -157,34 +157,3 @@ export const idle: NotebookTransport = ({ signal }, { open }) =>
157
157
  open();
158
158
  signal.addEventListener("abort", () => settle(), { once: true });
159
159
  });
160
-
161
- /**
162
- * Follow the notebook running in the WASM worker.
163
- *
164
- * The worker sends marimo notifications as `{ data: notification }`, which
165
- * arrive as `marimo` events.
166
- */
167
- export function pyodide(
168
- attach: (consumer: (message: MessageEvent<string>) => void) => void,
169
- ): NotebookTransport {
170
- return ({ signal }, { open, message }) =>
171
- new Promise((settle) => {
172
- open();
173
- attach(({ data }) => {
174
- if (signal.aborted) {
175
- return;
176
- }
177
- const value = jsonParseWithSpecialChar(data);
178
- // The worker sends notifications without the host's event envelope.
179
- message(
180
- typeof value === "object" &&
181
- value !== null &&
182
- !("event" in value) &&
183
- "data" in value
184
- ? { event: "marimo", data: { marimo: value.data } }
185
- : value,
186
- );
187
- });
188
- signal.addEventListener("abort", () => settle(), { once: true });
189
- });
190
- }
@@ -263,13 +263,18 @@ export function useNotebookSession(opts: {
263
263
  filterStorageFromVariables(variableNames);
264
264
  return;
265
265
  case "variable-values":
266
- setMetadata(
267
- msg.data.variables.map((v) => ({
266
+ setMetadata([
267
+ ...(msg.data.removed ?? []).map((v) => ({
268
+ name: v.name as VariableName,
269
+ dataType: undefined,
270
+ value: undefined,
271
+ })),
272
+ ...msg.data.variables.map((v) => ({
268
273
  name: v.name as VariableName,
269
274
  dataType: v.datatype,
270
275
  value: v.value,
271
276
  })),
272
- );
277
+ ]);
273
278
  return;
274
279
  case "alert":
275
280
  toast({