@marimo-team/islands 0.23.14-dev34 → 0.23.14-dev35

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.
@@ -36198,7 +36198,7 @@ ${d}`,
36198
36198
  return Logger.warn("Failed to get version from mount config"), null;
36199
36199
  }
36200
36200
  }
36201
- marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.14-dev34");
36201
+ marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.14-dev35");
36202
36202
  showCodeInRunModeAtom = atom(true);
36203
36203
  atom(null);
36204
36204
  var import_compiler_runtime = require_compiler_runtime();
package/dist/main.js CHANGED
@@ -26,7 +26,7 @@ import { $ as reducer, $t as requestClientAtom, A as ChevronDownIcon, At as Path
26
26
  import { __tla as __tla_1 } from "./chunk-5FQGJX7Z-BbqSm5gU.js";
27
27
  import { o as useSize, s as Root$1, u as createLucideIcon } from "./dist--2Bqjvs0.js";
28
28
  import { A as SquareFunction, C as DEFAULT_COLOR_SCHEME, D as SCALE_TYPE_DESCRIPTIONS, E as EMPTY_VALUE$1, O as TIME_UNIT_DESCRIPTIONS, S as DEFAULT_AGGREGATION, T as DEFAULT_TIME_UNIT, _ as AGGREGATION_TYPE_DESCRIPTIONS, a as AGGREGATION_FNS$1, b as COLOR_SCHEMES, c as COLOR_BY_FIELDS, d as NONE_VALUE, f as SELECTABLE_DATA_TYPES, g as TIME_UNITS, h as STRING_AGGREGATION_FNS, i as convertDataTypeToSelectable, j as ChartColumn, k as escapeFieldName, l as COMBINED_TIME_UNITS, m as SORT_TYPES, n as createSpecWithoutData, o as BIN_AGGREGATION, p as SINGLE_TIME_UNITS, r as isFieldSet, s as CHART_TYPES, t as augmentSpecWithData, u as ChartType, v as AGGREGATION_TYPE_ICON, w as DEFAULT_MAX_BINS_FACET, x as COUNT_FIELD, y as CHART_TYPE_ICON } from "./spec-CnTgI25l.js";
29
- import { $ as PANEL_TYPES, $t as HtmlOutput, A as prettifyRowCount, At as INDEX_COLUMN_NAME, B as CompactChipRow, Bt as dateToLocalISODateTime, C as downloadSizeLimitAtom, Ct as ColumnChartSpecModel, D as ErrorState, Dt as getPageIndexForRow, E as EmptyState, Et as usePrevious$1, F as ContextMenuItem, Ft as hasFunctionProperty, G as Command, Gt as TabsTrigger, H as DateRangePicker, Ht as Tabs, I as ContextMenuSeparator, It as isRecord, J as CommandItem, Jt as ChartLoadingState, K as CommandEmpty, Kt as ChartErrorState, L as ContextMenuTrigger, Lt as isNullishFilter, M as getUserColumnVisibilityCounts, Mt as TOO_MANY_ROWS, N as ContextMenu, Nt as toFieldTypes, O as LoadingState, Ot as loadTableAndRawData, P as ContextMenuContent, Pt as getMimeValues, Q as ContextAwarePanelItem, Qt as Kbd, R as useInternalStateWithSync, Rt as Maps, S as Filenames, St as ColumnChartContext, T as ColumnPreviewContainer, Tt as useIntersectionObserver, U as Combobox, Ut as TabsContent, V as DatePicker, Vt as dateToLocalISOTime, W as ComboboxItem, Wt as TabsList, X as CommandSeparator, Xt as useOverflowDetection, Y as CommandList, Yt as LazyVegaEmbed, Z as smartMatch, Zt as RenderTextWithLinks, _ as ADD_PRINTING_CLASS, _t as TableRow, an as Funnel, at as slotsController, b as downloadHTMLAsImage, bt as inferFieldTypes, c as Slide, cn as Ellipsis, d as RadioGroupItem, dn as ChevronsUpDown, dt as Provider$1, en as EmotionCacheProvider, et as contextAwarePanelOpen, f as JsonOutput, fn as ChevronsRight, ft as Table, g as InstallPackageButton, gn as ArrowDownWideNarrow, gt as TableHeader, h as DataTable, hn as ChevronLeft, ht as TableHead, in as GripHorizontal, it as SlotNames, j as getColumnCountForDisplay, jt as SELECT_COLUMN_ID, k as prettifyRowColumnCount, kt as loadTableData, l as Switch, ln as Download, m as OutputRenderer, mn as ChevronsDownUp, mt as TableCell, n as marimoVersionAtom, nn as $fae977aafc393c5c$export$6b862160d295c8e, nt as contextAwarePanelType, o as SLIDE_TYPE_OPTIONS_BY_VALUE, on as EyeOff, ot as Toggle, p as OutputArea, pn as ChevronsLeft, pt as TableBody, q as CommandInput, qt as ChartInfoState, r as showCodeInRunModeAtom, rn as TextWrap, rt as isCellAwareAtom, t as useNotebookCodeAvailable, tn as $fae977aafc393c5c$export$588937bcd60ade55, tt as contextAwarePanelOwner, u as RadioGroup, un as Code, ut as Fill, v as downloadBlob, vt as NAMELESS_COLUMN_PREFIX, w as ColumnName, wt as DelayMount, x as Progress, xt as renderCellValue, y as downloadByURL, yt as generateColumns, z as useSelectList, zt as dateToLocalISODate, __tla as __tla_2 } from "./code-visibility-BLnXV6lv.js";
29
+ import { $ as PANEL_TYPES, $t as HtmlOutput, A as prettifyRowCount, At as INDEX_COLUMN_NAME, B as CompactChipRow, Bt as dateToLocalISODateTime, C as downloadSizeLimitAtom, Ct as ColumnChartSpecModel, D as ErrorState, Dt as getPageIndexForRow, E as EmptyState, Et as usePrevious$1, F as ContextMenuItem, Ft as hasFunctionProperty, G as Command, Gt as TabsTrigger, H as DateRangePicker, Ht as Tabs, I as ContextMenuSeparator, It as isRecord, J as CommandItem, Jt as ChartLoadingState, K as CommandEmpty, Kt as ChartErrorState, L as ContextMenuTrigger, Lt as isNullishFilter, M as getUserColumnVisibilityCounts, Mt as TOO_MANY_ROWS, N as ContextMenu, Nt as toFieldTypes, O as LoadingState, Ot as loadTableAndRawData, P as ContextMenuContent, Pt as getMimeValues, Q as ContextAwarePanelItem, Qt as Kbd, R as useInternalStateWithSync, Rt as Maps, S as Filenames, St as ColumnChartContext, T as ColumnPreviewContainer, Tt as useIntersectionObserver, U as Combobox, Ut as TabsContent, V as DatePicker, Vt as dateToLocalISOTime, W as ComboboxItem, Wt as TabsList, X as CommandSeparator, Xt as useOverflowDetection, Y as CommandList, Yt as LazyVegaEmbed, Z as smartMatch, Zt as RenderTextWithLinks, _ as ADD_PRINTING_CLASS, _t as TableRow, an as Funnel, at as slotsController, b as downloadHTMLAsImage, bt as inferFieldTypes, c as Slide, cn as Ellipsis, d as RadioGroupItem, dn as ChevronsUpDown, dt as Provider$1, en as EmotionCacheProvider, et as contextAwarePanelOpen, f as JsonOutput, fn as ChevronsRight, ft as Table, g as InstallPackageButton, gn as ArrowDownWideNarrow, gt as TableHeader, h as DataTable, hn as ChevronLeft, ht as TableHead, in as GripHorizontal, it as SlotNames, j as getColumnCountForDisplay, jt as SELECT_COLUMN_ID, k as prettifyRowColumnCount, kt as loadTableData, l as Switch, ln as Download, m as OutputRenderer, mn as ChevronsDownUp, mt as TableCell, n as marimoVersionAtom, nn as $fae977aafc393c5c$export$6b862160d295c8e, nt as contextAwarePanelType, o as SLIDE_TYPE_OPTIONS_BY_VALUE, on as EyeOff, ot as Toggle, p as OutputArea, pn as ChevronsLeft, pt as TableBody, q as CommandInput, qt as ChartInfoState, r as showCodeInRunModeAtom, rn as TextWrap, rt as isCellAwareAtom, t as useNotebookCodeAvailable, tn as $fae977aafc393c5c$export$588937bcd60ade55, tt as contextAwarePanelOwner, u as RadioGroup, un as Code, ut as Fill, v as downloadBlob, vt as NAMELESS_COLUMN_PREFIX, w as ColumnName, wt as DelayMount, x as Progress, xt as renderCellValue, y as downloadByURL, yt as generateColumns, z as useSelectList, zt as dateToLocalISODate, __tla as __tla_2 } from "./code-visibility-CbaQRHz2.js";
30
30
  import { c as Calendar, i as createReducerAndAtoms, n as useOnUnmount, o as ToggleLeft, t as useOnMount } from "./useLifecycle-CxffarYV.js";
31
31
  import { t as Check } from "./check-C9OoNtR4.js";
32
32
  import { A as Icon, C as logNever, D as $18f2051aff69b9bf$export$a54013f0d02a8f82, E as $18f2051aff69b9bf$export$43bb16f9c6d9e3f7, F as createCollection, I as X, M as clamp$2, N as usePrevious$2, P as useDirection, R as ChevronDown, S as assertNever, a as SelectGroup, c as SelectSeparator, d as NativeSelect, i as SelectContent, j as Trigger$1, l as SelectTrigger, n as capitalize, o as SelectItem, r as Select, s as SelectLabel, t as Strings, u as SelectValue, w as $a916eb452884faea$export$b7a616150fdb9f44 } from "./strings-Dq_j3Rxw.js";
@@ -36313,7 +36313,7 @@ ${c}
36313
36313
  function _temp2$2(e) {
36314
36314
  e.target === e.currentTarget && e.key === "Enter" && (e.preventDefault(), e.stopPropagation(), e.currentTarget.click());
36315
36315
  }
36316
- var LazySlidesComponent = import_react.lazy(() => import("./reveal-component-D6H16dMJ.js"));
36316
+ var LazySlidesComponent = import_react.lazy(() => import("./reveal-component-BSTNfFu5.js"));
36317
36317
  const SlidesLayoutRenderer = ({ layout: e, setLayout: r, cells: c, mode: l }) => {
36318
36318
  var _a3;
36319
36319
  let u = useAtomValue(kioskModeAtom), d = l === "read" || u, f = useAtomValue(numColumnsAtom) > 1, [p, m] = (0, import_react.useState)(null), { slideCells: h, skippedIds: g, noOutputIds: _, slideTypes: v, startCellIndex: y } = (0, import_react.useMemo)(() => computeSlideCellsInfo(c, e), [
@@ -9,7 +9,7 @@ import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
9
9
  import { lt as kioskModeAtom, pt as outputIsStale } from "./html-to-image-DLSOS-bE.js";
10
10
  import "./chunk-5FQGJX7Z-BbqSm5gU.js";
11
11
  import { u as createLucideIcon } from "./dist--2Bqjvs0.js";
12
- import { a as DEFAULT_SLIDE_TYPE, c as Slide, ct as PanelGroup, i as DEFAULT_DECK_TRANSITION, lt as PanelResizeHandle, on as EyeOff, s as SlideSidebar, sn as Expand, st as Panel, t as useNotebookCodeAvailable, un as Code } from "./code-visibility-BLnXV6lv.js";
12
+ import { a as DEFAULT_SLIDE_TYPE, c as Slide, ct as PanelGroup, i as DEFAULT_DECK_TRANSITION, lt as PanelResizeHandle, on as EyeOff, s as SlideSidebar, sn as Expand, st as Panel, t as useNotebookCodeAvailable, un as Code } from "./code-visibility-CbaQRHz2.js";
13
13
  import { X as useDebouncedCallback } from "./input-BSdZp5Ng.js";
14
14
  import "./toDate-D1Z7ZXWh.js";
15
15
  import "./react-dom-BTJzcVJ9.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.23.14-dev34",
3
+ "version": "0.23.14-dev35",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -1,6 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import { beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { HTTPError } from "@/utils/errors";
4
5
  import { API } from "../api";
5
6
 
6
7
  // Mock fetch globally
@@ -77,4 +78,20 @@ describe("API", () => {
77
78
  expect.objectContaining({ method: "POST" }),
78
79
  );
79
80
  });
81
+
82
+ it("openapi-client error rejects with HTTPError carrying the status", async () => {
83
+ const body = { detail: "This connection is read-only for this action." };
84
+ await expect(
85
+ API.handleResponseReturnNull({
86
+ error: body,
87
+ response: { status: 403, statusText: "Forbidden" } as Response,
88
+ }),
89
+ ).rejects.toMatchObject({ status: 403, cause: body });
90
+ await expect(
91
+ API.handleResponseReturnNull({
92
+ error: body,
93
+ response: { status: 403, statusText: "Forbidden" } as Response,
94
+ }),
95
+ ).rejects.toBeInstanceOf(HTTPError);
96
+ });
80
97
  });
@@ -0,0 +1,46 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { HTTPError } from "@/utils/errors";
5
+
6
+ const toastMock = vi.fn();
7
+ vi.mock("@/components/ui/use-toast", () => ({
8
+ toast: (...args: unknown[]) => toastMock(...args),
9
+ }));
10
+
11
+ import { createErrorToastingRequests } from "../requests-toasting";
12
+ import type { EditRequests, RunRequests } from "../types";
13
+
14
+ function requestsThatReject(error: unknown): EditRequests & RunRequests {
15
+ return createErrorToastingRequests({
16
+ sendRun: vi.fn().mockRejectedValue(error),
17
+ } as unknown as EditRequests & RunRequests);
18
+ }
19
+
20
+ describe("createErrorToastingRequests", () => {
21
+ beforeEach(() => {
22
+ toastMock.mockClear();
23
+ });
24
+
25
+ it("suppresses the error toast for a capability 403", async () => {
26
+ const requests = requestsThatReject(
27
+ new HTTPError(403, "Forbidden", {
28
+ detail: "This connection is read-only for this action.",
29
+ }),
30
+ );
31
+ await expect(requests.sendRun({} as never)).rejects.toBeInstanceOf(
32
+ HTTPError,
33
+ );
34
+ expect(toastMock).not.toHaveBeenCalled();
35
+ });
36
+
37
+ it("shows a danger toast for other request errors", async () => {
38
+ const requests = requestsThatReject(new HTTPError(500, "Server Error"));
39
+ await expect(requests.sendRun({} as never)).rejects.toBeInstanceOf(
40
+ HTTPError,
41
+ );
42
+ expect(toastMock).toHaveBeenCalledWith(
43
+ expect.objectContaining({ variant: "danger" }),
44
+ );
45
+ });
46
+ });
@@ -1,6 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import { createMarimoClient } from "@marimo-team/marimo-api";
4
+ import { HTTPError } from "../../utils/errors";
4
5
  import { Logger } from "../../utils/Logger";
5
6
  import { Strings } from "../../utils/strings";
6
7
  import { getRuntimeManager } from "../runtime/config";
@@ -50,7 +51,7 @@ export const API = {
50
51
  const errorBody = isJson
51
52
  ? await response.json()
52
53
  : await response.text();
53
- throw new Error(response.statusText, { cause: errorBody });
54
+ throw new HTTPError(response.status, response.statusText, errorBody);
54
55
  }
55
56
  if (isJson) {
56
57
  return response.json() as RESP;
@@ -83,7 +84,7 @@ export const API = {
83
84
  })
84
85
  .then((response) => {
85
86
  if (!response.ok) {
86
- throw new Error(response.statusText);
87
+ throw new HTTPError(response.status, response.statusText);
87
88
  }
88
89
  if (
89
90
  response.headers.get("Content-Type")?.startsWith("application/json")
@@ -108,8 +109,13 @@ export const API = {
108
109
  response: Response;
109
110
  }): Promise<T> => {
110
111
  if (response.error) {
111
- // oxlint-disable-next-line typescript/prefer-promise-reject-errors
112
- return Promise.reject(response.error);
112
+ return Promise.reject(
113
+ new HTTPError(
114
+ response.response.status,
115
+ response.response.statusText,
116
+ response.error,
117
+ ),
118
+ );
113
119
  }
114
120
  return Promise.resolve(response.data as T);
115
121
  },
@@ -118,8 +124,13 @@ export const API = {
118
124
  response: Response;
119
125
  }): Promise<null> => {
120
126
  if (response.error) {
121
- // oxlint-disable-next-line typescript/prefer-promise-reject-errors
122
- return Promise.reject(response.error);
127
+ return Promise.reject(
128
+ new HTTPError(
129
+ response.response.status,
130
+ response.response.statusText,
131
+ response.error,
132
+ ),
133
+ );
123
134
  }
124
135
  return Promise.resolve(null);
125
136
  },
@@ -5,7 +5,7 @@ import { useAtomValue } from "jotai";
5
5
  import { Spinner } from "@/components/icons/spinner";
6
6
  import { Button } from "@/components/ui/button";
7
7
  import { toast } from "@/components/ui/use-toast";
8
- import { NoKernelConnectedError, prettyError } from "@/utils/errors";
8
+ import { HTTPError, NoKernelConnectedError, prettyError } from "@/utils/errors";
9
9
  import { Logger } from "@/utils/Logger";
10
10
  import { useConnectToRuntime } from "../runtime/config";
11
11
  import { store } from "../state/jotai";
@@ -109,6 +109,14 @@ export function createErrorToastingRequests(
109
109
  throw error;
110
110
  }
111
111
 
112
+ // A capability 403: the connection is read-only for this action. The
113
+ // live capability notification already moved the UI to viewer state,
114
+ // so don't alarm the user with an error toast.
115
+ if (error instanceof HTTPError && error.status === 403) {
116
+ Logger.warn(`Request refused, connection is read-only: ${key}`);
117
+ throw error;
118
+ }
119
+
112
120
  const title = MESSAGES[keyString];
113
121
  const message = prettyError(error);
114
122
  if (title) {
@@ -62,6 +62,21 @@ function safeJSONParse(message: string): unknown {
62
62
  }
63
63
  }
64
64
 
65
+ /**
66
+ * A failed HTTP response. Carries the status code so callers can branch on it
67
+ * (e.g. treat a capability 403 as a benign viewer state). The response body is
68
+ * kept as `cause` so `prettyError` can surface its `detail`.
69
+ */
70
+ export class HTTPError extends Error {
71
+ readonly status: number;
72
+
73
+ constructor(status: number, statusText: string, body?: unknown) {
74
+ super(statusText, { cause: body });
75
+ this.name = "HTTPError";
76
+ this.status = status;
77
+ }
78
+ }
79
+
65
80
  export class CellNotInitializedError extends Error {
66
81
  constructor(
67
82
  message = "The cell containing this UI element has not been run yet. Please run the cell first.",