@standardagents/code-web 0.14.3-canary.6cc75f → 0.14.4-branch.9e48e914.ee06ef

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.
Files changed (37) hide show
  1. package/README.md +9 -1
  2. package/dist/build.json +1 -1
  3. package/dist/licenses/jco-transpile.txt +220 -0
  4. package/dist/manifest.json +1 -1
  5. package/dist/manifest.sig +1 -1
  6. package/dist/pkg/standard_web.d.ts +50 -12
  7. package/dist/pkg/standard_web.js +292 -20
  8. package/dist/pkg/standard_web_bg.wasm +0 -0
  9. package/dist/pkg/standard_web_bg.wasm.d.ts +17 -12
  10. package/dist/plugins/clock-cells/clock_cells.core.wasm +0 -0
  11. package/dist/plugins/clock-cells/clock_cells.wasm +0 -0
  12. package/dist/plugins/clock-cells/standard-plugin.json +11 -0
  13. package/dist/plugins/host/transpile.js +51 -0
  14. package/dist/plugins/host/ui-jspi.js +14851 -0
  15. package/dist/plugins/host/ui.core2.wasm +0 -0
  16. package/dist/plugins/host/ui.core3.wasm +0 -0
  17. package/dist/plugins/host/ui.js +14675 -0
  18. package/dist/plugins/host/world.js +172 -0
  19. package/dist/plugins/jco/cli.js +141 -0
  20. package/dist/plugins/jco/common.js +16 -0
  21. package/dist/plugins/jco/config.js +7 -0
  22. package/dist/plugins/jco/environment.js +24 -0
  23. package/dist/plugins/jco/filesystem.js +339 -0
  24. package/dist/plugins/jco/in-memory-filesystem.js +620 -0
  25. package/dist/plugins/jco/io.js +366 -0
  26. package/dist/plugins/jco/js-component-bindgen-component.core.wasm +0 -0
  27. package/dist/plugins/jco/js-component-bindgen-component.core2.wasm +0 -0
  28. package/dist/plugins/jco/js-component-bindgen-component.js +14272 -0
  29. package/dist/plugins/jco/opfs-filesystem.js +245 -0
  30. package/dist/plugins/jco/random.js +51 -0
  31. package/dist/plugins/plasma-pixels/plasma_pixels.core.wasm +0 -0
  32. package/dist/plugins/plasma-pixels/plasma_pixels.wasm +0 -0
  33. package/dist/plugins/plasma-pixels/standard-plugin.json +11 -0
  34. package/dist/plugins/runtime.js +1044 -0
  35. package/dist/plugins/samples.json +81 -0
  36. package/dist/plugins/worker.js +411 -0
  37. package/package.json +8 -2
@@ -0,0 +1,172 @@
1
+ // Instantiating a plugin's core module against the `ui-plugin` world with
2
+ // glue our own build produced (docs/plugin-runtime.md, "The browser
3
+ // runtime").
4
+ //
5
+ // jco's glue for a component is JavaScript generated from that component:
6
+ // its trampolines depend on which imports the component uses and how its
7
+ // core modules are wired. Running a plugin author's glue, or glue generated
8
+ // in the page from the author's component, would run JavaScript the viewer's
9
+ // build did not produce, which the Worker policy (`script-src 'self'`)
10
+ // forbids. So the build transpiles a *reference* component instead: a dummy
11
+ // core module wit-component makes from `wit/standard-plugin` alone that
12
+ // imports every function of the world and exports every export. Its glue
13
+ // (`ui.js`, and `ui-jspi.js` for JSPI) and its two small wit-component
14
+ // shim modules (`ui.core2.wasm`, `ui.core3.wasm`: the indirect-call table
15
+ // and its fix-up) are fixed files of the viewer's bundle.
16
+ //
17
+ // A plugin contributes exactly one core module: the one of its component
18
+ // that exports the world (`selectMain`). `instantiatePlugin` hands the glue
19
+ // that module in place of the reference one, translating import and export
20
+ // names between the legacy wit-component names our SDK emits
21
+ // (`standard:plugin/surface@2.0.0` / `attach`, `activate`, `cabi_realloc`,
22
+ // `cabi_post_frame`) and the standard names the reference module uses
23
+ // (`cm32p2|standard:plugin/surface@2` / `attach`, `cm32p2||activate`,
24
+ // `cm32p2_realloc`, `cm32p2||frame_post`). The canonical ABI makes both
25
+ // sides' core signatures a function of the WIT alone, and the wasm engine
26
+ // type-checks every import that links to a shim export, so a module that
27
+ // imports anything outside the world, or a world function at another type,
28
+ // fails at instantiation and runs nothing.
29
+
30
+ /** The world's exports, in the plugin's (legacy) spelling. */
31
+ export const WORLD_EXPORTS = ['activate', 'frame', 'event', 'deactivate']
32
+
33
+ /** Imports that wait for the account: async under JSPI, answered from the
34
+ * Worker's mirror (or refused) without it. jco's `asyncImports` names. */
35
+ export const ACCOUNT_IMPORTS = [
36
+ 'standard:plugin/values@2.0.0#get',
37
+ 'standard:plugin/values@2.0.0#set',
38
+ 'standard:plugin/values@2.0.0#delete',
39
+ 'standard:plugin/values@2.0.0#keys',
40
+ 'standard:plugin/live@2.0.0#publish',
41
+ 'standard:plugin/live@2.0.0#delete',
42
+ 'standard:plugin/live@2.0.0#subscribe',
43
+ 'standard:plugin/live@2.0.0#unsubscribe',
44
+ 'standard:plugin/events@2.0.0#emit',
45
+ 'standard:plugin/events@2.0.0#on',
46
+ 'standard:plugin/events@2.0.0#off',
47
+ 'standard:plugin/calls@2.0.0#call',
48
+ 'standard:plugin/claims@2.0.0#claim',
49
+ 'standard:plugin/secrets@2.0.0#get',
50
+ ]
51
+
52
+ /** The reference component's file names (`name: 'ui'` at build time). */
53
+ export const REFERENCE = { main: 'ui.core.wasm', shims: ['ui.core2.wasm', 'ui.core3.wasm'] }
54
+
55
+ const STANDARD = 'cm32p2|'
56
+
57
+ /** A semver's canonical form in standard names: `2.0.0` -> `2`,
58
+ * `0.3.1` -> `0.3`, `0.0.4` -> `0.0.4`. */
59
+ function canonicalVersion(version) {
60
+ const [major, minor, patch] = version.split('.').map(part => Number.parseInt(part, 10))
61
+ if (major) return `${major}`
62
+ if (minor) return `0.${minor}`
63
+ return `0.0.${patch}`
64
+ }
65
+
66
+ /** An import module name in the standard spelling. */
67
+ export function standardModule(name) {
68
+ if (name.startsWith(STANDARD)) return name
69
+ const at = name.lastIndexOf('@')
70
+ if (at < 0) return `${STANDARD}${name}`
71
+ return `${STANDARD}${name.slice(0, at)}@${canonicalVersion(name.slice(at + 1))}`
72
+ }
73
+
74
+ function exportNames(module) {
75
+ return new Set(WebAssembly.Module.exports(module).map(entry => entry.name))
76
+ }
77
+
78
+ /** Whether a core module exports the whole world, in either spelling. */
79
+ function exportsWorld(names) {
80
+ const legacy = names.has('memory') && names.has('cabi_realloc') && WORLD_EXPORTS.every(name => names.has(name))
81
+ const standard = names.has(`${STANDARD.slice(0, -1)}_memory`) && names.has(`${STANDARD.slice(0, -1)}_realloc`)
82
+ && WORLD_EXPORTS.every(name => names.has(`${STANDARD}|${name}`))
83
+ return legacy || standard
84
+ }
85
+
86
+ /** The one core module of a component that exports the world. */
87
+ export function selectMain(modules) {
88
+ const found = modules.filter(module => exportsWorld(exportNames(module)))
89
+ if (found.length !== 1) {
90
+ throw new Error(`the component has ${found.length} core modules that export the ui-plugin world; exactly one must`)
91
+ }
92
+ return found[0]
93
+ }
94
+
95
+ /**
96
+ * Refuses a main module that imports anything the world does not provide.
97
+ * `provided` is the standard-named import object the reference glue builds
98
+ * (or any object with the same keys).
99
+ */
100
+ export function checkImports(main, provided) {
101
+ for (const entry of WebAssembly.Module.imports(main)) {
102
+ const module = standardModule(entry.module)
103
+ if (entry.kind !== 'function' || typeof provided[module]?.[entry.name] !== 'function') {
104
+ throw new Error(`the plugin imports ${entry.module}#${entry.name}, which is outside the ui-plugin world`)
105
+ }
106
+ }
107
+ }
108
+
109
+ /** The world's import names, as the reference glue provides them. */
110
+ export function worldImportNames(referenceMain) {
111
+ const provided = {}
112
+ for (const entry of WebAssembly.Module.imports(referenceMain)) {
113
+ ;(provided[entry.module] ??= {})[entry.name] = () => {}
114
+ }
115
+ return provided
116
+ }
117
+
118
+ /** The main module's exports as the reference glue reads them. */
119
+ function standardExports(exports) {
120
+ if (exports[`${STANDARD.slice(0, -1)}_memory`]) {
121
+ const out = { ...exports }
122
+ out.cm32p2_initialize ??= () => {}
123
+ for (const name of WORLD_EXPORTS) out[`${STANDARD}|${name}_post`] ??= () => {}
124
+ return out
125
+ }
126
+ const out = {
127
+ cm32p2_memory: exports.memory,
128
+ cm32p2_realloc: exports.cabi_realloc,
129
+ // wit-component calls `_initialize` when a module has one.
130
+ cm32p2_initialize: exports._initialize ?? (() => {}),
131
+ }
132
+ for (const name of WORLD_EXPORTS) {
133
+ out[`${STANDARD}|${name}`] = exports[name]
134
+ // A module without a post-return function needs none: nothing the
135
+ // export returns was allocated for the caller.
136
+ out[`${STANDARD}|${name}_post`] = exports[`cabi_post_${name}`] ?? (() => {})
137
+ }
138
+ return out
139
+ }
140
+
141
+ /**
142
+ * Instantiates `main` (the plugin's core module) through the reference
143
+ * glue. `glue` is `ui.js` or `ui-jspi.js`; `shims` maps the reference shim
144
+ * file names to their compiled modules; `imports` is the host import object
145
+ * (runtime.js's `PluginHost.imports()`). `wrap(module, name, fn)` may wrap
146
+ * one core import (the Worker records `attach`'s region address). Returns
147
+ * the component's exports and the plugin's linear memory.
148
+ */
149
+ export function instantiatePlugin({ glue, shims, main, imports, wrap = (_module, _name, fn) => fn }) {
150
+ const reference = {}
151
+ let memory = null
152
+ const instance = glue.instantiate((name) => {
153
+ if (name === REFERENCE.main) return reference
154
+ const module = shims[name]
155
+ if (!module) throw new Error(`the world glue asked for an unknown core module ${name}`)
156
+ return module
157
+ }, imports, (module, importObject) => {
158
+ if (module !== reference) return new WebAssembly.Instance(module, importObject)
159
+ checkImports(main, importObject)
160
+ const linked = {}
161
+ for (const entry of WebAssembly.Module.imports(main)) {
162
+ const standard = standardModule(entry.module)
163
+ const fn = importObject[standard][entry.name]
164
+ ;(linked[entry.module] ??= {})[entry.name] = wrap(standard, entry.name, fn)
165
+ }
166
+ const exports = new WebAssembly.Instance(main, linked).exports
167
+ memory = exports.memory ?? exports.cm32p2_memory
168
+ return { exports: standardExports(exports) }
169
+ })
170
+ if (instance instanceof Promise) throw new Error('the world glue instantiated asynchronously')
171
+ return { instance, memory: () => memory }
172
+ }
@@ -0,0 +1,141 @@
1
+ import { inputStreamCreate, outputStreamCreate, pollableCreate, } from "./io.js";
2
+ export { _setEnv, _setArgs, environment } from "./environment.js";
3
+ export { _setCwd } from "./config.js";
4
+ const symbolDispose = Symbol.dispose ?? Symbol.for("dispose");
5
+ class ComponentExit extends Error {
6
+ exitError = true;
7
+ code;
8
+ constructor(code) {
9
+ super(`Component exited ${code === 0 ? "successfully" : "with error"}`);
10
+ this.code = code;
11
+ }
12
+ }
13
+ export const exit = {
14
+ exit(status) {
15
+ throw new ComponentExit(status.tag === "err" ? 1 : 0);
16
+ },
17
+ // @ts-expect-error - Available only wasi-cli v0.2.12
18
+ exitWithCode(code) {
19
+ throw new ComponentExit(code);
20
+ },
21
+ };
22
+ export function _setStdin(handler) {
23
+ stdinStream.handler = handler;
24
+ }
25
+ export function _setStderr(handler) {
26
+ stderrStream.handler = handler;
27
+ }
28
+ export function _setStdout(handler) {
29
+ stdoutStream.handler = handler;
30
+ }
31
+ const stdinStream = inputStreamCreate({
32
+ blockingRead() {
33
+ throw { tag: "closed" };
34
+ },
35
+ subscribe() {
36
+ return pollableCreate();
37
+ },
38
+ [symbolDispose]() { },
39
+ });
40
+ function consoleStream(writeLine) {
41
+ const decoder = new TextDecoder();
42
+ let pending = "";
43
+ const emitCompleteLines = () => {
44
+ const lines = pending.split("\n");
45
+ pending = lines.pop();
46
+ for (const line of lines) {
47
+ writeLine(line.endsWith("\r") ? line.slice(0, -1) : line);
48
+ }
49
+ };
50
+ return {
51
+ write(contents) {
52
+ pending += decoder.decode(contents, { stream: true });
53
+ emitCompleteLines();
54
+ },
55
+ flush() {
56
+ pending += decoder.decode();
57
+ if (pending) {
58
+ writeLine(pending);
59
+ }
60
+ pending = "";
61
+ },
62
+ blockingFlush() {
63
+ this.flush?.();
64
+ },
65
+ drop() {
66
+ this.flush?.();
67
+ },
68
+ };
69
+ }
70
+ const stdoutStream = outputStreamCreate(consoleStream((line) => console.log(line)));
71
+ const stderrStream = outputStreamCreate(consoleStream((line) => console.error(line)));
72
+ export const stdin = {
73
+ getStdin() {
74
+ return stdinStream;
75
+ },
76
+ };
77
+ export const stdout = {
78
+ getStdout() {
79
+ return stdoutStream;
80
+ },
81
+ };
82
+ export const stderr = {
83
+ getStderr() {
84
+ return stderrStream;
85
+ },
86
+ };
87
+ class TerminalInput {
88
+ }
89
+ class TerminalOutput {
90
+ }
91
+ export const terminalInput = {
92
+ TerminalInput,
93
+ };
94
+ export const terminalOutput = {
95
+ TerminalOutput,
96
+ };
97
+ export const terminalStderr = {
98
+ getTerminalStderr() {
99
+ return undefined;
100
+ },
101
+ };
102
+ export const terminalStdin = {
103
+ getTerminalStdin() {
104
+ return undefined;
105
+ },
106
+ };
107
+ export const terminalStdout = {
108
+ getTerminalStdout() {
109
+ return undefined;
110
+ },
111
+ };
112
+ /** Create isolated browser CLI interfaces without changing compatibility globals. */
113
+ export function createCli(config = {}) {
114
+ const stdinInstance = inputStreamCreate(config.stdin ?? {
115
+ blockingRead() {
116
+ throw { tag: "closed" };
117
+ },
118
+ subscribe: () => pollableCreate(),
119
+ });
120
+ const stdoutInstance = outputStreamCreate(config.stdout ?? consoleStream((line) => console.log(line)));
121
+ const stderrInstance = outputStreamCreate(config.stderr ?? consoleStream((line) => console.error(line)));
122
+ const env = Object.entries(config.environment ?? {});
123
+ const args = [...(config.arguments ?? [])];
124
+ const cwd = config.initialCwd ?? "/";
125
+ return {
126
+ environment: {
127
+ getEnvironment: () => env.map(([key, value]) => [key, value]),
128
+ getArguments: () => [...args],
129
+ initialCwd: () => cwd,
130
+ },
131
+ exit,
132
+ stdin: { getStdin: () => stdinInstance },
133
+ stdout: { getStdout: () => stdoutInstance },
134
+ stderr: { getStderr: () => stderrInstance },
135
+ terminalInput,
136
+ terminalOutput,
137
+ terminalStdin,
138
+ terminalStdout,
139
+ terminalStderr,
140
+ };
141
+ }
@@ -0,0 +1,16 @@
1
+ export const MAX_U64 = (1n << 64n) - 1n;
2
+ /** Validate and return a WebAssembly u64 value. */
3
+ export function checkedU64(value, name) {
4
+ if (typeof value !== "bigint" || value < 0n || value > MAX_U64) {
5
+ throw new TypeError(`${name} must be a valid u64`);
6
+ }
7
+ return value;
8
+ }
9
+ /** Convert a WebAssembly u64 value to a lossless JavaScript number. */
10
+ export function checkedU64AsNumber(value, name) {
11
+ checkedU64(value, name);
12
+ if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
13
+ throw new RangeError(`${name} exceeds JavaScript's safe integer range`);
14
+ }
15
+ return Number(value);
16
+ }
@@ -0,0 +1,7 @@
1
+ let _cwd = "/";
2
+ export function _setCwd(cwd) {
3
+ _cwd = cwd;
4
+ }
5
+ export function _getCwd() {
6
+ return _cwd;
7
+ }
@@ -0,0 +1,24 @@
1
+ import { _setCwd as fsSetCwd } from "./config.js";
2
+ let _env = [];
3
+ let _args = [];
4
+ let _cwd = "/";
5
+ export function _setEnv(envObj) {
6
+ _env = Object.entries(envObj);
7
+ }
8
+ export function _setArgs(args) {
9
+ _args = args;
10
+ }
11
+ export function _setCwd(cwd) {
12
+ fsSetCwd((_cwd = cwd));
13
+ }
14
+ export const environment = {
15
+ getEnvironment() {
16
+ return _env;
17
+ },
18
+ getArguments() {
19
+ return _args;
20
+ },
21
+ initialCwd() {
22
+ return _cwd;
23
+ },
24
+ };
@@ -0,0 +1,339 @@
1
+ import { environment } from "./environment.js";
2
+ import { InMemoryFilesystemAdapter } from "./in-memory-filesystem.js";
3
+ import { _setCwd } from "./config.js";
4
+ export { _setCwd } from "./config.js";
5
+ export { InMemoryFilesystemAdapter } from "./in-memory-filesystem.js";
6
+ export { OpfsFilesystemAdapter, loadOpfsCapability } from "./opfs-filesystem.js";
7
+ class DirectoryEntryStream {
8
+ #implementation;
9
+ static _create(implementation) {
10
+ const stream = new DirectoryEntryStream();
11
+ stream.#implementation = implementation;
12
+ return stream;
13
+ }
14
+ readDirectoryEntry() {
15
+ return this.#implementation.readDirectoryEntry();
16
+ }
17
+ }
18
+ const directoryEntryStreamCreate = DirectoryEntryStream._create;
19
+ // @ts-expect-error - Deleting static method
20
+ delete DirectoryEntryStream._create;
21
+ class Descriptor {
22
+ #implementation;
23
+ _getImplementation(descriptor) {
24
+ return descriptor.#implementation;
25
+ }
26
+ static _create(implementation) {
27
+ const descriptor = new Descriptor();
28
+ descriptor.#implementation = implementation;
29
+ return descriptor;
30
+ }
31
+ readViaStream(offset) {
32
+ return this.#implementation.readViaStream(offset);
33
+ }
34
+ writeViaStream(offset) {
35
+ return this.#implementation.writeViaStream(offset);
36
+ }
37
+ appendViaStream() {
38
+ return this.#implementation.appendViaStream();
39
+ }
40
+ advise(offset, length, advice) {
41
+ return this.#implementation.advise(offset, length, advice);
42
+ }
43
+ syncData() {
44
+ return this.#implementation.syncData();
45
+ }
46
+ getFlags() {
47
+ return this.#implementation.getFlags();
48
+ }
49
+ getType() {
50
+ return this.#implementation.getType();
51
+ }
52
+ setSize(size) {
53
+ return this.#implementation.setSize(size);
54
+ }
55
+ setTimes(dataAccessTimestamp, dataModificationTimestamp) {
56
+ return this.#implementation.setTimes(dataAccessTimestamp, dataModificationTimestamp);
57
+ }
58
+ read(length, offset) {
59
+ return this.#implementation.read(length, offset);
60
+ }
61
+ write(buffer, offset) {
62
+ return this.#implementation.write(buffer, offset);
63
+ }
64
+ readDirectory() {
65
+ return directoryEntryStreamCreate(this.#implementation.readDirectory());
66
+ }
67
+ sync() {
68
+ return this.#implementation.sync();
69
+ }
70
+ createDirectoryAt(path) {
71
+ return this.#implementation.createDirectoryAt(path);
72
+ }
73
+ stat() {
74
+ return this.#implementation.stat();
75
+ }
76
+ statAt(pathFlags, path) {
77
+ return this.#implementation.statAt(pathFlags, path);
78
+ }
79
+ setTimesAt(pathFlags, path, dataAccessTimestamp, dataModificationTimestamp) {
80
+ return this.#implementation.setTimesAt(pathFlags, path, dataAccessTimestamp, dataModificationTimestamp);
81
+ }
82
+ linkAt(oldPathFlags, oldPath, newDescriptor, newPath) {
83
+ return this.#implementation.linkAt(oldPathFlags, oldPath, descriptorGetImplementation(newDescriptor), newPath);
84
+ }
85
+ openAt(pathFlags, path, openFlags, flags) {
86
+ return descriptorCreate(this.#implementation.openAt(pathFlags, path, openFlags, flags));
87
+ }
88
+ readlinkAt(path) {
89
+ return this.#implementation.readlinkAt(path);
90
+ }
91
+ removeDirectoryAt(path) {
92
+ return this.#implementation.removeDirectoryAt(path);
93
+ }
94
+ renameAt(oldPath, newDescriptor, newPath) {
95
+ return this.#implementation.renameAt(oldPath, descriptorGetImplementation(newDescriptor), newPath);
96
+ }
97
+ symlinkAt(oldPath, newPath) {
98
+ return this.#implementation.symlinkAt(oldPath, newPath);
99
+ }
100
+ unlinkFileAt(path) {
101
+ return this.#implementation.unlinkFileAt(path);
102
+ }
103
+ isSameObject(other) {
104
+ return this.#implementation.isSameObject(descriptorGetImplementation(other));
105
+ }
106
+ metadataHash() {
107
+ return this.#implementation.metadataHash();
108
+ }
109
+ metadataHashAt(pathFlags, path) {
110
+ return this.#implementation.metadataHashAt(pathFlags, path);
111
+ }
112
+ lockShared() {
113
+ return this.#implementation.lockShared?.();
114
+ }
115
+ lockExclusive() {
116
+ return this.#implementation.lockExclusive?.();
117
+ }
118
+ tryLockShared() {
119
+ return this.#implementation.tryLockShared?.() ?? false;
120
+ }
121
+ tryLockExclusive() {
122
+ return this.#implementation.tryLockExclusive?.() ?? false;
123
+ }
124
+ unlock() {
125
+ return this.#implementation.unlock?.();
126
+ }
127
+ }
128
+ const descriptorGetImplementation = Descriptor.prototype._getImplementation;
129
+ // @ts-expect-error - Deleting prototype method
130
+ delete Descriptor.prototype._getImplementation;
131
+ const descriptorCreate = Descriptor._create;
132
+ // @ts-expect-error - Deleting static method
133
+ delete Descriptor._create;
134
+ const defaultAdapter = new InMemoryFilesystemAdapter();
135
+ let _fileData = { dir: {} };
136
+ let _preopens = [];
137
+ let _rootPreopen = null;
138
+ export const preopens = {
139
+ getDirectories() {
140
+ return _preopens;
141
+ },
142
+ };
143
+ /** Create isolated filesystem namespaces backed by an application-selected adapter. */
144
+ export function createFilesystem({ adapter, preopens: configuredPreopens, }) {
145
+ const entries = Object.entries(configuredPreopens).map(([guestPath, capability]) => [descriptorCreate(adapter.getRoot(capability)), guestPath]);
146
+ let disposed = false;
147
+ return {
148
+ types,
149
+ preopens: {
150
+ getDirectories() {
151
+ if (disposed) {
152
+ throw new Error("filesystem adapter has been disposed");
153
+ }
154
+ return [...entries];
155
+ },
156
+ },
157
+ dispose() {
158
+ if (disposed) {
159
+ return;
160
+ }
161
+ disposed = true;
162
+ adapter.dispose?.();
163
+ },
164
+ };
165
+ }
166
+ export function _setFileData(fileData) {
167
+ _fileData = fileData;
168
+ if (_rootPreopen) {
169
+ _rootPreopen[0] = descriptorCreate(defaultAdapter.getRoot(fileData));
170
+ }
171
+ else {
172
+ _setPreopens({ "/": fileData });
173
+ }
174
+ const cwd = environment.initialCwd();
175
+ _setCwd(cwd || "/");
176
+ }
177
+ export function _getFileData() {
178
+ return JSON.stringify(_fileData);
179
+ }
180
+ /**
181
+ * Replace all preopens with the given set.
182
+ * @param preopensConfig - Map of virtual paths to file data entries
183
+ */
184
+ export function _setPreopens(preopensConfig) {
185
+ _preopens = [];
186
+ _rootPreopen = null;
187
+ for (const [virtualPath, fileData] of Object.entries(preopensConfig)) {
188
+ _addPreopen(virtualPath, fileData);
189
+ }
190
+ }
191
+ /**
192
+ * Add a single preopen mapping.
193
+ * @param virtualPath - The virtual path visible to the guest
194
+ * @param fileData - The file data object representing the directory
195
+ */
196
+ export function _addPreopen(virtualPath, fileData) {
197
+ const descriptor = descriptorCreate(defaultAdapter.getRoot(fileData));
198
+ const entry = [descriptor, virtualPath];
199
+ _preopens.push(entry);
200
+ if (virtualPath === "/") {
201
+ _rootPreopen = entry;
202
+ }
203
+ }
204
+ /**
205
+ * Add a single preopen backed by a custom adapter (e.g. `OpfsFilesystemAdapter`) instead of the
206
+ * default in-memory one. Lets a host wire an alternative `BrowserFilesystemAdapter` into the
207
+ * top-level `wasi:filesystem/preopens` singleton that transpiled components import statically.
208
+ * @param virtualPath - The virtual path visible to the guest
209
+ * @param adapter - The adapter that will back this preopen
210
+ * @param capability - The adapter-specific capability to load as the preopen's root
211
+ */
212
+ export function _addPreopenWithAdapter(virtualPath, adapter, capability) {
213
+ const descriptor = descriptorCreate(adapter.getRoot(capability));
214
+ const entry = [descriptor, virtualPath];
215
+ _preopens.push(entry);
216
+ if (virtualPath === "/") {
217
+ _rootPreopen = entry;
218
+ }
219
+ }
220
+ /** Clear all preopens, giving the guest no filesystem access. */
221
+ export function _clearPreopens() {
222
+ _preopens = [];
223
+ _rootPreopen = null;
224
+ }
225
+ /** Get current preopens configuration. */
226
+ export function _getPreopens() {
227
+ return [..._preopens];
228
+ }
229
+ /** Reject host paths because browser filesystems require explicit capabilities. */
230
+ export function _createPreopenDescriptor(hostPreopen) {
231
+ throw new TypeError(`browser preopen ${JSON.stringify(hostPreopen)} is a host path; configure browser file data or an adapter instead`);
232
+ }
233
+ export const types = {
234
+ Descriptor,
235
+ DirectoryEntryStream,
236
+ filesystemErrorCode: (err) => {
237
+ let message;
238
+ if ("payload" in err) {
239
+ message = err.payload;
240
+ }
241
+ else if ("message" in err) {
242
+ message = err.message;
243
+ }
244
+ return convertFsError(message);
245
+ },
246
+ };
247
+ function convertFsError(e) {
248
+ switch (e.code) {
249
+ case "EACCES":
250
+ return "access";
251
+ case "EAGAIN":
252
+ case "EWOULDBLOCK":
253
+ return "would-block";
254
+ case "EALREADY":
255
+ return "already";
256
+ case "EBADF":
257
+ return "bad-descriptor";
258
+ case "EBUSY":
259
+ return "busy";
260
+ case "EDEADLK":
261
+ return "deadlock";
262
+ case "EDQUOT":
263
+ return "quota";
264
+ case "EEXIST":
265
+ return "exist";
266
+ case "EFBIG":
267
+ return "file-too-large";
268
+ case "EILSEQ":
269
+ return "illegal-byte-sequence";
270
+ case "EINPROGRESS":
271
+ return "in-progress";
272
+ case "EINTR":
273
+ return "interrupted";
274
+ case "EINVAL":
275
+ return "invalid";
276
+ case "EIO":
277
+ return "io";
278
+ case "EISDIR":
279
+ return "is-directory";
280
+ case "ELOOP":
281
+ return "loop";
282
+ case "EMLINK":
283
+ return "too-many-links";
284
+ case "EMSGSIZE":
285
+ return "message-size";
286
+ case "ENAMETOOLONG":
287
+ return "name-too-long";
288
+ case "ENODEV":
289
+ return "no-device";
290
+ case "ENOENT":
291
+ return "no-entry";
292
+ case "ENOLCK":
293
+ return "no-lock";
294
+ case "ENOMEM":
295
+ return "insufficient-memory";
296
+ case "ENOSPC":
297
+ return "insufficient-space";
298
+ case "ENOTDIR":
299
+ case "ERR_FS_EISDIR":
300
+ return "not-directory";
301
+ case "ENOTEMPTY":
302
+ return "not-empty";
303
+ case "ENOTRECOVERABLE":
304
+ return "not-recoverable";
305
+ case "ENOTSUP":
306
+ return "unsupported";
307
+ case "ENOTTY":
308
+ return "no-tty";
309
+ // windows gives this error for badly structured `//` reads
310
+ // this seems like a slightly better error than unknown given
311
+ // that it's a common footgun
312
+ case -4094:
313
+ case "ENXIO":
314
+ return "no-such-device";
315
+ case "EOVERFLOW":
316
+ return "overflow";
317
+ case "EPERM":
318
+ return "not-permitted";
319
+ case "EPIPE":
320
+ return "pipe";
321
+ case "EROFS":
322
+ return "read-only";
323
+ case "ESPIPE":
324
+ return "invalid-seek";
325
+ case "ETXTBSY":
326
+ return "text-file-busy";
327
+ case "EXDEV":
328
+ return "cross-device";
329
+ case "UNKNOWN":
330
+ switch (e.errno) {
331
+ case -4094:
332
+ return "no-such-device";
333
+ default:
334
+ throw e;
335
+ }
336
+ default:
337
+ throw e;
338
+ }
339
+ }