@preact-mvc/atoll 0.1.0 → 0.1.2

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/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # @preact-mvc/atoll
2
+
3
+ [![CI](https://github.com/jwhenry3/preact-mvc/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/jwhenry3/preact-mvc/actions/workflows/ci.yml)
4
+ [![codecov](https://codecov.io/gh/jwhenry3/preact-mvc/graph/badge.svg?branch=main)](https://codecov.io/gh/jwhenry3/preact-mvc)
5
+ [![Socket Badge](https://badge.socket.dev/npm/package/@preact-mvc/atoll)](https://badge.socket.dev/npm/package/@preact-mvc/atoll)
6
+
7
+ Framework-free worker-rendered islands, modeled on
8
+ [Atoll](https://jwhenry3.github.io/atolljs/): a facade over
9
+ `@atolljs/islands` + `@atolljs/core` that mounts a worker-hosted UI tree
10
+ as an ordinary element. The worker renders against a proxy DOM; commits
11
+ stream back over `postMessage` as ops the main-thread driver replays as
12
+ real DOM. Nothing in this package knows about the framework — that's what
13
+ `@preact-mvc/atoll-island` adds.
14
+
15
+ **[PreactMVC — islands documentation](https://jwhenry3.github.io/preact-mvc/docs/islands/)**
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm install @preact-mvc/atoll
21
+ ```
22
+
23
+ ## The contract is the shared module
24
+
25
+ `defineIslandContract` names the registry app, declares emit payloads
26
+ (validated worker-side with zod), and carries the worker factory — the
27
+ one file both threads import:
28
+
29
+ ```ts
30
+ // ticker.contract.ts
31
+ import { defineIslandContract, z } from '@preact-mvc/atoll';
32
+
33
+ export const tickerContract = defineIslandContract({
34
+ app: 'ticker',
35
+ events: {
36
+ 'worker-ping': z.object({ count: z.number() }),
37
+ },
38
+ // The URL literal stays bundler-detectable — never hoist or compute it.
39
+ worker: () =>
40
+ new Worker(new URL('./ticker.worker.ts', import.meta.url), {
41
+ type: 'module',
42
+ }),
43
+ });
44
+ ```
45
+
46
+ ## Shell side
47
+
48
+ ```ts
49
+ import { mountIsland, connectIslandWorker, callbackProp } from '@preact-mvc/atoll';
50
+ ```
51
+
52
+ - `mountIsland` — mount a registered worker app into a host element.
53
+ - `connectIslandWorker` — drive an already-running worker.
54
+ - `callbackProp` — mark a prop as a function that crosses the wire.
55
+ - `islandApp`, `defineIslandContract`, `isIslandContract`, `z` — the
56
+ registry/contract API re-exported from `@atolljs/islands` +
57
+ `@atolljs/core`.
58
+ - `@preact-mvc/atoll/worker` — the worker-side entry (proxy DOM,
59
+ instance dispatcher); import it only in worker code.
60
+
61
+ Rules of the wire: props and event payloads must be `structuredClone`-able;
62
+ functions cross only via `callbackProp` markers; worker code sees the
63
+ proxy DOM and nothing else — `document` resolves through the instance
64
+ dispatcher, never ambient globals.
65
+
66
+ Published builds ship compiled `dist/` (`.js` + `.d.ts`).
@@ -0,0 +1,77 @@
1
+ /**
2
+ * `@preact-mvc/atoll` shell surface — a thin facade over `@atolljs/islands`
3
+ * (docs/atoll/islands.md). The op protocol, proxy DOM, instance lifecycle,
4
+ * and op-replay driver are the real package now; this file only normalizes
5
+ * the worker option (an already-created WorkerLike counts as an entry, the
6
+ * real package wants a bundler-detectable factory or URL) and defaults the
7
+ * transport to message-only so mounts work without COOP/COEP headers —
8
+ * GitHub Pages can't serve them.
9
+ *
10
+ * Push mode still works: pass `mode: 'push'` on a `worker:` mount (builds a
11
+ * doorbell client) or `doorbell: true` on `connectIslandWorker`, and serve
12
+ * Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy:
13
+ * require-corp.
14
+ */
15
+ import { callbackProp } from '@atolljs/islands';
16
+ import type { IslandClient, IslandHandle, IslandWorkerOptions, Mode, Op } from '@atolljs/islands';
17
+ export { callbackProp };
18
+ export type { IslandClient, IslandHandle, Mode, Op };
19
+ /**
20
+ * What a `worker:` option accepts: a bundler-detectable factory
21
+ * `() => new Worker(new URL(...))`, a URL, or an already-spawned worker
22
+ * (test doubles like `InProcessWorker` count — the real `Worker` type would
23
+ * reject them, so the surface is structural).
24
+ */
25
+ export type WorkerLike = Pick<Worker, 'postMessage' | 'addEventListener' | 'removeEventListener' | 'terminate'>;
26
+ export interface ConnectOptions extends IslandWorkerOptions {
27
+ /** Bundler-detectable factory / URL, or an already-spawned worker. */
28
+ worker: WorkerLike | (() => WorkerLike) | URL;
29
+ /**
30
+ * Shared-memory doorbell for push-mode flush — requires cross-origin
31
+ * isolation. Default false (message-only): mounts fall back to the 50ms
32
+ * poll, which needs no special headers.
33
+ */
34
+ doorbell?: boolean;
35
+ /**
36
+ * Keep the worker thread resident (but idle) when its last island
37
+ * destroys: the instance still unmounts — dispose hooks run, ops stop —
38
+ * but the thread's module graph and worker-side caches survive, so the
39
+ * next mount on this client is a warm start. Explicit `client.terminate()`
40
+ * still kills it.
41
+ */
42
+ keepAlive?: boolean;
43
+ }
44
+ /** One island client = one dedicated worker. Islands mounted with `client:`
45
+ * share it; each `worker:` mount builds its own. */
46
+ export declare function connectIslandWorker({ worker, doorbell, ...options }: ConnectOptions): IslandClient;
47
+ export interface MountOptions extends IslandWorkerOptions {
48
+ /** Container the island's ops replay into. */
49
+ el: HTMLElement;
50
+ /**
51
+ * Which app to mount: the `apps` registry key, a stamped app
52
+ * (`islandApp`/`viewIsland` result), or a contract. Resolved through
53
+ * `islandAppNameOf` — bare components fall back to the function name.
54
+ */
55
+ app?: unknown;
56
+ props?: Record<string, unknown>;
57
+ /** Island → shell channel: receives every worker-side `emit(name, payload)`. */
58
+ onEvent?: (name: string, payload: unknown) => void;
59
+ /** `data-atoll-slot` transclusion holes — shell mounts real DOM inside. */
60
+ slots?: Record<string, (el: HTMLElement | null) => void>;
61
+ onActivity?: () => void;
62
+ onOps?: (ops: readonly Op[], elapsedMs: number) => void;
63
+ /**
64
+ * 'push' uses the doorbell SAB (cross-origin isolation required for
65
+ * `worker:` mounts); 'poll' (the default here) needs none.
66
+ */
67
+ mode?: Mode;
68
+ /** Devtools renderer tag ('preact-mvc'); the adapter sets it. */
69
+ framework?: string;
70
+ mountTimeout?: number;
71
+ /** This mount's destroy() leaves the client resident-but-idle. */
72
+ keepAlive?: boolean;
73
+ /** A shared `connectIslandWorker` client, OR an entry this mount owns. */
74
+ client?: IslandClient;
75
+ worker?: WorkerLike | (() => WorkerLike) | URL;
76
+ }
77
+ export declare function mountIsland(opts: MountOptions): Promise<IslandHandle>;
package/dist/driver.js ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `@preact-mvc/atoll` shell surface — a thin facade over `@atolljs/islands`
3
+ * (docs/atoll/islands.md). The op protocol, proxy DOM, instance lifecycle,
4
+ * and op-replay driver are the real package now; this file only normalizes
5
+ * the worker option (an already-created WorkerLike counts as an entry, the
6
+ * real package wants a bundler-detectable factory or URL) and defaults the
7
+ * transport to message-only so mounts work without COOP/COEP headers —
8
+ * GitHub Pages can't serve them.
9
+ *
10
+ * Push mode still works: pass `mode: 'push'` on a `worker:` mount (builds a
11
+ * doorbell client) or `doorbell: true` on `connectIslandWorker`, and serve
12
+ * Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy:
13
+ * require-corp.
14
+ */
15
+ import { callbackProp, connectIslandWorker as atollConnectIslandWorker, islandAppNameOf, mountIsland as atollMountIsland, } from '@atolljs/islands';
16
+ export { callbackProp };
17
+ const asWorkerEntry = (w) => w instanceof URL ? w : typeof w === 'function' ? w : () => w;
18
+ /** One island client = one dedicated worker. Islands mounted with `client:`
19
+ * share it; each `worker:` mount builds its own. */
20
+ export function connectIslandWorker({ worker, doorbell = false, ...options }) {
21
+ return atollConnectIslandWorker({ ...options, doorbell, worker: asWorkerEntry(worker) });
22
+ }
23
+ export function mountIsland(opts) {
24
+ const { worker, client, app, mode = 'poll', ...rest } = opts;
25
+ const name = islandAppNameOf(app);
26
+ if (app !== undefined && name === undefined) {
27
+ return Promise.reject(new Error('mountIsland: could not resolve an app name — pass the registry key ' +
28
+ 'or stamp the app with islandApp(name, app)'));
29
+ }
30
+ const base = { ...rest, app: name, mode };
31
+ return client !== undefined
32
+ ? atollMountIsland({ ...base, client })
33
+ : atollMountIsland({ ...base, worker: asWorkerEntry(worker) });
34
+ }
@@ -8,29 +8,16 @@
8
8
  * `callbackProp`, `islandApp`. Worker side (import in worker entries):
9
9
  * the `./worker` subpath re-exports `@atolljs/islands/worker` —
10
10
  * `definePolyWorker`/`defineMonoWorker`, `emit`, instance scope. The
11
- * preact-mvc adapter and `<Island/>` shell components live in
11
+ * PreactMVC adapter and `<Island/>` shell components live in
12
12
  * `@preact-mvc/atoll-island`.
13
13
  */
14
14
  export { islandApp, islandAppNameOf } from '@atolljs/islands';
15
15
  export type { IslandAppProps } from '@atolljs/islands';
16
- export {
17
- defineIslandContract,
18
- isIslandContract,
19
- withContract,
20
- contractOf,
21
- contractWorkerOf,
22
- } from '@atolljs/islands';
23
- export type {
24
- IslandContract,
25
- IslandContractEventHandler,
26
- IslandContractEvents,
27
- IslandContractProps,
28
- IslandWorkerOptions,
29
- } from '@atolljs/islands';
16
+ export { defineIslandContract, isIslandContract, withContract, contractOf, contractWorkerOf, } from '@atolljs/islands';
17
+ export type { IslandContract, IslandContractEventHandler, IslandContractEvents, IslandContractProps, IslandWorkerOptions, } from '@atolljs/islands';
30
18
  export type { EventPayload, Op, WireProps } from '@atolljs/islands';
31
19
  export { z } from '@atolljs/core';
32
20
  export type { Schema } from '@atolljs/core';
33
-
34
21
  export { mountIsland, connectIslandWorker, callbackProp } from './driver';
35
22
  export type { ConnectOptions, MountOptions, WorkerLike } from './driver';
36
23
  export type { IslandClient, IslandHandle, Mode } from './driver';
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `@preact-mvc/atoll` — the shell-facing facade over the real Atoll
3
+ * packages (`@atolljs/islands` + `@atolljs/core`). Worker islands render
4
+ * inside Web Workers against a proxy DOM; commits stream back as ops the
5
+ * driver replays onto real DOM.
6
+ *
7
+ * Shell side (this entry): `mountIsland`, `connectIslandWorker`,
8
+ * `callbackProp`, `islandApp`. Worker side (import in worker entries):
9
+ * the `./worker` subpath re-exports `@atolljs/islands/worker` —
10
+ * `definePolyWorker`/`defineMonoWorker`, `emit`, instance scope. The
11
+ * PreactMVC adapter and `<Island/>` shell components live in
12
+ * `@preact-mvc/atoll-island`.
13
+ */
14
+ export { islandApp, islandAppNameOf } from '@atolljs/islands';
15
+ export { defineIslandContract, isIslandContract, withContract, contractOf, contractWorkerOf, } from '@atolljs/islands';
16
+ export { z } from '@atolljs/core';
17
+ export { mountIsland, connectIslandWorker, callbackProp } from './driver';
@@ -5,20 +5,7 @@
5
5
  * import { definePolyWorker } from '@preact-mvc/atoll/worker';
6
6
  * export const worker = definePolyWorker({ apps: { ... } });
7
7
  */
8
- export {
9
- definePolyWorker,
10
- defineMonoWorker,
11
- islandApp,
12
- islandAppNameOf,
13
- emit,
14
- runInInstance,
15
- getActiveInstance,
16
- getLastActiveInstance,
17
- getLastTouchedInstance,
18
- setActiveInstance,
19
- installDomShim,
20
- ProxyElement,
21
- } from '@atolljs/islands/worker';
8
+ export { definePolyWorker, defineMonoWorker, islandApp, islandAppNameOf, emit, runInInstance, getActiveInstance, getLastActiveInstance, getLastTouchedInstance, setActiveInstance, installDomShim, ProxyElement, } from '@atolljs/islands/worker';
22
9
  /**
23
10
  * Nested-island surfaces: `mountIsland` is the ONE mount API on both
24
11
  * threads — a ProxyElement target (inside a worker-rendered tree) routes
@@ -30,45 +17,21 @@ export {
30
17
  * `new Worker` needs an engine that supports it — Chrome/Firefox/Node,
31
18
  * NOT Safari workers.
32
19
  */
33
- export {
34
- connectIslandWorker,
35
- mountIsland,
36
- callbackProp,
37
- } from './driver';
20
+ export { connectIslandWorker, mountIsland, callbackProp, } from './driver';
38
21
  export type { ConnectIslandWorkerConfig, MountIslandOptions } from '@atolljs/islands/worker';
39
- export {
40
- defineIslandContract,
41
- isIslandContract,
42
- withContract,
43
- contractOf,
44
- } from '@atolljs/islands/worker';
45
- export type {
46
- ImperativeIslandApp,
47
- IslandApp,
48
- IslandContract,
49
- PolyWorkerRegistry,
50
- ProxyDocument,
51
- RenderContext,
52
- RenderedHandle,
53
- RenderedIslandApp,
54
- } from '@atolljs/islands/worker';
22
+ export { defineIslandContract, isIslandContract, withContract, contractOf, } from '@atolljs/islands/worker';
23
+ export type { ImperativeIslandApp, IslandApp, IslandContract, PolyWorkerRegistry, ProxyDocument, RenderContext, RenderedHandle, RenderedIslandApp, } from '@atolljs/islands/worker';
55
24
  export type { EventPayload, Op, WireProps } from '@atolljs/islands/worker';
56
25
  export type { IslandWorkerDefinition } from '@atolljs/islands';
57
-
58
- import { setActiveInstance } from '@atolljs/islands/worker';
59
26
  import type { IslandWorkerDefinition } from '@atolljs/islands';
60
-
61
27
  /** What `definePolyWorker`/`defineMonoWorker` return — the worker def type
62
28
  * island clients type-check against. */
63
29
  export type IslandWorkerDef = IslandWorkerDefinition;
64
-
65
30
  /**
66
31
  * Enter `key`'s instance scope, returning the previous key for restore —
67
32
  * a named pair around `setActiveInstance` (which returns the prev itself),
68
- * used by the preact-mvc adapter's out-of-task render scoping.
33
+ * used by the PreactMVC adapter's out-of-task render scoping.
69
34
  */
70
- export const enterInstance = (key: string): string => setActiveInstance(key);
35
+ export declare const enterInstance: (key: string) => string;
71
36
  /** Restore the scope `enterInstance` returned (`''` when there was none). */
72
- export const exitInstance = (prev: string | null): void => {
73
- setActiveInstance(prev ?? '');
74
- };
37
+ export declare const exitInstance: (prev: string | null) => void;
package/dist/worker.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * `@preact-mvc/atoll/worker` — the worker-side entry, re-exported from
3
+ * `@atolljs/islands/worker`. Import in worker entries only:
4
+ *
5
+ * import { definePolyWorker } from '@preact-mvc/atoll/worker';
6
+ * export const worker = definePolyWorker({ apps: { ... } });
7
+ */
8
+ export { definePolyWorker, defineMonoWorker, islandApp, islandAppNameOf, emit, runInInstance, getActiveInstance, getLastActiveInstance, getLastTouchedInstance, setActiveInstance, installDomShim, ProxyElement, } from '@atolljs/islands/worker';
9
+ /**
10
+ * Nested-island surfaces: `mountIsland` is the ONE mount API on both
11
+ * threads — a ProxyElement target (inside a worker-rendered tree) routes
12
+ * to the registered sub-mounter and spawns a real sub-worker; a real
13
+ * element drives the main-thread applier. `connectIslandWorker` is
14
+ * thread-agnostic and spawns from whichever thread calls it. Re-exported
15
+ * through our driver facade so the same worker-option normalization and
16
+ * message-only defaults apply on nested mounts. Platform note: nested
17
+ * `new Worker` needs an engine that supports it — Chrome/Firefox/Node,
18
+ * NOT Safari workers.
19
+ */
20
+ export { connectIslandWorker, mountIsland, callbackProp, } from './driver';
21
+ export { defineIslandContract, isIslandContract, withContract, contractOf, } from '@atolljs/islands/worker';
22
+ import { setActiveInstance } from '@atolljs/islands/worker';
23
+ /**
24
+ * Enter `key`'s instance scope, returning the previous key for restore —
25
+ * a named pair around `setActiveInstance` (which returns the prev itself),
26
+ * used by the PreactMVC adapter's out-of-task render scoping.
27
+ */
28
+ export const enterInstance = (key) => setActiveInstance(key);
29
+ /** Restore the scope `enterInstance` returned (`''` when there was none). */
30
+ export const exitInstance = (prev) => {
31
+ setActiveInstance(prev ?? '');
32
+ };
package/package.json CHANGED
@@ -1,21 +1,27 @@
1
1
  {
2
2
  "name": "@preact-mvc/atoll",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Framework-free worker-rendered islands: op protocol, proxy DOM, worker runtime, main-thread driver",
5
5
  "type": "module",
6
+ "sideEffects": false,
6
7
  "exports": {
7
- ".": "./src/index.ts",
8
- "./worker": "./src/worker.ts",
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./worker": {
13
+ "types": "./dist/worker.d.ts",
14
+ "default": "./dist/worker.js"
15
+ },
9
16
  "./package.json": "./package.json",
10
- "./*": "./src/*"
17
+ "./*": "./dist/*"
11
18
  },
12
19
  "files": [
13
- "src",
14
- "!src/**/*.test.ts",
15
- "!src/**/*.test.tsx"
20
+ "dist"
16
21
  ],
17
22
  "scripts": {
18
- "typecheck": "tsc --noEmit"
23
+ "typecheck": "tsc --noEmit",
24
+ "build": "tsc -p tsconfig.build.json"
19
25
  },
20
26
  "publishConfig": {
21
27
  "access": "public",
@@ -30,5 +36,6 @@
30
36
  "url": "https://github.com/jwhenry3/preact-mvc",
31
37
  "directory": "packages/atoll"
32
38
  },
33
- "license": "MIT"
39
+ "license": "MIT",
40
+ "types": "./dist/index.d.ts"
34
41
  }
package/src/driver.ts DELETED
@@ -1,123 +0,0 @@
1
- /**
2
- * `@preact-mvc/atoll` shell surface — a thin facade over `@atolljs/islands`
3
- * (docs/atoll/islands.md). The op protocol, proxy DOM, instance lifecycle,
4
- * and op-replay driver are the real package now; this file only normalizes
5
- * the worker option (an already-created WorkerLike counts as an entry, the
6
- * real package wants a bundler-detectable factory or URL) and defaults the
7
- * transport to message-only so mounts work without COOP/COEP headers —
8
- * GitHub Pages can't serve them.
9
- *
10
- * Push mode still works: pass `mode: 'push'` on a `worker:` mount (builds a
11
- * doorbell client) or `doorbell: true` on `connectIslandWorker`, and serve
12
- * Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy:
13
- * require-corp.
14
- */
15
- import {
16
- callbackProp,
17
- connectIslandWorker as atollConnectIslandWorker,
18
- islandAppNameOf,
19
- mountIsland as atollMountIsland,
20
- } from '@atolljs/islands';
21
- import type {
22
- IslandClient,
23
- IslandHandle,
24
- IslandWorkerOptions,
25
- Mode,
26
- Op,
27
- } from '@atolljs/islands';
28
-
29
- export { callbackProp };
30
- export type { IslandClient, IslandHandle, Mode, Op };
31
-
32
- /**
33
- * What a `worker:` option accepts: a bundler-detectable factory
34
- * `() => new Worker(new URL(...))`, a URL, or an already-spawned worker
35
- * (test doubles like `InProcessWorker` count — the real `Worker` type would
36
- * reject them, so the surface is structural).
37
- */
38
- export type WorkerLike = Pick<
39
- Worker,
40
- 'postMessage' | 'addEventListener' | 'removeEventListener' | 'terminate'
41
- >;
42
-
43
- const asWorkerEntry = (
44
- w: WorkerLike | (() => WorkerLike) | URL,
45
- ): (() => Worker) | URL =>
46
- w instanceof URL ? w : typeof w === 'function' ? (w as () => Worker) : () => w as Worker;
47
-
48
- export interface ConnectOptions extends IslandWorkerOptions {
49
- /** Bundler-detectable factory / URL, or an already-spawned worker. */
50
- worker: WorkerLike | (() => WorkerLike) | URL;
51
- /**
52
- * Shared-memory doorbell for push-mode flush — requires cross-origin
53
- * isolation. Default false (message-only): mounts fall back to the 50ms
54
- * poll, which needs no special headers.
55
- */
56
- doorbell?: boolean;
57
- /**
58
- * Keep the worker thread resident (but idle) when its last island
59
- * destroys: the instance still unmounts — dispose hooks run, ops stop —
60
- * but the thread's module graph and worker-side caches survive, so the
61
- * next mount on this client is a warm start. Explicit `client.terminate()`
62
- * still kills it.
63
- */
64
- keepAlive?: boolean;
65
- }
66
-
67
- /** One island client = one dedicated worker. Islands mounted with `client:`
68
- * share it; each `worker:` mount builds its own. */
69
- export function connectIslandWorker({
70
- worker,
71
- doorbell = false,
72
- ...options
73
- }: ConnectOptions): IslandClient {
74
- return atollConnectIslandWorker({ ...options, doorbell, worker: asWorkerEntry(worker) });
75
- }
76
-
77
- export interface MountOptions extends IslandWorkerOptions {
78
- /** Container the island's ops replay into. */
79
- el: HTMLElement;
80
- /**
81
- * Which app to mount: the `apps` registry key, a stamped app
82
- * (`islandApp`/`viewIsland` result), or a contract. Resolved through
83
- * `islandAppNameOf` — bare components fall back to the function name.
84
- */
85
- app?: unknown;
86
- props?: Record<string, unknown>;
87
- /** Island → shell channel: receives every worker-side `emit(name, payload)`. */
88
- onEvent?: (name: string, payload: unknown) => void;
89
- /** `data-atoll-slot` transclusion holes — shell mounts real DOM inside. */
90
- slots?: Record<string, (el: HTMLElement | null) => void>;
91
- onActivity?: () => void;
92
- onOps?: (ops: readonly Op[], elapsedMs: number) => void;
93
- /**
94
- * 'push' uses the doorbell SAB (cross-origin isolation required for
95
- * `worker:` mounts); 'poll' (the default here) needs none.
96
- */
97
- mode?: Mode;
98
- /** Devtools renderer tag ('preact-mvc'); the adapter sets it. */
99
- framework?: string;
100
- mountTimeout?: number;
101
- /** This mount's destroy() leaves the client resident-but-idle. */
102
- keepAlive?: boolean;
103
- /** A shared `connectIslandWorker` client, OR an entry this mount owns. */
104
- client?: IslandClient;
105
- worker?: WorkerLike | (() => WorkerLike) | URL;
106
- }
107
-
108
- export function mountIsland(opts: MountOptions): Promise<IslandHandle> {
109
- const { worker, client, app, mode = 'poll', ...rest } = opts;
110
- const name = islandAppNameOf(app);
111
- if (app !== undefined && name === undefined) {
112
- return Promise.reject(
113
- new Error(
114
- 'mountIsland: could not resolve an app name — pass the registry key ' +
115
- 'or stamp the app with islandApp(name, app)',
116
- ),
117
- );
118
- }
119
- const base = { ...rest, app: name, mode };
120
- return client !== undefined
121
- ? atollMountIsland({ ...base, client })
122
- : atollMountIsland({ ...base, worker: asWorkerEntry(worker!) });
123
- }