@marimo-team/islands 0.24.3-dev55 → 0.24.3-dev58
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/dist/{ErrorBoundary-uQMMsMtf.js → ErrorBoundary-D1_JTlgF.js} +1 -1
- package/dist/assets/__vite-browser-external-C9iR87Zl.js +1 -0
- package/dist/assets/{worker-BemUy60C.js → worker-D7hWi02M.js} +2 -2
- package/dist/{code-visibility-DXFlGQTg.js → code-visibility-Ct164a9c.js} +1 -1
- package/dist/{common-DHIrhrev.js → common-B8x6sgCj.js} +1 -1
- package/dist/{data-grid-overlay-editor-DhUvLXgC.js → data-grid-overlay-editor-DOiNVNSM.js} +1 -1
- package/dist/{feedback-button-DejCYgl6.js → feedback-button-ajITqvHB.js} +2 -2
- package/dist/{glide-data-editor-BeDrnFzb.js → glide-data-editor-BZeeQUSi.js} +3 -3
- package/dist/{globals-DIuJGoqK.js → globals-S6heT9pz.js} +1 -1
- package/dist/main.js +42 -30
- package/dist/{number-overlay-editor-CKgrZ6UJ.js → number-overlay-editor-DSBousWi.js} +1 -1
- package/dist/{reveal-component-sLNrYulm.js → reveal-component-CegCLPOh.js} +2 -2
- package/package.json +1 -1
- package/src/core/islands/worker-factory.ts +2 -12
- package/src/core/wasm/__tests__/bootstrap.test.ts +63 -0
- package/src/core/wasm/__tests__/bridge.test.ts +8 -0
- package/src/core/wasm/__tests__/fs.test.ts +22 -0
- package/src/core/wasm/__tests__/runtime-config.test.ts +58 -0
- package/src/core/wasm/bridge.ts +18 -16
- package/src/core/wasm/rpc.ts +2 -0
- package/src/core/wasm/runtime-config.ts +27 -0
- package/src/core/wasm/worker/bootstrap.ts +21 -11
- package/src/core/wasm/worker/fs.ts +4 -0
- package/src/core/wasm/worker/save-worker.ts +7 -0
- package/src/core/wasm/worker/types.ts +7 -4
- package/src/core/wasm/worker/worker.ts +6 -0
- package/src/utils/__tests__/worker.test.ts +81 -0
- package/src/utils/worker.ts +22 -0
- package/dist/assets/__vite-browser-external-BajL8aoc.js +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
import type { PyodideInterface } from "pyodide";
|
|
3
|
+
import type { WasmRuntimeConfig } from "../runtime-config";
|
|
3
4
|
import type { UserConfig } from "@/core/config/config-schema";
|
|
4
5
|
import type {
|
|
5
6
|
CommandMessage,
|
|
@@ -43,10 +44,12 @@ export interface WasmController {
|
|
|
43
44
|
* Prepare the wasm environment
|
|
44
45
|
* @param opts.version - The marimo version
|
|
45
46
|
*/
|
|
46
|
-
bootstrap(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
bootstrap(
|
|
48
|
+
opts: WasmRuntimeConfig & {
|
|
49
|
+
version: string;
|
|
50
|
+
pyodideVersion: string;
|
|
51
|
+
},
|
|
52
|
+
): Promise<PyodideInterface>;
|
|
50
53
|
/**
|
|
51
54
|
* Mount the filesystem
|
|
52
55
|
* @param opts.code - The code to mount
|
|
@@ -22,6 +22,7 @@ import { prettyError } from "../../../utils/errors";
|
|
|
22
22
|
import { invariant } from "../../../utils/invariant";
|
|
23
23
|
import { Logger } from "../../../utils/Logger";
|
|
24
24
|
import type { ParentSchema } from "../rpc";
|
|
25
|
+
import type { WasmRuntimeConfig } from "../runtime-config";
|
|
25
26
|
import { TRANSPORT_ID } from "./constants";
|
|
26
27
|
import { WasmFileSystem } from "./fs";
|
|
27
28
|
import { getController } from "./getController";
|
|
@@ -47,6 +48,8 @@ declare const self: Window & {
|
|
|
47
48
|
|
|
48
49
|
const workerInitSpan = t.startSpan("worker:init");
|
|
49
50
|
|
|
51
|
+
const runtimeConfig = new Deferred<WasmRuntimeConfig>();
|
|
52
|
+
|
|
50
53
|
// Initialize pyodide
|
|
51
54
|
async function loadPyodideAndPackages() {
|
|
52
55
|
try {
|
|
@@ -58,6 +61,7 @@ async function loadPyodideAndPackages() {
|
|
|
58
61
|
message: "Loading marimo...",
|
|
59
62
|
});
|
|
60
63
|
self.pyodide = await t.wrapAsync(controller.bootstrap.bind(controller))({
|
|
64
|
+
...(await runtimeConfig.promise),
|
|
61
65
|
version: marimoVersion,
|
|
62
66
|
pyodideVersion: pyodideVersion,
|
|
63
67
|
});
|
|
@@ -354,6 +358,8 @@ const rpc = createRPC<WorkerSchema, ParentSchema>({
|
|
|
354
358
|
requestHandler,
|
|
355
359
|
});
|
|
356
360
|
|
|
361
|
+
rpc.addMessageListener("bootstrap", (config) => runtimeConfig.resolve(config));
|
|
362
|
+
|
|
357
363
|
rpc.send("ready", {});
|
|
358
364
|
|
|
359
365
|
/// Listeners
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { createModuleWorker } from "../worker";
|
|
4
|
+
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
vi.unstubAllGlobals();
|
|
7
|
+
vi.restoreAllMocks();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
describe("createModuleWorker", () => {
|
|
11
|
+
it.each(["http", "blob"])(
|
|
12
|
+
"preserves caller-owned %s worker URLs",
|
|
13
|
+
(scheme) => {
|
|
14
|
+
const Worker = vi.fn(function (
|
|
15
|
+
_url: string | URL,
|
|
16
|
+
_options: WorkerOptions,
|
|
17
|
+
) {
|
|
18
|
+
return {};
|
|
19
|
+
});
|
|
20
|
+
vi.stubGlobal("Worker", Worker);
|
|
21
|
+
const url = new URL(
|
|
22
|
+
scheme === "blob"
|
|
23
|
+
? `blob:${location.origin}/worker`
|
|
24
|
+
: new URL("/worker.js", location.href),
|
|
25
|
+
);
|
|
26
|
+
const revoke = vi.spyOn(URL, "revokeObjectURL");
|
|
27
|
+
createModuleWorker(url, { name: "marimo" });
|
|
28
|
+
expect(Worker).toHaveBeenCalledWith(url.href, {
|
|
29
|
+
type: "module",
|
|
30
|
+
name: "marimo",
|
|
31
|
+
});
|
|
32
|
+
expect(revoke).not.toHaveBeenCalled();
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
it("preserves the page origin for hosted CDN workers", () => {
|
|
37
|
+
const Worker = vi.fn(function (
|
|
38
|
+
_url: string | URL,
|
|
39
|
+
_options: WorkerOptions,
|
|
40
|
+
) {
|
|
41
|
+
return {};
|
|
42
|
+
});
|
|
43
|
+
vi.stubGlobal("Worker", Worker);
|
|
44
|
+
const create = vi
|
|
45
|
+
.spyOn(URL, "createObjectURL")
|
|
46
|
+
.mockReturnValue("blob:worker");
|
|
47
|
+
const revoke = vi
|
|
48
|
+
.spyOn(URL, "revokeObjectURL")
|
|
49
|
+
.mockImplementation(() => undefined);
|
|
50
|
+
createModuleWorker(new URL("https://cdn.example.com/worker.js"), {
|
|
51
|
+
name: "islands",
|
|
52
|
+
});
|
|
53
|
+
expect(create).toHaveBeenCalledWith(expect.any(Blob));
|
|
54
|
+
expect(Worker).toHaveBeenCalledWith("blob:worker", {
|
|
55
|
+
type: "module",
|
|
56
|
+
name: "islands",
|
|
57
|
+
});
|
|
58
|
+
expect(revoke).toHaveBeenCalledWith("blob:worker");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("imports a CDN worker from an opaque origin", () => {
|
|
62
|
+
const Worker = vi.fn(function (
|
|
63
|
+
_url: string | URL,
|
|
64
|
+
_options: WorkerOptions,
|
|
65
|
+
) {
|
|
66
|
+
return {};
|
|
67
|
+
});
|
|
68
|
+
vi.stubGlobal("Worker", Worker);
|
|
69
|
+
vi.stubGlobal("origin", "null");
|
|
70
|
+
const url = new URL("https://cdn.example.com/worker.js");
|
|
71
|
+
createModuleWorker(url, { name: "0.24.2::controller" });
|
|
72
|
+
const [source, options] = Worker.mock.calls[0];
|
|
73
|
+
expect(decodeURIComponent(String(source))).toBe(
|
|
74
|
+
'data:application/javascript,import "https://cdn.example.com/worker.js"',
|
|
75
|
+
);
|
|
76
|
+
expect(options).toEqual({
|
|
77
|
+
type: "module",
|
|
78
|
+
name: "0.24.2::controller",
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
/** Load a module worker across origins, including from file:// pages. */
|
|
4
|
+
export function createModuleWorker(url: URL, options: WorkerOptions): Worker {
|
|
5
|
+
if (url.origin === globalThis.origin) {
|
|
6
|
+
return new Worker(url.href, { ...options, type: "module" });
|
|
7
|
+
}
|
|
8
|
+
const js = `import ${JSON.stringify(url.href)}`;
|
|
9
|
+
// Blob workers preserve the page origin, but file:// needs a data URL.
|
|
10
|
+
const source =
|
|
11
|
+
globalThis.origin === "null"
|
|
12
|
+
? `data:application/javascript,${encodeURIComponent(js)}`
|
|
13
|
+
: URL.createObjectURL(new Blob([js], { type: "application/javascript" }));
|
|
14
|
+
try {
|
|
15
|
+
return new Worker(source, { ...options, type: "module" });
|
|
16
|
+
} finally {
|
|
17
|
+
if (source.startsWith("blob:")) {
|
|
18
|
+
// Worker() captures the Blob before returning, even while imports load.
|
|
19
|
+
URL.revokeObjectURL(source);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./worker-BemUy60C.js";var t=e(((e,t)=>{t.exports={}}));export default t();
|