@swiftbrowser/web 0.10.3 → 0.11.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/node/dist/node/config.d.ts +5 -0
- package/node/dist/node/config.d.ts.map +1 -1
- package/node/dist/node/config.js +1 -0
- package/node/dist/node/config.js.map +1 -1
- package/node/dist/node/index.d.ts +1 -0
- package/node/dist/node/index.d.ts.map +1 -1
- package/node/dist/node/index.js +1 -0
- package/node/dist/node/index.js.map +1 -1
- package/node/dist/src/nativeHost.d.ts +46 -0
- package/node/dist/src/nativeHost.d.ts.map +1 -0
- package/node/dist/src/nativeHost.js +129 -0
- package/node/dist/src/nativeHost.js.map +1 -0
- package/package.json +1 -1
- package/src/animation.ts +29 -1
- package/src/nativeHost.ts +166 -0
- package/src/renderer.ts +2 -0
- package/src/wasm.ts +61 -12
|
@@ -46,6 +46,11 @@ export interface SiteOptions {
|
|
|
46
46
|
* the browser. This repository's site only.
|
|
47
47
|
*/
|
|
48
48
|
playground?: PlaygroundOptions;
|
|
49
|
+
/**
|
|
50
|
+
* The path the site is served under when it is not a host's root (`/native/`
|
|
51
|
+
* for a site inside another: Vite's `base`); `/` by default. Build only.
|
|
52
|
+
*/
|
|
53
|
+
base?: string;
|
|
49
54
|
}
|
|
50
55
|
/** The layout `options` resolve to (see `SiteOptions.layout`). */
|
|
51
56
|
export declare function siteLayout(options: Pick<SiteOptions, 'apps' | 'sites' | 'layout'>): SiteLayout;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAKvC,OAAO,EAAmD,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAChI,OAAO,EAAE,KAAK,iBAAiB,EAAyC,MAAM,0BAA0B,CAAC;AAEzG,OAAO,EAAmC,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,sGAAsG;IACtG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB;;;OAGG;IACH,UAAU,CAAC,EAAE,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAKvC,OAAO,EAAmD,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAChI,OAAO,EAAE,KAAK,iBAAiB,EAAyC,MAAM,0BAA0B,CAAC;AAEzG,OAAO,EAAmC,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,sGAAsG;IACtG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB;;;OAGG;IACH,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC,GAAG,UAAU,CAG9F;AAED,qGAAqG;AACrG,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oHAAoH;IACpH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,yGAAyG;IACzG,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,0GAA0G;IAC1G,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAOD;;;;;GAKG;AACH,wBAAgB,OAAO,IAAI,MAAM,CAoBhC;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,UAAU,EAAE,CAWnE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,CAoEjE"}
|
package/node/dist/node/config.js
CHANGED
|
@@ -115,6 +115,7 @@ export function createViteConfig(options) {
|
|
|
115
115
|
pages['playground'] = path.resolve(root, 'playground/index.html');
|
|
116
116
|
return {
|
|
117
117
|
root,
|
|
118
|
+
...(options.base ? { base: options.base } : {}),
|
|
118
119
|
plugins: [
|
|
119
120
|
swiftWasm(apps),
|
|
120
121
|
appManifests(apps, included, manifestOptions),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAqD,MAAM,2BAA2B,CAAC;AAChI,OAAO,EAA0B,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACzG,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAgB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@ export { APP_NAME, validateAppSpecs } from './apps.js';
|
|
|
15
15
|
export type { LandingApp, SiteOptions } from './config.js';
|
|
16
16
|
export { createViteConfig, landingApps, siteLayout, webRoot } from './config.js';
|
|
17
17
|
export type { SiteInfo, SiteLayout, SitePageMode } from '../plugins/site-layout.js';
|
|
18
|
+
export { wasmNativeHost, type WasmNativeHost, type WasmNativeHostOptions } from '../src/nativeHost.js';
|
|
18
19
|
export interface DevServerOptions extends SiteOptions {
|
|
19
20
|
/** Defaults to 5173. */
|
|
20
21
|
port?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,MAAM,CAAC;AACnF,OAAO,EAAgC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7E,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACvD,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACjF,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,MAAM,CAAC;AACnF,OAAO,EAAgC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7E,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACvD,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACjF,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAEvG,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,gFAAgF;IAChF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yDAAyD;IACzD,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;CACjD;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAWvF;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUxE;AAED,0GAA0G;AAC1G,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE7D"}
|
package/node/dist/node/index.js
CHANGED
|
@@ -14,6 +14,7 @@ import { build, createServer } from 'vite';
|
|
|
14
14
|
import { createViteConfig, siteLayout } from './config.js';
|
|
15
15
|
export { APP_NAME, validateAppSpecs } from './apps.js';
|
|
16
16
|
export { createViteConfig, landingApps, siteLayout, webRoot } from './config.js';
|
|
17
|
+
export { wasmNativeHost } from '../src/nativeHost.js';
|
|
17
18
|
/**
|
|
18
19
|
* A configured, started Vite dev server (`listen` has been called) with the
|
|
19
20
|
* registry plugins for `options.apps`. Call `server.printUrls()` to show the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,YAAY,EAA0C,MAAM,MAAM,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAoB,MAAM,aAAa,CAAC;AAG7E,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,YAAY,EAA0C,MAAM,MAAM,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAoB,MAAM,aAAa,CAAC;AAG7E,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEjF,OAAO,EAAE,cAAc,EAAmD,MAAM,sBAAsB,CAAC;AAsBvG;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAyB;IAC7D,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAC1D,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,MAAM,GAAkB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;IACnD,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;IAC3C,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;IAC3C,IAAI,UAAU,KAAK,SAAS;QAAE,MAAM,CAAC,UAAU,GAAG,UAAU,CAAC;IAC7D,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;IAC3C,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/E,MAAM,SAAS,CAAC,MAAM,EAAE,CAAC;IACzB,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAyB;IACvD,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAC3D,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,KAAK;QAAE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACxF,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,KAAK,CAAC;QACV,GAAG,MAAM;QACT,UAAU,EAAE,KAAK;QACjB,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjC,KAAK,EAAE,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,WAAW,IAAI,IAAI,EAAE;KAC3F,CAAC,CAAC;AACL,CAAC;AAED,0GAA0G;AAC1G,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,OAAO,UAAU,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host's JavaScript as SwiftBrowser Native's engine (docs/native.md,
|
|
3
|
+
* "The round trip"): for a module built with the round-trip target
|
|
4
|
+
* (`Native/RoundTrip`, the native views compiled against the shim), this
|
|
5
|
+
* answers its one import, `sb_native.request`, and exposes the native
|
|
6
|
+
* functions Swift installs (`applyOps`, `log`, `now`, …) on `__sbNative`,
|
|
7
|
+
* each a call of the module's `sb_native_invoke` export.
|
|
8
|
+
*
|
|
9
|
+
* The page (wasm.ts, for a module that imports `sb_native`) and Node
|
|
10
|
+
* (scripts/run-wasi.mjs) use it the same way: merge `imports` into the
|
|
11
|
+
* module's imports, instantiate, then `attach` the instance. Strings cross
|
|
12
|
+
* linear memory as UTF-8; an answer to Swift is a buffer from `sb_alloc`
|
|
13
|
+
* holding a little-endian 4-byte length and the bytes, which Swift frees,
|
|
14
|
+
* and a result from Swift is the same layout, freed with `sb_native_free`
|
|
15
|
+
* once read. `@swiftbrowser/native/wasm-host` re-exports it.
|
|
16
|
+
*/
|
|
17
|
+
export interface WasmNativeHostOptions {
|
|
18
|
+
/** Runs a script at the global scope (default: an indirect `eval`). */
|
|
19
|
+
evaluate?: (script: string, name: string) => void;
|
|
20
|
+
/** The global object the bundle's globals live on (default `globalThis`). */
|
|
21
|
+
global?: Record<string, unknown>;
|
|
22
|
+
/**
|
|
23
|
+
* Called after each installed function ran, with its name: the page runs
|
|
24
|
+
* the module's executor after an `applyOps` that came from the page's own
|
|
25
|
+
* loop (a fetch's answer, a timer), which no event follows.
|
|
26
|
+
*/
|
|
27
|
+
afterInvoke?: (name: string) => void;
|
|
28
|
+
}
|
|
29
|
+
export interface WasmNativeHost {
|
|
30
|
+
/** Merge into the module's import object before instantiating. */
|
|
31
|
+
imports: {
|
|
32
|
+
sb_native: {
|
|
33
|
+
request: (kind: number, kindLength: number, a: number, aLength: number, b: number, bLength: number) => number;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/** The instance, once instantiated: its memory and the exports the host calls. */
|
|
37
|
+
attach(instance: NativeInstance): void;
|
|
38
|
+
/** The `__sbNative` object as it stands (replaced by a reset). */
|
|
39
|
+
readonly native: Record<string, (...args: unknown[]) => unknown>;
|
|
40
|
+
}
|
|
41
|
+
/** A `WebAssembly.Instance` (typed structurally: the Node build has no DOM lib). */
|
|
42
|
+
export interface NativeInstance {
|
|
43
|
+
exports: object;
|
|
44
|
+
}
|
|
45
|
+
export declare function wasmNativeHost(options?: WasmNativeHostOptions): WasmNativeHost;
|
|
46
|
+
//# sourceMappingURL=nativeHost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nativeHost.d.ts","sourceRoot":"","sources":["../../../src/nativeHost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,qBAAqB;IACpC,uEAAuE;IACvE,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,OAAO,EAAE;QACP,SAAS,EAAE;YACT,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;SAC/G,CAAC;KACH,CAAC;IACF,kFAAkF;IAClF,MAAM,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;IACvC,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,CAAC;CAClE;AAED,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB;AAYD,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,cAAc,CA2GlF"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host's JavaScript as SwiftBrowser Native's engine (docs/native.md,
|
|
3
|
+
* "The round trip"): for a module built with the round-trip target
|
|
4
|
+
* (`Native/RoundTrip`, the native views compiled against the shim), this
|
|
5
|
+
* answers its one import, `sb_native.request`, and exposes the native
|
|
6
|
+
* functions Swift installs (`applyOps`, `log`, `now`, …) on `__sbNative`,
|
|
7
|
+
* each a call of the module's `sb_native_invoke` export.
|
|
8
|
+
*
|
|
9
|
+
* The page (wasm.ts, for a module that imports `sb_native`) and Node
|
|
10
|
+
* (scripts/run-wasi.mjs) use it the same way: merge `imports` into the
|
|
11
|
+
* module's imports, instantiate, then `attach` the instance. Strings cross
|
|
12
|
+
* linear memory as UTF-8; an answer to Swift is a buffer from `sb_alloc`
|
|
13
|
+
* holding a little-endian 4-byte length and the bytes, which Swift frees,
|
|
14
|
+
* and a result from Swift is the same layout, freed with `sb_native_free`
|
|
15
|
+
* once read. `@swiftbrowser/native/wasm-host` re-exports it.
|
|
16
|
+
*/
|
|
17
|
+
/** The globals a bundle defines, dropped by a reset (`JSHost.reset`). */
|
|
18
|
+
const BUNDLE_GLOBALS = ['__sbDispatch', '__sbTimerFired', '__sbFetchResult', '__sbRefresh', '__sbVendor'];
|
|
19
|
+
export function wasmNativeHost(options = {}) {
|
|
20
|
+
const g = options.global ?? globalThis;
|
|
21
|
+
const evaluate = options.evaluate ?? ((script) => (0, eval)(script));
|
|
22
|
+
const encoder = new TextEncoder();
|
|
23
|
+
const decoder = new TextDecoder();
|
|
24
|
+
let exports = null;
|
|
25
|
+
let native = {};
|
|
26
|
+
const need = () => {
|
|
27
|
+
if (!exports)
|
|
28
|
+
throw new Error('wasmNativeHost: attach(instance) before the module runs');
|
|
29
|
+
return exports;
|
|
30
|
+
};
|
|
31
|
+
const read = (pointer, length) => decoder.decode(new Uint8Array(need().memory.buffer, pointer, length));
|
|
32
|
+
/** A buffer from `sb_alloc` with the text's length and bytes; Swift frees it. */
|
|
33
|
+
const answer = (value) => {
|
|
34
|
+
const bytes = encoder.encode(JSON.stringify(value));
|
|
35
|
+
const pointer = need().sb_alloc(bytes.length + 4);
|
|
36
|
+
// The allocation may have grown the memory: take the view after it.
|
|
37
|
+
const view = new DataView(need().memory.buffer);
|
|
38
|
+
view.setUint32(pointer, bytes.length, true);
|
|
39
|
+
new Uint8Array(need().memory.buffer, pointer + 4, bytes.length).set(bytes);
|
|
40
|
+
return pointer;
|
|
41
|
+
};
|
|
42
|
+
const describe = (error) => (error instanceof Error ? (error.stack ?? error.message) : String(error));
|
|
43
|
+
/** A native function's call: into Swift and back with its JSON result. */
|
|
44
|
+
const invoke = (name, args) => {
|
|
45
|
+
try {
|
|
46
|
+
return call(name, args);
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
options.afterInvoke?.(name);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const call = (name, args) => {
|
|
53
|
+
const nameBytes = encoder.encode(name);
|
|
54
|
+
const argsBytes = encoder.encode(JSON.stringify(args));
|
|
55
|
+
const namePointer = need().sb_alloc(nameBytes.length || 1);
|
|
56
|
+
new Uint8Array(need().memory.buffer, namePointer, nameBytes.length).set(nameBytes);
|
|
57
|
+
const argsPointer = need().sb_alloc(argsBytes.length || 1);
|
|
58
|
+
new Uint8Array(need().memory.buffer, argsPointer, argsBytes.length).set(argsBytes);
|
|
59
|
+
const result = need().sb_native_invoke(namePointer, nameBytes.length, argsPointer, argsBytes.length);
|
|
60
|
+
if (result === 0)
|
|
61
|
+
return undefined;
|
|
62
|
+
const length = new DataView(need().memory.buffer).getUint32(result, true);
|
|
63
|
+
const text = read(result + 4, length);
|
|
64
|
+
need().sb_native_free(result);
|
|
65
|
+
const value = JSON.parse(text);
|
|
66
|
+
if (value && typeof value === 'object' && 'error' in value && Object.keys(value).length === 1) {
|
|
67
|
+
throw new Error(String(value.error));
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
70
|
+
};
|
|
71
|
+
const reset = () => {
|
|
72
|
+
for (const name of BUNDLE_GLOBALS)
|
|
73
|
+
delete g[name];
|
|
74
|
+
native = {};
|
|
75
|
+
g['__sbNative'] = native;
|
|
76
|
+
};
|
|
77
|
+
const request = (kind, kindLength, a, aLength, b, bLength) => {
|
|
78
|
+
const what = read(kind, kindLength);
|
|
79
|
+
const first = read(a, aLength);
|
|
80
|
+
const second = read(b, bLength);
|
|
81
|
+
switch (what) {
|
|
82
|
+
case 'reset':
|
|
83
|
+
reset();
|
|
84
|
+
return 0;
|
|
85
|
+
case 'install':
|
|
86
|
+
native[first] = (...args) => invoke(first, args);
|
|
87
|
+
return 0;
|
|
88
|
+
case 'eval':
|
|
89
|
+
try {
|
|
90
|
+
evaluate(first, second);
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
return answer({ error: describe(error) });
|
|
95
|
+
}
|
|
96
|
+
case 'call': {
|
|
97
|
+
const fn = g[first];
|
|
98
|
+
if (typeof fn !== 'function')
|
|
99
|
+
return answer({ error: `${first} is not defined` });
|
|
100
|
+
try {
|
|
101
|
+
const result = fn(...JSON.parse(second));
|
|
102
|
+
return answer({ ok: result === undefined ? null : result });
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return answer({ error: describe(error) });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
case 'has':
|
|
109
|
+
return answer({ ok: first in g });
|
|
110
|
+
default:
|
|
111
|
+
return answer({ error: `unknown request ${what}` });
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
reset();
|
|
115
|
+
return {
|
|
116
|
+
imports: { sb_native: { request } },
|
|
117
|
+
attach(instance) {
|
|
118
|
+
for (const name of ['memory', 'sb_alloc', 'sb_native_invoke', 'sb_native_free']) {
|
|
119
|
+
if (!(name in instance.exports))
|
|
120
|
+
throw new Error(`wasmNativeHost: the module does not export ${name}`);
|
|
121
|
+
}
|
|
122
|
+
exports = instance.exports;
|
|
123
|
+
},
|
|
124
|
+
get native() {
|
|
125
|
+
return native;
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=nativeHost.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nativeHost.js","sourceRoot":"","sources":["../../../src/nativeHost.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/animation.ts
CHANGED
|
@@ -961,12 +961,36 @@ export class Animator {
|
|
|
961
961
|
el.animate([from, to], { ...timing, fill: 'backwards' });
|
|
962
962
|
}
|
|
963
963
|
|
|
964
|
+
/** The exit clones playing, each with the element it left (its parent at removal): `dropExitClonesIn`. */
|
|
965
|
+
private readonly exitClones = new Map<HTMLElement, HTMLElement>();
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* Drops the exit clones of elements that left `container` or anything in
|
|
969
|
+
* it: a clone stands in for content of a container that is now going
|
|
970
|
+
* itself, and would play on over whatever takes the container's place. A
|
|
971
|
+
* screen that swaps its content for a placeholder a commit before it is
|
|
972
|
+
* popped (a split view's detail as its selection clears) left its bar
|
|
973
|
+
* group's clone fading over the uncovered screen's bar. (A clone not built
|
|
974
|
+
* yet, its pass still waiting for the frame, is refused in `exit`.)
|
|
975
|
+
*/
|
|
976
|
+
dropExitClonesIn(container: HTMLElement): void {
|
|
977
|
+
for (const [clone, owner] of this.exitClones) {
|
|
978
|
+
if (owner !== container && !container.contains(owner)) continue;
|
|
979
|
+
this.exitClones.delete(clone);
|
|
980
|
+
for (const animation of clone.getAnimations()) animation.cancel();
|
|
981
|
+
clone.remove();
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
964
985
|
/**
|
|
965
986
|
* Re-insert a visual clone of a removed element at its old position and
|
|
966
987
|
* play its transition backwards; the clone is dropped when done.
|
|
967
988
|
*/
|
|
968
989
|
exit(rec: RemovedRecord, animation: Animation | undefined): HTMLElement | null {
|
|
969
990
|
const parent = rec.ancestors[0] ?? null;
|
|
991
|
+
// The element it left has gone itself since (a later pass in the same
|
|
992
|
+
// task popped the screen): nothing is left to leave from.
|
|
993
|
+
if (parent && !parent.isConnected) return null;
|
|
970
994
|
const end = transitionStart(rec.transition ?? implicitTransitionOf(rec.el, parent), true);
|
|
971
995
|
if (isIdentity(end) || !rec.rect) return null;
|
|
972
996
|
const clone = ghostClone(rec.el);
|
|
@@ -999,7 +1023,11 @@ export class Animator {
|
|
|
999
1023
|
}
|
|
1000
1024
|
const timing = baseTiming(timingFor(animation));
|
|
1001
1025
|
const anim = clone.animate([from, to], { ...timing, fill: 'forwards' });
|
|
1002
|
-
|
|
1026
|
+
if (parent) this.exitClones.set(clone, parent);
|
|
1027
|
+
const done = (): void => {
|
|
1028
|
+
this.exitClones.delete(clone);
|
|
1029
|
+
clone.remove();
|
|
1030
|
+
};
|
|
1003
1031
|
anim.finished.then(done, done);
|
|
1004
1032
|
window.setTimeout(done, timing.duration + timing.delay + 100);
|
|
1005
1033
|
return clone;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host's JavaScript as SwiftBrowser Native's engine (docs/native.md,
|
|
3
|
+
* "The round trip"): for a module built with the round-trip target
|
|
4
|
+
* (`Native/RoundTrip`, the native views compiled against the shim), this
|
|
5
|
+
* answers its one import, `sb_native.request`, and exposes the native
|
|
6
|
+
* functions Swift installs (`applyOps`, `log`, `now`, …) on `__sbNative`,
|
|
7
|
+
* each a call of the module's `sb_native_invoke` export.
|
|
8
|
+
*
|
|
9
|
+
* The page (wasm.ts, for a module that imports `sb_native`) and Node
|
|
10
|
+
* (scripts/run-wasi.mjs) use it the same way: merge `imports` into the
|
|
11
|
+
* module's imports, instantiate, then `attach` the instance. Strings cross
|
|
12
|
+
* linear memory as UTF-8; an answer to Swift is a buffer from `sb_alloc`
|
|
13
|
+
* holding a little-endian 4-byte length and the bytes, which Swift frees,
|
|
14
|
+
* and a result from Swift is the same layout, freed with `sb_native_free`
|
|
15
|
+
* once read. `@swiftbrowser/native/wasm-host` re-exports it.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export interface WasmNativeHostOptions {
|
|
19
|
+
/** Runs a script at the global scope (default: an indirect `eval`). */
|
|
20
|
+
evaluate?: (script: string, name: string) => void;
|
|
21
|
+
/** The global object the bundle's globals live on (default `globalThis`). */
|
|
22
|
+
global?: Record<string, unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* Called after each installed function ran, with its name: the page runs
|
|
25
|
+
* the module's executor after an `applyOps` that came from the page's own
|
|
26
|
+
* loop (a fetch's answer, a timer), which no event follows.
|
|
27
|
+
*/
|
|
28
|
+
afterInvoke?: (name: string) => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface WasmNativeHost {
|
|
32
|
+
/** Merge into the module's import object before instantiating. */
|
|
33
|
+
imports: {
|
|
34
|
+
sb_native: {
|
|
35
|
+
request: (kind: number, kindLength: number, a: number, aLength: number, b: number, bLength: number) => number;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
/** The instance, once instantiated: its memory and the exports the host calls. */
|
|
39
|
+
attach(instance: NativeInstance): void;
|
|
40
|
+
/** The `__sbNative` object as it stands (replaced by a reset). */
|
|
41
|
+
readonly native: Record<string, (...args: unknown[]) => unknown>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** A `WebAssembly.Instance` (typed structurally: the Node build has no DOM lib). */
|
|
45
|
+
export interface NativeInstance {
|
|
46
|
+
exports: object;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface Exports {
|
|
50
|
+
memory: { buffer: ArrayBuffer };
|
|
51
|
+
sb_alloc: (length: number) => number;
|
|
52
|
+
sb_native_invoke: (name: number, nameLength: number, args: number, argsLength: number) => number;
|
|
53
|
+
sb_native_free: (pointer: number) => void;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The globals a bundle defines, dropped by a reset (`JSHost.reset`). */
|
|
57
|
+
const BUNDLE_GLOBALS = ['__sbDispatch', '__sbTimerFired', '__sbFetchResult', '__sbRefresh', '__sbVendor'];
|
|
58
|
+
|
|
59
|
+
export function wasmNativeHost(options: WasmNativeHostOptions = {}): WasmNativeHost {
|
|
60
|
+
const g = options.global ?? (globalThis as unknown as Record<string, unknown>);
|
|
61
|
+
const evaluate = options.evaluate ?? ((script: string) => (0, eval)(script));
|
|
62
|
+
const encoder = new TextEncoder();
|
|
63
|
+
const decoder = new TextDecoder();
|
|
64
|
+
let exports: Exports | null = null;
|
|
65
|
+
let native: Record<string, (...args: unknown[]) => unknown> = {};
|
|
66
|
+
|
|
67
|
+
const need = (): Exports => {
|
|
68
|
+
if (!exports) throw new Error('wasmNativeHost: attach(instance) before the module runs');
|
|
69
|
+
return exports;
|
|
70
|
+
};
|
|
71
|
+
const read = (pointer: number, length: number): string =>
|
|
72
|
+
decoder.decode(new Uint8Array(need().memory.buffer, pointer, length));
|
|
73
|
+
/** A buffer from `sb_alloc` with the text's length and bytes; Swift frees it. */
|
|
74
|
+
const answer = (value: unknown): number => {
|
|
75
|
+
const bytes = encoder.encode(JSON.stringify(value));
|
|
76
|
+
const pointer = need().sb_alloc(bytes.length + 4);
|
|
77
|
+
// The allocation may have grown the memory: take the view after it.
|
|
78
|
+
const view = new DataView(need().memory.buffer);
|
|
79
|
+
view.setUint32(pointer, bytes.length, true);
|
|
80
|
+
new Uint8Array(need().memory.buffer, pointer + 4, bytes.length).set(bytes);
|
|
81
|
+
return pointer;
|
|
82
|
+
};
|
|
83
|
+
const describe = (error: unknown): string => (error instanceof Error ? (error.stack ?? error.message) : String(error));
|
|
84
|
+
|
|
85
|
+
/** A native function's call: into Swift and back with its JSON result. */
|
|
86
|
+
const invoke = (name: string, args: unknown[]): unknown => {
|
|
87
|
+
try {
|
|
88
|
+
return call(name, args);
|
|
89
|
+
} finally {
|
|
90
|
+
options.afterInvoke?.(name);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const call = (name: string, args: unknown[]): unknown => {
|
|
94
|
+
const nameBytes = encoder.encode(name);
|
|
95
|
+
const argsBytes = encoder.encode(JSON.stringify(args));
|
|
96
|
+
const namePointer = need().sb_alloc(nameBytes.length || 1);
|
|
97
|
+
new Uint8Array(need().memory.buffer, namePointer, nameBytes.length).set(nameBytes);
|
|
98
|
+
const argsPointer = need().sb_alloc(argsBytes.length || 1);
|
|
99
|
+
new Uint8Array(need().memory.buffer, argsPointer, argsBytes.length).set(argsBytes);
|
|
100
|
+
const result = need().sb_native_invoke(namePointer, nameBytes.length, argsPointer, argsBytes.length);
|
|
101
|
+
if (result === 0) return undefined;
|
|
102
|
+
const length = new DataView(need().memory.buffer).getUint32(result, true);
|
|
103
|
+
const text = read(result + 4, length);
|
|
104
|
+
need().sb_native_free(result);
|
|
105
|
+
const value: unknown = JSON.parse(text);
|
|
106
|
+
if (value && typeof value === 'object' && 'error' in value && Object.keys(value).length === 1) {
|
|
107
|
+
throw new Error(String((value as { error: unknown }).error));
|
|
108
|
+
}
|
|
109
|
+
return value;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const reset = (): void => {
|
|
113
|
+
for (const name of BUNDLE_GLOBALS) delete g[name];
|
|
114
|
+
native = {};
|
|
115
|
+
g['__sbNative'] = native;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const request = (kind: number, kindLength: number, a: number, aLength: number, b: number, bLength: number): number => {
|
|
119
|
+
const what = read(kind, kindLength);
|
|
120
|
+
const first = read(a, aLength);
|
|
121
|
+
const second = read(b, bLength);
|
|
122
|
+
switch (what) {
|
|
123
|
+
case 'reset':
|
|
124
|
+
reset();
|
|
125
|
+
return 0;
|
|
126
|
+
case 'install':
|
|
127
|
+
native[first] = (...args: unknown[]) => invoke(first, args);
|
|
128
|
+
return 0;
|
|
129
|
+
case 'eval':
|
|
130
|
+
try {
|
|
131
|
+
evaluate(first, second);
|
|
132
|
+
return 0;
|
|
133
|
+
} catch (error) {
|
|
134
|
+
return answer({ error: describe(error) });
|
|
135
|
+
}
|
|
136
|
+
case 'call': {
|
|
137
|
+
const fn = g[first];
|
|
138
|
+
if (typeof fn !== 'function') return answer({ error: `${first} is not defined` });
|
|
139
|
+
try {
|
|
140
|
+
const result: unknown = (fn as (...args: unknown[]) => unknown)(...(JSON.parse(second) as unknown[]));
|
|
141
|
+
return answer({ ok: result === undefined ? null : result });
|
|
142
|
+
} catch (error) {
|
|
143
|
+
return answer({ error: describe(error) });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
case 'has':
|
|
147
|
+
return answer({ ok: first in g });
|
|
148
|
+
default:
|
|
149
|
+
return answer({ error: `unknown request ${what}` });
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
reset();
|
|
154
|
+
return {
|
|
155
|
+
imports: { sb_native: { request } },
|
|
156
|
+
attach(instance) {
|
|
157
|
+
for (const name of ['memory', 'sb_alloc', 'sb_native_invoke', 'sb_native_free']) {
|
|
158
|
+
if (!(name in instance.exports)) throw new Error(`wasmNativeHost: the module does not export ${name}`);
|
|
159
|
+
}
|
|
160
|
+
exports = instance.exports as unknown as Exports;
|
|
161
|
+
},
|
|
162
|
+
get native() {
|
|
163
|
+
return native;
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
package/src/renderer.ts
CHANGED
|
@@ -2231,6 +2231,8 @@ export class Renderer {
|
|
|
2231
2231
|
const el = this.elements.get(id);
|
|
2232
2232
|
if (!el) throw new RendererError(`Cannot remove unknown element ${id}`, op);
|
|
2233
2233
|
const parent = el.parentElement;
|
|
2234
|
+
// Clones of what left this subtree earlier (a bar group's, src/animation.ts) go with it.
|
|
2235
|
+
this.animator.dropExitClonesIn(el);
|
|
2234
2236
|
const stack = parent?.classList.contains('sb-navstack-screens')
|
|
2235
2237
|
? parent.parentElement
|
|
2236
2238
|
: null;
|
package/src/wasm.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { HOME, HOME_ENVIRONMENT, TMP, homeDirectory } from './appFiles';
|
|
|
15
15
|
import { zoneInfoEntries } from './zoneinfo';
|
|
16
16
|
import { base64Encode } from './base64';
|
|
17
17
|
import { performHostRequest, type HostRequestEnvironment } from './hostRequests';
|
|
18
|
+
import { wasmNativeHost } from './nativeHost';
|
|
18
19
|
import { isOp, type ElementId, type Op, type RendererEvent, type RequestOp, type SwiftDataOp } from './protocol';
|
|
19
20
|
|
|
20
21
|
export type OpsSink = (ops: Op[]) => void;
|
|
@@ -274,9 +275,41 @@ export async function loadApp(
|
|
|
274
275
|
};
|
|
275
276
|
}
|
|
276
277
|
|
|
278
|
+
// A native app's engine: the bundle it evaluates runs at the page's global
|
|
279
|
+
// scope, as `run-wasi.mjs` runs it at Node's. A pass the app applies from
|
|
280
|
+
// the page's own loop (a fetch's answer, a timer) mutates the tree the
|
|
281
|
+
// native views observe; the executor runs after it so the shim draws the
|
|
282
|
+
// change, as it runs after an event. Inside an event or a run it waits
|
|
283
|
+
// for that to end (the executor is not re-entered).
|
|
284
|
+
let hostDepth = 0;
|
|
285
|
+
let kickWanted = false;
|
|
286
|
+
let kick: (() => void) | null = null;
|
|
287
|
+
const guarded = <T>(work: () => T): T => {
|
|
288
|
+
hostDepth++;
|
|
289
|
+
try {
|
|
290
|
+
return work();
|
|
291
|
+
} finally {
|
|
292
|
+
hostDepth--;
|
|
293
|
+
if (hostDepth === 0 && kickWanted) {
|
|
294
|
+
kickWanted = false;
|
|
295
|
+
kick?.();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
const nativeHost = importsNativeHost(module)
|
|
300
|
+
? wasmNativeHost({
|
|
301
|
+
afterInvoke: (name) => {
|
|
302
|
+
if (name !== 'applyOps' || !kick) return;
|
|
303
|
+
if (hostDepth > 0) kickWanted = true;
|
|
304
|
+
else kick();
|
|
305
|
+
},
|
|
306
|
+
})
|
|
307
|
+
: null;
|
|
277
308
|
const instance = await WebAssembly.instantiate(module, {
|
|
278
309
|
[WASI_MODULE]: wasi.wasiImport,
|
|
310
|
+
...(nativeHost ? nativeHost.imports : {}),
|
|
279
311
|
});
|
|
312
|
+
nativeHost?.attach(instance);
|
|
280
313
|
const exports = instance.exports as unknown as SwiftBrowserExports;
|
|
281
314
|
for (const name of REQUIRED_EXPORTS) {
|
|
282
315
|
if (!(name in exports)) {
|
|
@@ -357,13 +390,15 @@ export async function loadApp(
|
|
|
357
390
|
// Phase 4: the executor runs after the first ops and after every event; the
|
|
358
391
|
// scheduler's own timer covers sleeps and clocks in between.
|
|
359
392
|
const scheduler = supportsJobs ? new JobScheduler((now) => exports.sb_run_jobs!(now), drain) : null;
|
|
360
|
-
const runJobs = (): number | null => (scheduler ? scheduler.kick() : null);
|
|
393
|
+
const runJobs = (): number | null => guarded(() => (scheduler ? scheduler.kick() : null));
|
|
394
|
+
if (nativeHost) kick = () => runJobs();
|
|
361
395
|
|
|
362
|
-
const sendEvent = (id: ElementId): void =>
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
396
|
+
const sendEvent = (id: ElementId): void =>
|
|
397
|
+
guarded(() => {
|
|
398
|
+
exports.sb_event(id | 0);
|
|
399
|
+
drain();
|
|
400
|
+
runJobs();
|
|
401
|
+
});
|
|
367
402
|
|
|
368
403
|
/** `bytes` in linear memory for the next event (`sb_bytes`), as the event names them. */
|
|
369
404
|
const putBytes = (bytes: Uint8Array): { $bytes: number } | string => {
|
|
@@ -383,10 +418,12 @@ export async function loadApp(
|
|
|
383
418
|
// `{"$bytes": n}` in the event, or as base64 for a module without `sb_bytes`.
|
|
384
419
|
const json = event.type === 'response' ? JSON.stringify(event, (_key, value: unknown) => (value instanceof Uint8Array ? putBytes(value) : value)) : JSON.stringify(event);
|
|
385
420
|
const bytes = encoder.encode(json);
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
421
|
+
guarded(() => {
|
|
422
|
+
const ptr = writeBytes(exports, bytes);
|
|
423
|
+
exports.sb_event_json!(ptr, bytes.byteLength);
|
|
424
|
+
drain();
|
|
425
|
+
runJobs();
|
|
426
|
+
});
|
|
390
427
|
return true;
|
|
391
428
|
};
|
|
392
429
|
deliver = sendEventJson;
|
|
@@ -490,17 +527,29 @@ export async function fetchParts(url: string, fetchImpl: typeof fetch = fetch):
|
|
|
490
527
|
return joined;
|
|
491
528
|
}
|
|
492
529
|
|
|
530
|
+
/**
|
|
531
|
+
* A SwiftBrowser Native app built for the browser (docs/native.md, "The round
|
|
532
|
+
* trip": the native views over the shim, with the host's JavaScript as the
|
|
533
|
+
* engine) imports `sb_native.request`; the page answers it (nativeHost.ts).
|
|
534
|
+
*/
|
|
535
|
+
const NATIVE_MODULE = 'sb_native';
|
|
536
|
+
|
|
493
537
|
function checkImports(module: WebAssembly.Module): void {
|
|
494
|
-
const foreign = WebAssembly.Module.imports(module).filter((i) => i.module !== WASI_MODULE);
|
|
538
|
+
const foreign = WebAssembly.Module.imports(module).filter((i) => i.module !== WASI_MODULE && i.module !== NATIVE_MODULE);
|
|
495
539
|
if (foreign.length > 0) {
|
|
496
540
|
const list = foreign.map((i) => `${i.module}.${i.name}`).join(', ');
|
|
497
541
|
throw new WasmLoadError(
|
|
498
542
|
`Module imports symbols outside ${WASI_MODULE}: ${list}. ` +
|
|
499
|
-
|
|
543
|
+
`The renderer only provides WASI preview1 (and ${NATIVE_MODULE} for a native app).`,
|
|
500
544
|
);
|
|
501
545
|
}
|
|
502
546
|
}
|
|
503
547
|
|
|
548
|
+
/** Whether the module runs a native app with the page's JavaScript as its engine. */
|
|
549
|
+
export function importsNativeHost(module: WebAssembly.Module): boolean {
|
|
550
|
+
return WebAssembly.Module.imports(module).some((i) => i.module === NATIVE_MODULE);
|
|
551
|
+
}
|
|
552
|
+
|
|
504
553
|
const decoder = new TextDecoder('utf-8', { fatal: true });
|
|
505
554
|
const encoder = new TextEncoder();
|
|
506
555
|
|