@swiftbrowser/native 0.15.0 → 0.16.0

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 CHANGED
@@ -126,6 +126,16 @@ worker. Drawn in a page (`site`), `createWorker` returns the page's own
126
126
  is the same in all three places. The iOS app's `WebAssembly` is the engine's
127
127
  interpreter (a third-party app has no JIT), and SIMD in it needs iOS 26.2.
128
128
 
129
+ ```ts
130
+ const worker = createWorker('satoru', { engine: 'webview' });
131
+ ```
132
+
133
+ `engine: 'webview'` runs the same bundle in a hidden `WKWebView` instead,
134
+ whose web content process does compile JavaScript and WebAssembly with its
135
+ JIT: much faster for heavy WebAssembly, for a process and a web
136
+ view's memory. Its `fetch` still goes through the app's `URLSession`, with
137
+ the app's cookies; a page's own `Worker` ignores the option.
138
+
129
139
  ## URLs the app is opened with
130
140
 
131
141
  ```ts
package/dist/bridge.d.ts CHANGED
@@ -27,14 +27,26 @@ export interface NativeBridge {
27
27
  locale(): string;
28
28
  /** The process's launch arguments (`-screen list` from an Xcode scheme or `simctl launch`). */
29
29
  launchArguments?(): string[];
30
- /** Starts worker `id` from `<name>.worker.js`; returns an error message, or nothing. Its messages arrive at `__sbWorkerMessage(id, text)`, its errors at `__sbWorkerError(id, message)`. */
31
- workerStart?(id: number, name: string): string | null | undefined;
30
+ /**
31
+ * Starts worker `id` from `<name>.worker.js` in `engine` (`'context'`
32
+ * when absent; hosts before 0.16 take no engine); returns an error
33
+ * message, or nothing. Its messages arrive at `__sbWorkerMessage(id, text)`,
34
+ * its errors at `__sbWorkerError(id, message)`.
35
+ */
36
+ workerStart?(id: number, name: string, engine?: WorkerEngine): string | null | undefined;
32
37
  /** Delivers an encoded message (worker.ts) to worker `id`'s `__sbWorkerReceive(text)`. */
33
38
  workerPost?(id: number, text: string): void;
34
39
  workerTerminate?(id: number): void;
35
40
  /** In a worker's context: an encoded message to the app's context. */
36
41
  workerPostMessage?(text: string): void;
37
42
  }
43
+ /**
44
+ * Where a native worker runs: `'context'`, a JavaScriptCore context on a
45
+ * thread of the app's; `'webview'`, a hidden `WKWebView`, whose web content
46
+ * process has WebKit's JIT (an app's own JavaScriptCore has none on iOS),
47
+ * for heavy WebAssembly.
48
+ */
49
+ export type WorkerEngine = 'context' | 'webview';
38
50
  /** The app's launch arguments, or none outside the native app. */
39
51
  export declare function launchArguments(): string[];
40
52
  export interface NativeFetchRequest {
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,+BAA+B;IAC/B,GAAG,IAAI,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9D,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAAC;IAC9D,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACvC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,WAAW,IAAI,MAAM,EAAE,CAAC;IACxB,YAAY,IAAI,IAAI,CAAC;IACrB,sCAAsC;IACtC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,gDAAgD;IAChD,MAAM,IAAI,MAAM,CAAC;IACjB,+FAA+F;IAC/F,eAAe,CAAC,IAAI,MAAM,EAAE,CAAC;IAM7B,4LAA4L;IAC5L,WAAW,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClE,0FAA0F;IAC1F,UAAU,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,eAAe,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,sEAAsE;IACtE,iBAAiB,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED,kEAAkE;AAClE,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAG1C;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,uBAAuB;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,yFAAyF;AACzF,wBAAgB,YAAY,CAAC,CAAC,GAAE,OAAO,UAAuB,GAAG,YAAY,GAAG,SAAS,CAExF"}
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,+BAA+B;IAC/B,GAAG,IAAI,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9D,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAAC;IAC9D,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACvC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,WAAW,IAAI,MAAM,EAAE,CAAC;IACxB,YAAY,IAAI,IAAI,CAAC;IACrB,sCAAsC;IACtC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,gDAAgD;IAChD,MAAM,IAAI,MAAM,CAAC;IACjB,+FAA+F;IAC/F,eAAe,CAAC,IAAI,MAAM,EAAE,CAAC;IAM7B;;;;;OAKG;IACH,WAAW,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzF,0FAA0F;IAC1F,UAAU,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,eAAe,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,sEAAsE;IACtE,iBAAiB,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,CAAC;AAEjD,kEAAkE;AAClE,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAG1C;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,uBAAuB;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,yFAAyF;AACzF,wBAAgB,YAAY,CAAC,CAAC,GAAE,OAAO,UAAuB,GAAG,YAAY,GAAG,SAAS,CAExF"}
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AA2CA,kEAAkE;AAClE,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,OAAO,MAAM,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,CAAC;AAC3C,CAAC;AAoBD,yFAAyF;AACzF,MAAM,UAAU,YAAY,CAAC,IAAuB,UAAU;IAC5D,OAAQ,CAA8C,CAAC,UAAU,CAAC;AACpE,CAAC"}
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAwDA,kEAAkE;AAClE,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,OAAO,MAAM,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,CAAC;AAC3C,CAAC;AAoBD,yFAAyF;AACzF,MAAM,UAAU,YAAY,CAAC,IAAuB,UAAU;IAC5D,OAAQ,CAA8C,CAAC,UAAU,CAAC;AACpE,CAAC"}
package/dist/index.d.ts CHANGED
@@ -13,10 +13,10 @@
13
13
  export { run, type RunOptions, type Running } from './run';
14
14
  export { Native, type NativeProps } from './native';
15
15
  export { installRuntime, type InstallOptions } from './runtime';
16
- export { nativeBridge, launchArguments, type NativeBridge, type NativeFetchRequest, type NativeFetchResult } from './bridge';
16
+ export { nativeBridge, launchArguments, type NativeBridge, type NativeFetchRequest, type NativeFetchResult, type WorkerEngine } from './bridge';
17
17
  export { SimpleHeaders, SimpleRequest, SimpleResponse, SimpleAbortController, SimpleAbortSignal, createFetch } from './fetch';
18
18
  export { SimpleURL, SimpleURLSearchParams } from './url';
19
19
  export { SimpleTextEncoder, SimpleTextDecoder, base64Encode, base64Decode, utf8Encode, utf8Decode } from './encoding';
20
- export { createWorker, NativeWorker, encodeMessage, decodeMessage, workerName, type WorkerLike, type WorkerMessageEvent, type WorkerErrorEvent } from './worker';
20
+ export { createWorker, NativeWorker, encodeMessage, decodeMessage, workerName, type NativeWorkerOptions, type WorkerLike, type WorkerMessageEvent, type WorkerErrorEvent } from './worker';
21
21
  export { onOpenURL } from './openURL';
22
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,GAAG,EAAE,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7H,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC9H,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACtH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjK,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,GAAG,EAAE,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAChJ,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC9H,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACtH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,KAAK,mBAAmB,EAAE,KAAK,UAAU,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC3L,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,GAAG,EAAiC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAoB,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,cAAc,EAAuB,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAsE,MAAM,UAAU,CAAC;AAC7H,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC9H,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACtH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAmE,MAAM,UAAU,CAAC;AACjK,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,GAAG,EAAiC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAoB,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,cAAc,EAAuB,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAyF,MAAM,UAAU,CAAC;AAChJ,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC9H,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACtH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAA6F,MAAM,UAAU,CAAC;AAC3L,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
package/dist/worker.d.ts CHANGED
@@ -16,8 +16,13 @@
16
16
  * worker.onmessage = (event) => console.log(event.data);
17
17
  * worker.postMessage({ draw: 'something' });
18
18
  * ```
19
+ *
20
+ * `createWorker(name, { engine: 'webview' })` runs the same bundle in a
21
+ * hidden `WKWebView` instead (WebViewWorkerHost.swift): WebKit's web
22
+ * content process compiles with its JIT, which an app's own JavaScriptCore
23
+ * may not on iOS, so heavy WebAssembly runs much faster there.
19
24
  */
20
- import { type NativeBridge } from './bridge';
25
+ import { type NativeBridge, type WorkerEngine } from './bridge';
21
26
  /** What `Worker` and a worker's `self` have in common, as an app uses them. */
22
27
  export interface WorkerLike {
23
28
  postMessage(data: unknown, transfer?: unknown[]): void;
@@ -45,6 +50,14 @@ export interface WorkerErrorEvent {
45
50
  export declare function encodeMessage(data: unknown): string;
46
51
  /** The value `encodeMessage` encoded. */
47
52
  export declare function decodeMessage(text: string): unknown;
53
+ /** How a worker is started. */
54
+ export interface NativeWorkerOptions {
55
+ /** Where it runs in the native app (bridge.ts): `'context'` (the default) or `'webview'`. A page's own `Worker` ignores it. */
56
+ engine?: WorkerEngine;
57
+ /** A page's `Worker` options, accepted and ignored: a bundle is one script. */
58
+ type?: 'classic' | 'module';
59
+ name?: string;
60
+ }
48
61
  type Listener<E> = (event: E) => void;
49
62
  /** `Worker` over the bridge, in the app's context. */
50
63
  export declare class NativeWorker implements WorkerLike {
@@ -56,7 +69,7 @@ export declare class NativeWorker implements WorkerLike {
56
69
  /** `name` is the bundle's: `<name>.worker.js` next to app.js. A URL's last path segment serves as the name (`render.worker.js` → `render`). */
57
70
  constructor(name: string | {
58
71
  href: string;
59
- } | URL, native?: NativeBridge | undefined);
72
+ } | URL, options?: NativeWorkerOptions, native?: NativeBridge | undefined);
60
73
  postMessage(data: unknown): void;
61
74
  terminate(): void;
62
75
  addEventListener(type: 'message', listener: Listener<WorkerMessageEvent>): void;
@@ -74,9 +87,9 @@ export declare function workerName(name: string | {
74
87
  /**
75
88
  * A worker from the bundle `<name>.worker.js`: the page's own `Worker` when
76
89
  * the app is drawn in a page (the bundle published with the site), else the
77
- * host's over the bridge.
90
+ * host's over the bridge, in `options.engine`.
78
91
  */
79
- export declare function createWorker(name: string): WorkerLike;
92
+ export declare function createWorker(name: string, options?: NativeWorkerOptions): WorkerLike;
80
93
  /**
81
94
  * A worker's own globals over its bridge: `self`, `postMessage`, `onmessage`
82
95
  * and `onerror` as properties the script assigns, `addEventListener`,
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"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"}
package/dist/worker.js CHANGED
@@ -16,6 +16,11 @@
16
16
  * worker.onmessage = (event) => console.log(event.data);
17
17
  * worker.postMessage({ draw: 'something' });
18
18
  * ```
19
+ *
20
+ * `createWorker(name, { engine: 'webview' })` runs the same bundle in a
21
+ * hidden `WKWebView` instead (WebViewWorkerHost.swift): WebKit's web
22
+ * content process compiles with its JIT, which an app's own JavaScriptCore
23
+ * may not on iOS, so heavy WebAssembly runs much faster there.
19
24
  */
20
25
  import { nativeBridge } from './bridge';
21
26
  import { base64Decode, base64Encode } from './encoding';
@@ -91,14 +96,14 @@ export class NativeWorker {
91
96
  onmessage = null;
92
97
  onerror = null;
93
98
  /** `name` is the bundle's: `<name>.worker.js` next to app.js. A URL's last path segment serves as the name (`render.worker.js` → `render`). */
94
- constructor(name, native = nativeBridge()) {
99
+ constructor(name, options = {}, native = nativeBridge()) {
95
100
  if (!native?.workerStart || !native.workerPost || !native.workerTerminate) {
96
101
  throw new Error('Worker: this host has no workers (SwiftBrowser Native 0.13 or later)');
97
102
  }
98
103
  this.#native = native;
99
104
  this.#id = NativeWorker.nextId++;
100
105
  NativeWorker.live.set(this.#id, this);
101
- const failure = native.workerStart(this.#id, workerName(name));
106
+ const failure = native.workerStart(this.#id, workerName(name), options.engine);
102
107
  if (failure) {
103
108
  NativeWorker.live.delete(this.#id);
104
109
  throw new Error(failure);
@@ -158,15 +163,15 @@ export function workerName(name) {
158
163
  /**
159
164
  * A worker from the bundle `<name>.worker.js`: the page's own `Worker` when
160
165
  * the app is drawn in a page (the bundle published with the site), else the
161
- * host's over the bridge.
166
+ * host's over the bridge, in `options.engine`.
162
167
  */
163
- export function createWorker(name) {
168
+ export function createWorker(name, options = {}) {
164
169
  const base = typeof __SB_WORKER_BASE__ === 'string' ? __SB_WORKER_BASE__ : undefined;
165
170
  const PageWorker = globalThis.Worker;
166
171
  if (typeof PageWorker === 'function' && base !== undefined)
167
172
  return new PageWorker(`${base}${workerName(name)}.worker.js`);
168
173
  if (nativeBridge()?.workerStart)
169
- return new NativeWorker(name);
174
+ return new NativeWorker(name, options);
170
175
  if (typeof PageWorker === 'function')
171
176
  return new PageWorker(`${workerName(name)}.worker.js`);
172
177
  throw new Error(`createWorker: no host for "${name}" (not in a SwiftBrowser Native app or a page)`);
@@ -1 +1 @@
1
- {"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,YAAY,EAAwC,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA0BxD,iBAAiB;AAEjB,MAAM,YAAY,GAAG;IACnB,UAAU;IACV,iBAAiB;IACjB,SAAS;IACT,WAAW;IACX,UAAU;IACV,WAAW;IACX,UAAU;IACV,YAAY;IACZ,YAAY;CACJ,CAAC;AAGX;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAAa;IACzC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,KAAc,EAAE,EAAE;QAC/E,IAAI,KAAK,YAAY,WAAW;YAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;QACnH,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAI,KAAK,CAAC,WAAiC,CAAC,IAAI,CAAC;YAC3D,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;YAC/E,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,IAAI,IAAI,IAAI,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;QACxG,CAAC;QACD,IAAI,KAAK,YAAY,KAAK;YAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,IAAI,EAAE,EAAE,CAAC;QAC1H,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,KAAc,EAAE,EAAE;QAC/C,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvC,MAAM,MAAM,GAAG,KAAgC,CAAC;YAChD,IAAI,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,QAAQ,EAAE,CAAC;gBAC3C,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;gBAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;gBAC/B,IAAI,IAAI,KAAK,aAAa;oBAAE,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;gBAC7G,MAAM,WAAW,GAAG,YAAY,CAAE,IAAuB,IAAI,YAAY,CAAC,CAAC,CAAE,IAAuB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;gBACrH,+DAA+D;gBAC/D,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAgB,CAAC;gBACxG,OAAO,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;YACjC,CAAC;YACD,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACjE,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAA+D,CAAC;gBAC9F,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;gBAC5C,IAAI,IAAI,CAAC,IAAI;oBAAE,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;gBACtC,IAAI,IAAI,CAAC,KAAK;oBAAE,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;gBACzC,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAeD,sDAAsD;AACtD,MAAM,OAAO,YAAY;IACf,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAClB,MAAM,CAAU,IAAI,GAAG,IAAI,GAAG,EAAwB,CAAC;IACtD,GAAG,CAAS;IACZ,OAAO,CAAe;IAC/B,WAAW,GAAG,KAAK,CAAC;IACX,iBAAiB,GAAG,IAAI,GAAG,EAAgC,CAAC;IAC5D,eAAe,GAAG,IAAI,GAAG,EAA8B,CAAC;IACjE,SAAS,GAAwC,IAAI,CAAC;IACtD,OAAO,GAAsC,IAAI,CAAC;IAElD,+IAA+I;IAC/I,YAAY,IAAqC,EAAE,UAA+B,EAAE,EAAE,SAAmC,YAAY,EAAE;QACrI,IAAI,CAAC,MAAM,EAAE,WAAW,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YAC1E,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;QAC1F,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC;QACjC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/E,IAAI,OAAO,EAAE,CAAC;YACZ,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,WAAW,CAAC,IAAa;QACvB,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO;QAC7B,IAAI,CAAC,OAAO,CAAC,UAAW,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,SAAS;QACP,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO;QAC7B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO,CAAC,eAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1C,CAAC;IAID,gBAAgB,CAAC,IAAyB,EAAE,QAAyB;QACnE,IAAI,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,QAAwC,CAAC,CAAC;;YACxF,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAsC,CAAC,CAAC;IACxE,CAAC;IAED,mBAAmB,CAAC,IAAyB,EAAE,QAAyB;QACtE,IAAI,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,QAAwC,CAAC,CAAC;;YAC3F,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAsC,CAAC,CAAC;IAC3E,CAAC;IAED,kDAAkD;IAClD,MAAM,CAAC,OAAO,CAAC,EAAU,EAAE,IAAY;QACrC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,KAAK,GAAuB,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACjF,MAAM,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC;QAC1B,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,iBAAiB;YAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACnE,CAAC;IAED,wFAAwF;IACxF,MAAM,CAAC,IAAI,CAAC,EAAU,EAAE,OAAe;QACrC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,KAAK,GAAqB,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;QAC3D,MAAM,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;QACxB,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,eAAe;YAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACjE,CAAC;;AAGH,mGAAmG;AACnG,MAAM,UAAU,UAAU,CAAC,IAAqC;IAC9D,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IACzD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC;IAC3C,OAAO,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AACrE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,UAA+B,EAAE;IAC1E,MAAM,IAAI,GAAG,OAAO,kBAAkB,KAAK,QAAQ,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC;IACrF,MAAM,UAAU,GAAI,UAA2D,CAAC,MAAM,CAAC;IACvF,IAAI,OAAO,UAAU,KAAK,UAAU,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,UAAU,CAAC,GAAG,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC1H,IAAI,YAAY,EAAE,EAAE,WAAW;QAAE,OAAO,IAAI,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxE,IAAI,OAAO,UAAU,KAAK,UAAU;QAAE,OAAO,IAAI,UAAU,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC7F,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,gDAAgD,CAAC,CAAC;AACtG,CAAC;AAED,0BAA0B;AAE1B;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAoB,EAAE,MAA+B;IACtF,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,KAAc,EAAQ,EAAE;QACpD,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QACtG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAgC,CAAC;IACjE,MAAM,cAAc,GAAG,IAAI,GAAG,EAA8B,CAAC;IAC7D,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvB,MAAM,CAAC,aAAa,EAAE,CAAC,IAAa,EAAE,EAAE,CAAC,MAAM,CAAC,iBAAkB,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzF,MAAM,CAAC,kBAAkB,EAAE,CAAC,IAAY,EAAE,QAAyB,EAAE,EAAE;QACrE,IAAI,IAAI,KAAK,SAAS;YAAE,gBAAgB,CAAC,GAAG,CAAC,QAAwC,CAAC,CAAC;aAClF,IAAI,IAAI,KAAK,OAAO;YAAE,cAAc,CAAC,GAAG,CAAC,QAAsC,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,qBAAqB,EAAE,CAAC,IAAY,EAAE,QAAyB,EAAE,EAAE;QACxE,IAAI,IAAI,KAAK,SAAS;YAAE,gBAAgB,CAAC,MAAM,CAAC,QAAwC,CAAC,CAAC;aACrF,IAAI,IAAI,KAAK,OAAO;YAAE,cAAc,CAAC,MAAM,CAAC,QAAsC,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,mDAAmD,CAAC,CAAC,CAAC;IAC/F,MAAM,CAAC,mBAAmB,EAAE,CAAC,IAAY,EAAE,EAAE;QAC3C,MAAM,KAAK,GAAuB,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACjF,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;QACpC,IAAI,OAAO,OAAO,KAAK,UAAU;YAAG,OAAwC,CAAC,KAAK,CAAC,CAAC;QACpF,KAAK,MAAM,QAAQ,IAAI,gBAAgB;YAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IACH,OAAO,SAAS,CAAC;AACnB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swiftbrowser/native",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "type": "module",
5
5
  "description": "Run a @swiftbrowser/react app natively: the runtime a JavaScriptCore-hosted app needs (timers, console, fetch and the other web globals over the SwiftBrowser Native bridge), the `run` entry that renders into the native SwiftUI renderer, and the bundler that builds app.js for the Xcode target.",
6
6
  "repository": {
@@ -59,8 +59,8 @@
59
59
  },
60
60
  "dependencies": {
61
61
  "@babel/core": "^7.29.7",
62
- "@swiftbrowser/react": "0.15.0",
63
- "@swiftbrowser/web": "0.15.0",
62
+ "@swiftbrowser/react": "0.16.0",
63
+ "@swiftbrowser/web": "0.16.0",
64
64
  "esbuild": "^0.28.2",
65
65
  "react-refresh": "^0.17.0"
66
66
  },
package/src/bridge.ts CHANGED
@@ -32,8 +32,13 @@ export interface NativeBridge {
32
32
  // `swiftbrowser-native build --worker <name>=<entry>` wrote next to app.js
33
33
  // (`<name>.worker.js`). The app's context has the first three; a worker's
34
34
  // context has the last and no `applyOps`.
35
- /** Starts worker `id` from `<name>.worker.js`; returns an error message, or nothing. Its messages arrive at `__sbWorkerMessage(id, text)`, its errors at `__sbWorkerError(id, message)`. */
36
- workerStart?(id: number, name: string): string | null | undefined;
35
+ /**
36
+ * Starts worker `id` from `<name>.worker.js` in `engine` (`'context'`
37
+ * when absent; hosts before 0.16 take no engine); returns an error
38
+ * message, or nothing. Its messages arrive at `__sbWorkerMessage(id, text)`,
39
+ * its errors at `__sbWorkerError(id, message)`.
40
+ */
41
+ workerStart?(id: number, name: string, engine?: WorkerEngine): string | null | undefined;
37
42
  /** Delivers an encoded message (worker.ts) to worker `id`'s `__sbWorkerReceive(text)`. */
38
43
  workerPost?(id: number, text: string): void;
39
44
  workerTerminate?(id: number): void;
@@ -41,6 +46,14 @@ export interface NativeBridge {
41
46
  workerPostMessage?(text: string): void;
42
47
  }
43
48
 
49
+ /**
50
+ * Where a native worker runs: `'context'`, a JavaScriptCore context on a
51
+ * thread of the app's; `'webview'`, a hidden `WKWebView`, whose web content
52
+ * process has WebKit's JIT (an app's own JavaScriptCore has none on iOS),
53
+ * for heavy WebAssembly.
54
+ */
55
+ export type WorkerEngine = 'context' | 'webview';
56
+
44
57
  /** The app's launch arguments, or none outside the native app. */
45
58
  export function launchArguments(): string[] {
46
59
  const native = nativeBridge();
package/src/index.ts CHANGED
@@ -14,9 +14,9 @@
14
14
  export { run, type RunOptions, type Running } from './run';
15
15
  export { Native, type NativeProps } from './native';
16
16
  export { installRuntime, type InstallOptions } from './runtime';
17
- export { nativeBridge, launchArguments, type NativeBridge, type NativeFetchRequest, type NativeFetchResult } from './bridge';
17
+ export { nativeBridge, launchArguments, type NativeBridge, type NativeFetchRequest, type NativeFetchResult, type WorkerEngine } from './bridge';
18
18
  export { SimpleHeaders, SimpleRequest, SimpleResponse, SimpleAbortController, SimpleAbortSignal, createFetch } from './fetch';
19
19
  export { SimpleURL, SimpleURLSearchParams } from './url';
20
20
  export { SimpleTextEncoder, SimpleTextDecoder, base64Encode, base64Decode, utf8Encode, utf8Decode } from './encoding';
21
- export { createWorker, NativeWorker, encodeMessage, decodeMessage, workerName, type WorkerLike, type WorkerMessageEvent, type WorkerErrorEvent } from './worker';
21
+ export { createWorker, NativeWorker, encodeMessage, decodeMessage, workerName, type NativeWorkerOptions, type WorkerLike, type WorkerMessageEvent, type WorkerErrorEvent } from './worker';
22
22
  export { onOpenURL } from './openURL';
package/src/worker.ts CHANGED
@@ -16,9 +16,14 @@
16
16
  * worker.onmessage = (event) => console.log(event.data);
17
17
  * worker.postMessage({ draw: 'something' });
18
18
  * ```
19
+ *
20
+ * `createWorker(name, { engine: 'webview' })` runs the same bundle in a
21
+ * hidden `WKWebView` instead (WebViewWorkerHost.swift): WebKit's web
22
+ * content process compiles with its JIT, which an app's own JavaScriptCore
23
+ * may not on iOS, so heavy WebAssembly runs much faster there.
19
24
  */
20
25
 
21
- import { nativeBridge, type NativeBridge } from './bridge';
26
+ import { nativeBridge, type NativeBridge, type WorkerEngine } from './bridge';
22
27
  import { base64Decode, base64Encode } from './encoding';
23
28
 
24
29
  /** The site's published path for worker bundles (`/native/bundle/App/`), defined by `swiftbrowser-native site`; undefined in an Xcode bundle. */
@@ -107,6 +112,15 @@ export function decodeMessage(text: string): unknown {
107
112
 
108
113
  // MARK: The app's side
109
114
 
115
+ /** How a worker is started. */
116
+ export interface NativeWorkerOptions {
117
+ /** Where it runs in the native app (bridge.ts): `'context'` (the default) or `'webview'`. A page's own `Worker` ignores it. */
118
+ engine?: WorkerEngine;
119
+ /** A page's `Worker` options, accepted and ignored: a bundle is one script. */
120
+ type?: 'classic' | 'module';
121
+ name?: string;
122
+ }
123
+
110
124
  type Listener<E> = (event: E) => void;
111
125
 
112
126
  /** `Worker` over the bridge, in the app's context. */
@@ -122,14 +136,14 @@ export class NativeWorker implements WorkerLike {
122
136
  onerror: Listener<WorkerErrorEvent> | null = null;
123
137
 
124
138
  /** `name` is the bundle's: `<name>.worker.js` next to app.js. A URL's last path segment serves as the name (`render.worker.js` → `render`). */
125
- constructor(name: string | { href: string } | URL, native: NativeBridge | undefined = nativeBridge()) {
139
+ constructor(name: string | { href: string } | URL, options: NativeWorkerOptions = {}, native: NativeBridge | undefined = nativeBridge()) {
126
140
  if (!native?.workerStart || !native.workerPost || !native.workerTerminate) {
127
141
  throw new Error('Worker: this host has no workers (SwiftBrowser Native 0.13 or later)');
128
142
  }
129
143
  this.#native = native;
130
144
  this.#id = NativeWorker.nextId++;
131
145
  NativeWorker.live.set(this.#id, this);
132
- const failure = native.workerStart(this.#id, workerName(name));
146
+ const failure = native.workerStart(this.#id, workerName(name), options.engine);
133
147
  if (failure) {
134
148
  NativeWorker.live.delete(this.#id);
135
149
  throw new Error(failure);
@@ -189,13 +203,13 @@ export function workerName(name: string | { href: string } | URL): string {
189
203
  /**
190
204
  * A worker from the bundle `<name>.worker.js`: the page's own `Worker` when
191
205
  * the app is drawn in a page (the bundle published with the site), else the
192
- * host's over the bridge.
206
+ * host's over the bridge, in `options.engine`.
193
207
  */
194
- export function createWorker(name: string): WorkerLike {
208
+ export function createWorker(name: string, options: NativeWorkerOptions = {}): WorkerLike {
195
209
  const base = typeof __SB_WORKER_BASE__ === 'string' ? __SB_WORKER_BASE__ : undefined;
196
210
  const PageWorker = (globalThis as { Worker?: new (url: string) => WorkerLike }).Worker;
197
211
  if (typeof PageWorker === 'function' && base !== undefined) return new PageWorker(`${base}${workerName(name)}.worker.js`);
198
- if (nativeBridge()?.workerStart) return new NativeWorker(name);
212
+ if (nativeBridge()?.workerStart) return new NativeWorker(name, options);
199
213
  if (typeof PageWorker === 'function') return new PageWorker(`${workerName(name)}.worker.js`);
200
214
  throw new Error(`createWorker: no host for "${name}" (not in a SwiftBrowser Native app or a page)`);
201
215
  }
@@ -27,7 +27,7 @@ import FoundationBridge // the shim's Foundation stand-ins (ShimAliases.swift)
27
27
  /// | `openURL(url)` | the system opener |
28
28
  /// | `locale()` | the viewer's locale identifier |
29
29
  /// | `launchArguments()` | the process's arguments (`-screen list` from a scheme or `simctl launch`) |
30
- /// | `workerStart(id, name)`, `workerPost(id, text)`, `workerTerminate(id)` | workers (WorkerHost.swift, JavaScriptCore only); their messages come to `__sbWorkerMessage(id, text)`, their errors to `__sbWorkerError(id, message)` |
30
+ /// | `workerStart(id, name, engine)`, `workerPost(id, text)`, `workerTerminate(id)` | workers (JavaScriptCore only): a `JSContext` on a thread (`"context"`, WorkerHost.swift) or a hidden web view with WebKit's JIT (`"webview"`, WebViewWorkerHost.swift); their messages come to `__sbWorkerMessage(id, text)`, their errors to `__sbWorkerError(id, message)` |
31
31
  ///
32
32
  /// Everything JavaScript-facing runs on the main thread; work that is not
33
33
  /// (a fetch, a worker) hops back before calling in.
@@ -37,7 +37,7 @@ final class HostBridge {
37
37
  private let tree: OpTree
38
38
  private var timers: [Int: Timer] = [:]
39
39
  #if canImport(JavaScriptCore)
40
- private var workers: [Int: WorkerHost] = [:]
40
+ private var workers: [Int: any WorkerEngine] = [:]
41
41
  #endif
42
42
  private let logger = Logger(subsystem: "swiftbrowser", category: "js")
43
43
  private let session = URLSession(configuration: .default)
@@ -180,16 +180,28 @@ final class HostBridge {
180
180
  guard let self, let id = arguments[safe: 0]?.int, let name = arguments[safe: 1]?.string else {
181
181
  return .string("workerStart: expected an id and a name")
182
182
  }
183
+ let onMessage: @Sendable (String) -> Void = { [weak self] text in
184
+ DispatchQueue.main.async {
185
+ MainActor.assumeIsolated { self?.callIn("__sbWorkerMessage", [.number(Double(id)), .string(text)]) }
186
+ }
187
+ }
188
+ let onError: @Sendable (String) -> Void = { [weak self] message in
189
+ DispatchQueue.main.async {
190
+ MainActor.assumeIsolated { self?.callIn("__sbWorkerError", [.number(Double(id)), .string(message)]) }
191
+ }
192
+ }
183
193
  do {
184
- let worker = try WorkerHost(name: name, onMessage: { [weak self] text in
185
- DispatchQueue.main.async {
186
- MainActor.assumeIsolated { self?.callIn("__sbWorkerMessage", [.number(Double(id)), .string(text)]) }
187
- }
188
- }, onError: { [weak self] message in
189
- DispatchQueue.main.async {
190
- MainActor.assumeIsolated { self?.callIn("__sbWorkerError", [.number(Double(id)), .string(message)]) }
191
- }
192
- })
194
+ let worker: any WorkerEngine
195
+ switch arguments[safe: 2]?.string ?? "context" {
196
+ case "context":
197
+ worker = try WorkerHost(name: name, onMessage: onMessage, onError: onError)
198
+ #if canImport(WebKit)
199
+ case "webview":
200
+ worker = try WebViewWorkerHost(name: name, onMessage: onMessage, onError: onError)
201
+ #endif
202
+ case let engine:
203
+ return .string("workerStart: no \(engine) engine here (\"context\" or \"webview\")")
204
+ }
193
205
  self.workers[id]?.terminate()
194
206
  self.workers[id] = worker
195
207
  worker.start()
@@ -0,0 +1,315 @@
1
+ #if canImport(SwiftUI) && canImport(JavaScriptCore) && canImport(WebKit)
2
+ import Foundation
3
+ import os
4
+ import SwiftBrowserProtocol
5
+ import WebKit
6
+ #if canImport(UIKit)
7
+ import UIKit
8
+ #endif
9
+
10
+ /// A worker in a hidden `WKWebView` (`createWorker(name, { engine: 'webview' })`):
11
+ /// the same `<name>.worker.js` and the same messages as WorkerHost.swift's
12
+ /// `JSContext`, run by WebKit's web content process, which compiles
13
+ /// JavaScript and WebAssembly with its JIT. An app's own JavaScriptCore has
14
+ /// no JIT on iOS (only Apple's processes are allowed one), so heavy
15
+ /// WebAssembly runs much faster here; the cost is a process and a
16
+ /// web view's memory.
17
+ ///
18
+ /// The page's `__sbNative` (`bootstrap`, below) is the worker bridge
19
+ /// written in JavaScript over the page's own timers and `crypto`. Its
20
+ /// `workerPostMessage`, `log` and `fetch` come here through the `sbWorker`
21
+ /// message handler, as JSON text. The runtime keeps the page's globals and
22
+ /// installs its own `fetch` family over the bridge, so requests go through
23
+ /// `URLSession`, with the app's cookies, as a `JSContext` worker's do.
24
+ /// Messages in, and fetch answers, go in with `callAsyncJavaScript`.
25
+ ///
26
+ /// On iOS the web view sits behind the key window's content, 1×1 and clear:
27
+ /// WebKit suspends the process of a web view outside a window.
28
+ @MainActor
29
+ final class WebViewWorkerHost: NSObject, WorkerEngine, WKNavigationDelegate {
30
+ let name: String
31
+ private let script: String
32
+ private let onMessage: @Sendable (String) -> Void
33
+ private let onError: @Sendable (String) -> Void
34
+ private let logger = Logger(subsystem: "swiftbrowser", category: "worker")
35
+ private let session = URLSession(configuration: .default)
36
+ private var webView: WKWebView?
37
+ /// Whether the script ran in the current page; messages wait in `pending` until it has.
38
+ private var ready = false
39
+ private var pending: [String] = []
40
+ private var terminated = false
41
+ #if os(iOS)
42
+ private var windowObserver: NSObjectProtocol?
43
+ #endif
44
+
45
+ /// The script is `<name>.worker.js` in `bundle`, as WorkerHost's; throws when it is not there.
46
+ init(name: String, bundle: Bundle = .main, onMessage: @escaping @Sendable (String) -> Void, onError: @escaping @Sendable (String) -> Void) throws {
47
+ guard let url = bundle.url(forResource: "\(name).worker", withExtension: "js") else {
48
+ throw JSError(message: "\(name).worker.js is not in the app bundle (build it with `swiftbrowser-native build --worker \(name)=<entry>`)")
49
+ }
50
+ self.name = name
51
+ script = try String(contentsOf: url, encoding: .utf8) + "\n//# sourceURL=\(name).worker.js"
52
+ self.onMessage = onMessage
53
+ self.onError = onError
54
+ }
55
+
56
+ func start() {
57
+ let configuration = WKWebViewConfiguration()
58
+ configuration.websiteDataStore = .nonPersistent()
59
+ let content = configuration.userContentController
60
+ content.addUserScript(WKUserScript(source: Self.bootstrap, injectionTime: .atDocumentStart, forMainFrameOnly: true))
61
+ content.add(MessageHandler(host: self), name: "sbWorker")
62
+ let webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 1, height: 1), configuration: configuration)
63
+ webView.navigationDelegate = self
64
+ #if DEBUG
65
+ webView.isInspectable = true // Safari's Develop menu
66
+ #endif
67
+ #if os(iOS)
68
+ webView.isOpaque = false
69
+ webView.backgroundColor = .clear
70
+ webView.scrollView.backgroundColor = .clear
71
+ webView.isUserInteractionEnabled = false
72
+ webView.accessibilityElementsHidden = true
73
+ #endif
74
+ self.webView = webView
75
+ attach()
76
+ load()
77
+ }
78
+
79
+ func post(_ text: String) {
80
+ guard !terminated else { return }
81
+ guard ready else {
82
+ pending.append(text)
83
+ return
84
+ }
85
+ evaluate("__sbWorkerReceive(text)", ["text": text])
86
+ }
87
+
88
+ func terminate() {
89
+ terminated = true
90
+ #if os(iOS)
91
+ if let windowObserver { NotificationCenter.default.removeObserver(windowObserver) }
92
+ windowObserver = nil
93
+ #endif
94
+ guard let webView else { return }
95
+ webView.configuration.userContentController.removeScriptMessageHandler(forName: "sbWorker")
96
+ webView.navigationDelegate = nil
97
+ webView.stopLoading()
98
+ webView.removeFromSuperview()
99
+ self.webView = nil
100
+ ready = false
101
+ pending = []
102
+ }
103
+
104
+ // MARK: The page
105
+
106
+ /// An empty page on an origin of its own (`localStorage` and the like
107
+ /// need one); nothing is fetched from it.
108
+ private func load() {
109
+ ready = false
110
+ let origin = URL(string: "https://worker.swiftbrowser.invalid/\(name)/")
111
+ webView?.loadHTMLString("<!doctype html><meta charset=\"utf-8\"><title>\(name)</title>", baseURL: origin)
112
+ }
113
+
114
+ func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
115
+ guard webView === self.webView, !ready else { return }
116
+ evaluate("__sbWorkerRun(script)", ["script": script])
117
+ ready = true
118
+ // In order after the script: WebKit runs the calls as they were sent.
119
+ let queued = pending
120
+ pending = []
121
+ for text in queued { post(text) }
122
+ }
123
+
124
+ func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: any Error) {
125
+ fail("\(name): the worker's page did not load: \(error.localizedDescription)")
126
+ }
127
+
128
+ /// The process ended (memory pressure, a crash): the worker starts over
129
+ /// in a new one, losing what was in flight.
130
+ func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
131
+ guard webView === self.webView else { return }
132
+ fail("\(name): the worker's web content process ended; restarting it")
133
+ load()
134
+ }
135
+
136
+ /// Runs `body` as an async function in the page, its arguments as locals.
137
+ private func evaluate(_ body: String, _ arguments: [String: Any]) {
138
+ webView?.callAsyncJavaScript(body, arguments: arguments, in: nil, in: .page) { [weak self] result in
139
+ guard case .failure(let error) = result else { return }
140
+ let message = (error as NSError).userInfo["WKJavaScriptExceptionMessage"] as? String ?? error.localizedDescription
141
+ MainActor.assumeIsolated { self?.fail(message) }
142
+ }
143
+ }
144
+
145
+ private func fail(_ message: String) {
146
+ logger.error("\(self.name): \(message, privacy: .public)")
147
+ onError(message)
148
+ }
149
+
150
+ // MARK: From the page
151
+
152
+ fileprivate func receive(_ text: String) {
153
+ guard let message = try? JSONValue.parse(text) else { return }
154
+ switch message["kind"].string {
155
+ case "message":
156
+ if let text = message["text"].string { onMessage(text) }
157
+ case "error":
158
+ fail(message["message"].string ?? "unknown error")
159
+ case "log":
160
+ let level = message["level"].string ?? "log"
161
+ let text = message["message"].string ?? ""
162
+ switch level {
163
+ case "error": logger.error("\(self.name): \(text, privacy: .public)")
164
+ case "warn": logger.warning("\(self.name): \(text, privacy: .public)")
165
+ case "debug": logger.debug("\(self.name): \(text, privacy: .public)")
166
+ default: logger.info("\(self.name): \(text, privacy: .public)")
167
+ }
168
+ #if DEBUG
169
+ print("[\(name):\(level)] \(text)")
170
+ #endif
171
+ case "fetch":
172
+ guard let id = message["id"].int else { return }
173
+ WorkerHost.perform(message["request"], session: session) { [weak self] result in
174
+ DispatchQueue.main.async {
175
+ MainActor.assumeIsolated {
176
+ self?.evaluate("__sbFetchResult(id, JSON.parse(result))", ["id": id, "result": result.json])
177
+ }
178
+ }
179
+ }
180
+ default:
181
+ break
182
+ }
183
+ }
184
+
185
+ // MARK: The window
186
+
187
+ #if os(iOS)
188
+ /// Puts the web view behind the key window's content, or waits for a window.
189
+ private func attach() {
190
+ guard let webView, webView.window == nil else { return }
191
+ let windows = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }.flatMap(\.windows)
192
+ guard let window = windows.first(where: \.isKeyWindow) ?? windows.first else {
193
+ if windowObserver == nil {
194
+ windowObserver = NotificationCenter.default.addObserver(forName: UIWindow.didBecomeKeyNotification, object: nil, queue: .main) { [weak self] _ in
195
+ MainActor.assumeIsolated { self?.attach() }
196
+ }
197
+ }
198
+ return
199
+ }
200
+ window.insertSubview(webView, at: 0)
201
+ if let windowObserver { NotificationCenter.default.removeObserver(windowObserver) }
202
+ windowObserver = nil
203
+ }
204
+ #else
205
+ /// A Mac's web view runs outside a window.
206
+ private func attach() {}
207
+ #endif
208
+
209
+ // MARK: The bridge in the page
210
+
211
+ /// The worker bridge (packages/native/src/bridge.ts) over the page, run
212
+ /// before anything else in it.
213
+ static var bootstrap: String {
214
+ let locale = JSONValue.string(Locale.current.identifier).json
215
+ let arguments = JSONValue.array(ProcessInfo.processInfo.arguments.map(JSONValue.string)).json
216
+ return """
217
+ (() => {
218
+ 'use strict';
219
+ const handler = window.webkit.messageHandlers.sbWorker;
220
+ const send = (message) => handler.postMessage(JSON.stringify(message));
221
+ const describe = (error) => {
222
+ if (!(error instanceof Error)) return String(error);
223
+ return error.stack ? `${error}\\n${error.stack}` : String(error);
224
+ };
225
+ const fail = (error) => send({ kind: 'error', message: describe(error) });
226
+ addEventListener('error', (event) => fail(event.error ?? event.message));
227
+ addEventListener('unhandledrejection', (event) => fail(event.reason));
228
+
229
+ // The runtime installs its fetch over the bridge in place of these.
230
+ for (const name of ['fetch', 'Headers', 'Request', 'Response', 'AbortController', 'AbortSignal']) {
231
+ Object.defineProperty(window, name, { value: undefined, writable: true, configurable: true });
232
+ }
233
+
234
+ // The page's console, and the app's log.
235
+ const format = (value) => {
236
+ if (typeof value === 'string') return value;
237
+ if (value instanceof Error) return describe(value);
238
+ try {
239
+ return JSON.stringify(value) ?? String(value);
240
+ } catch {
241
+ return String(value);
242
+ }
243
+ };
244
+ for (const level of ['log', 'info', 'warn', 'error', 'debug']) {
245
+ const write = console[level].bind(console);
246
+ console[level] = (...values) => {
247
+ write(...values);
248
+ send({ kind: 'log', level, message: values.map(format).join(' ') });
249
+ };
250
+ }
251
+
252
+ const timers = new Map();
253
+ const clearTimer = (id) => {
254
+ clearTimeout(timers.get(id));
255
+ clearInterval(timers.get(id));
256
+ timers.delete(id);
257
+ };
258
+ window.__sbNative = {
259
+ workerPostMessage: (text) => send({ kind: 'message', text: String(text) }),
260
+ log: (level, message) => send({ kind: 'log', level: String(level), message: String(message) }),
261
+ now: () => performance.now(),
262
+ setTimer: (id, delay, repeats) => {
263
+ clearTimer(id);
264
+ const fire = () => {
265
+ if (!repeats) timers.delete(id);
266
+ window.__sbTimerFired?.(id);
267
+ };
268
+ timers.set(id, repeats ? setInterval(fire, delay) : setTimeout(fire, delay));
269
+ },
270
+ clearTimer,
271
+ fetch: (id, request) => send({ kind: 'fetch', id, request: typeof request === 'string' ? JSON.parse(request) : request }),
272
+ // No storage of its own, as a JSContext worker.
273
+ storageGet: () => null,
274
+ storageSet: () => {},
275
+ storageRemove: () => {},
276
+ storageKeys: () => [],
277
+ storageClear: () => {},
278
+ randomBytes: (count) => {
279
+ const bytes = crypto.getRandomValues(new Uint8Array(Math.max(0, Math.min(count | 0, 65536))));
280
+ let text = '';
281
+ for (const byte of bytes) text += String.fromCharCode(byte);
282
+ return btoa(text);
283
+ },
284
+ openURL: () => false,
285
+ locale: () => \(locale),
286
+ launchArguments: () => \(arguments),
287
+ };
288
+
289
+ // The worker's script, at top level; what it throws is the worker's error.
290
+ window.__sbWorkerRun = (script) => {
291
+ try {
292
+ (0, eval)(script);
293
+ } catch (error) {
294
+ fail(error);
295
+ }
296
+ };
297
+ })();
298
+ """
299
+ }
300
+ }
301
+
302
+ /// The page's messages to the host, without the content controller keeping the host alive.
303
+ @MainActor
304
+ private final class MessageHandler: NSObject, WKScriptMessageHandler {
305
+ private weak var host: WebViewWorkerHost?
306
+
307
+ init(host: WebViewWorkerHost) {
308
+ self.host = host
309
+ }
310
+
311
+ func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
312
+ if let text = message.body as? String { host?.receive(text) }
313
+ }
314
+ }
315
+ #endif
@@ -174,8 +174,18 @@ final class WorkerHost: @unchecked Sendable {
174
174
 
175
175
  /// As HostBridge's, answering on the worker's thread.
176
176
  private func fetch(id: Int, request: JSONValue) {
177
+ Self.perform(request, session: session) { [weak self] result in
178
+ guard let self else { return }
179
+ self.thread.perform { [self] in self.call("__sbFetchResult", [.number(Double(id)), result]) }
180
+ }
181
+ }
182
+
183
+ /// Runs a worker's `fetch` request (`{url, method, headers, body}`, the
184
+ /// body base64) on `session` and answers with what `__sbFetchResult`
185
+ /// takes, on the session's queue.
186
+ static func perform(_ request: JSONValue, session: URLSession, completion: @escaping @Sendable (JSONValue) -> Void) {
177
187
  guard let urlString = request["url"].string, let url = URL(string: urlString) else {
178
- call("__sbFetchResult", [.number(Double(id)), .object(["error": .string("invalid URL")])])
188
+ completion(.object(["error": .string("invalid URL")]))
179
189
  return
180
190
  }
181
191
  var urlRequest = URLRequest(url: url)
@@ -186,31 +196,43 @@ final class WorkerHost: @unchecked Sendable {
186
196
  if let body = request["body"].string, let data = Data(base64Encoded: body) {
187
197
  urlRequest.httpBody = data
188
198
  }
189
- let task = session.dataTask(with: urlRequest) { [weak self] data, response, error in
190
- let result: JSONValue
199
+ let task = session.dataTask(with: urlRequest) { data, response, error in
191
200
  if let error {
192
- result = .object(["error": .string(error.localizedDescription)])
193
- } else {
194
- let http = response as? HTTPURLResponse
195
- var headers: JSONObject = [:]
196
- for (name, value) in http?.allHeaderFields ?? [:] {
197
- headers[String(describing: name).lowercased()] = .string(String(describing: value))
198
- }
199
- result = .object([
200
- "status": .number(Double(http?.statusCode ?? 200)),
201
- "statusText": .string(http.map { HTTPURLResponse.localizedString(forStatusCode: $0.statusCode) } ?? ""),
202
- "headers": .object(headers),
203
- "url": .string(response?.url?.absoluteString ?? urlString),
204
- "body": .string((data ?? Data()).base64EncodedString()),
205
- ])
201
+ completion(.object(["error": .string(error.localizedDescription)]))
202
+ return
206
203
  }
207
- guard let self else { return }
208
- self.thread.perform { [self] in self.call("__sbFetchResult", [.number(Double(id)), result]) }
204
+ let http = response as? HTTPURLResponse
205
+ var headers: JSONObject = [:]
206
+ for (name, value) in http?.allHeaderFields ?? [:] {
207
+ headers[String(describing: name).lowercased()] = .string(String(describing: value))
208
+ }
209
+ completion(.object([
210
+ "status": .number(Double(http?.statusCode ?? 200)),
211
+ "statusText": .string(http.map { HTTPURLResponse.localizedString(forStatusCode: $0.statusCode) } ?? ""),
212
+ "headers": .object(headers),
213
+ "url": .string(response?.url?.absoluteString ?? urlString),
214
+ "body": .string((data ?? Data()).base64EncodedString()),
215
+ ]))
209
216
  }
210
217
  task.resume()
211
218
  }
212
219
  }
213
220
 
221
+ /// A worker as the app's bridge (HostBridge.swift) drives it: this file's
222
+ /// `JSContext` on a thread, or a hidden web view (WebViewWorkerHost.swift).
223
+ @MainActor
224
+ protocol WorkerEngine: AnyObject {
225
+ /// Loads the script; messages posted before it ran wait for it.
226
+ func start()
227
+ /// Delivers an encoded message to the worker's `__sbWorkerReceive`.
228
+ func post(_ text: String)
229
+ func terminate()
230
+ }
231
+
232
+ // In an extension, so the protocol's actor is not inferred for the class:
233
+ // the host's own work is on its thread.
234
+ extension WorkerHost: WorkerEngine {}
235
+
214
236
  /// A thread with a run loop that runs blocks sent to it, in order, after
215
237
  /// the block it started with.
216
238
  final class WorkerThread: @unchecked Sendable {
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/wasm/SwiftBrowserNative.wasm
3
- size: 49302313 bytes
4
- sha256: a2426ea2bd5032a173f7975b94c57b9f331404b419e57e87c5573e7350eac8da
3
+ size: 49302688 bytes
4
+ sha256: 05f97ec252da1a85b64465ba5426d2ce1c620c78016ec4f2ae1bb7387a270be0