wasm-platform-kit 0.0.0-stage → 0.2.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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +224 -2
  3. package/assets/wasi/LICENSE +220 -0
  4. package/assets/wasi/cli.d.ts +43 -0
  5. package/assets/wasi/cli.js +147 -0
  6. package/assets/wasi/clocks.d.ts +3 -0
  7. package/assets/wasi/clocks.js +55 -0
  8. package/assets/wasi/common.d.ts +5 -0
  9. package/assets/wasi/common.js +16 -0
  10. package/assets/wasi/config.d.ts +2 -0
  11. package/assets/wasi/config.js +7 -0
  12. package/assets/wasi/environment.d.ts +5 -0
  13. package/assets/wasi/environment.js +24 -0
  14. package/assets/wasi/filesystem.d.ts +117 -0
  15. package/assets/wasi/filesystem.js +341 -0
  16. package/assets/wasi/helpers/cli.d.ts +7 -0
  17. package/assets/wasi/helpers/cli.js +25 -0
  18. package/assets/wasi/helpers/filesystem.d.ts +6 -0
  19. package/assets/wasi/helpers/filesystem.js +10 -0
  20. package/assets/wasi/http.d.ts +13 -0
  21. package/assets/wasi/http.js +953 -0
  22. package/assets/wasi/in-memory-filesystem.d.ts +38 -0
  23. package/assets/wasi/in-memory-filesystem.js +620 -0
  24. package/assets/wasi/in-memory-http.d.ts +8 -0
  25. package/assets/wasi/in-memory-http.js +11 -0
  26. package/assets/wasi/in-memory-sockets.d.ts +34 -0
  27. package/assets/wasi/in-memory-sockets.js +294 -0
  28. package/assets/wasi/index.d.ts +7 -0
  29. package/assets/wasi/index.js +7 -0
  30. package/assets/wasi/io.d.ts +67 -0
  31. package/assets/wasi/io.js +366 -0
  32. package/assets/wasi/opfs-filesystem.d.ts +52 -0
  33. package/assets/wasi/opfs-filesystem.js +262 -0
  34. package/assets/wasi/random.d.ts +4 -0
  35. package/assets/wasi/random.js +51 -0
  36. package/assets/wasi/sockets.d.ts +9 -0
  37. package/assets/wasi/sockets.js +85 -0
  38. package/browser.mjs +209 -0
  39. package/client.mjs +138 -0
  40. package/index.d.ts +199 -0
  41. package/install.d.ts +22 -0
  42. package/install.mjs +176 -0
  43. package/native-registration.mjs +70 -0
  44. package/node.mjs +332 -0
  45. package/package.json +66 -4
  46. package/policy.mjs +433 -0
  47. package/worker.mjs +389 -0
package/install.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type {HostOptions} from './index.js';
2
+
3
+ /** Trusted embedding package installation settings; guest manifests grant no authority. */
4
+ export interface InstallationOptions
5
+ {
6
+ directory: URL;
7
+ component: URL;
8
+ componentSha256: string;
9
+ prebuiltArtifacts?: HostOptions['nativeArtifacts'];
10
+ /** Defaults to WASM_PLATFORM_KIT_BUILD_FROM_SOURCE=1. */
11
+ fromSource?: boolean;
12
+ signal?: AbortSignal;
13
+ /** Installation-only deadline, at most 900000ms; guest execution limits are independent. */
14
+ timeout?: number;
15
+ }
16
+ export function prepareNative(options: InstallationOptions): Promise<{
17
+ preparation: 'prebuilt' | 'source';
18
+ componentSha256: string;
19
+ nativeSha256: string;
20
+ configuration: string;
21
+ target: string;
22
+ }>;
package/install.mjs ADDED
@@ -0,0 +1,176 @@
1
+ // Installation prepares executable artifacts. Runtime modules never import this module.
2
+ // ref:DEC-wpk-installation-preparation
3
+ import {execFile} from 'node:child_process';
4
+ import {createHash} from 'node:crypto';
5
+ import {createReadStream, createWriteStream} from 'node:fs';
6
+ import {pipeline} from 'node:stream/promises';
7
+ import {mkdir, mkdtemp, rename, rm, writeFile} from 'node:fs/promises';
8
+ import {createRequire} from 'node:module';
9
+ import {fileURLToPath} from 'node:url';
10
+ import path from 'node:path';
11
+ import {promisify} from 'node:util';
12
+ import {nativeConfiguration, nativeTargets} from './native-registration.mjs';
13
+
14
+ const require = createRequire(import.meta.url);
15
+ const execute = promisify(execFile);
16
+
17
+ /** Hashes streams with the same artifact bounds as the native helper. ref:DEC-wpk-installation-preparation */
18
+ async function digest(file, limit)
19
+ {
20
+ const hash = createHash('sha256');
21
+ let size = 0;
22
+ for await (const chunk of createReadStream(file))
23
+ {
24
+ size += chunk.length;
25
+ if (size > limit) throw new Error('Installation artifact size exhausted');
26
+ hash.update(chunk);
27
+ }
28
+ return hash.digest('hex');
29
+ }
30
+
31
+ /** Copies only bounded, pinned input into private installation staging. ref:DEC-wpk-installation-preparation */
32
+ async function snapshot(component, destination, expected, signal)
33
+ {
34
+ const hash = createHash('sha256');
35
+ let size = 0;
36
+ await pipeline(
37
+ createReadStream(component),
38
+ async function* (source)
39
+ {
40
+ for await (const chunk of source)
41
+ {
42
+ size += chunk.length;
43
+ if (size > 128 * 1024 * 1024)
44
+ throw new Error('Installation artifact size exhausted');
45
+ hash.update(chunk);
46
+ yield chunk;
47
+ }
48
+ },
49
+ createWriteStream(destination, {flags: 'wx', mode: 0o600}),
50
+ {signal},
51
+ );
52
+ if (hash.digest('hex') !== expected)
53
+ throw new Error('Portable component integrity mismatch');
54
+ }
55
+
56
+ /** Verifies a prebuilt artifact or compiles a pinned portable component during installation. ref:DEC-wpk-installation-preparation */
57
+ export async function prepareNative({
58
+ directory,
59
+ component,
60
+ componentSha256,
61
+ prebuiltArtifacts = {},
62
+ fromSource = process.env.WASM_PLATFORM_KIT_BUILD_FROM_SOURCE === '1',
63
+ signal,
64
+ timeout = 15 * 60 * 1000,
65
+ })
66
+ {
67
+ const platform = `${process.platform}-${process.arch}`;
68
+ const target = nativeTargets[platform];
69
+ if (
70
+ !target ||
71
+ (process.platform === 'linux' &&
72
+ !process.report.getReport().header.glibcVersionRuntime)
73
+ )
74
+ throw new Error(
75
+ 'Native installation supports macOS and glibc Linux on x64/ARM64; use WSL on Windows',
76
+ );
77
+ if (!/^[a-f0-9]{64}$/.test(componentSha256))
78
+ throw new Error('Trusted component digest required');
79
+ if (
80
+ !Number.isSafeInteger(timeout) ||
81
+ timeout <= 0 ||
82
+ timeout > 15 * 60 * 1000
83
+ )
84
+ throw new Error(
85
+ 'Installation timeout must be between 1 and 900000 milliseconds',
86
+ );
87
+ signal?.throwIfAborted();
88
+ require.resolve(`wasm-platform-kit-${platform}/bin/host-sdk-runtime`);
89
+ if (!fromSource)
90
+ {
91
+ let prebuilt;
92
+ try
93
+ {
94
+ const entry = prebuiltArtifacts[platform];
95
+ if (entry) prebuilt = {...entry, artifact: entry.artifact};
96
+ }
97
+ catch (error)
98
+ {
99
+ if (
100
+ !['MODULE_NOT_FOUND', 'ENOENT'].includes(error.code) &&
101
+ !['MODULE_NOT_FOUND', 'ENOENT'].includes(error.cause?.code)
102
+ )
103
+ throw error;
104
+ }
105
+ if (prebuilt)
106
+ {
107
+ if (
108
+ prebuilt.componentSha256 !== componentSha256 ||
109
+ prebuilt.configuration !== nativeConfiguration ||
110
+ prebuilt.target !== target ||
111
+ (await digest(prebuilt.artifact, 512 * 1024 * 1024)) !==
112
+ prebuilt.nativeSha256
113
+ )
114
+ throw new Error('Prebuilt native artifact integrity mismatch');
115
+ // A rebuild without force-source returns the installation to its packaged artifact.
116
+ await rm(new URL(`.native/${platform}/registration.json`, directory), {
117
+ force: true,
118
+ });
119
+ return {preparation: 'prebuilt', ...prebuilt};
120
+ }
121
+ }
122
+ const destination = fileURLToPath(new URL(`.native/${platform}/`, directory));
123
+ await mkdir(destination, {recursive: true, mode: 0o700});
124
+ await writeFile(new URL('.native/.npmignore', directory), '*\n');
125
+ const staging = await mkdtemp(path.join(destination, '.prepare-'));
126
+ try
127
+ {
128
+ const source = path.join(staging, 'component.wasm');
129
+ const output = path.join(staging, 'component.cwasm');
130
+ await snapshot(component, source, componentSha256, signal);
131
+ signal?.throwIfAborted();
132
+ const binary = require.resolve(
133
+ `wasm-platform-kit-${platform}/bin/host-sdk-source-runtime`,
134
+ );
135
+ const {stdout} = await execute(
136
+ binary,
137
+ ['--precompile', source, output, target],
138
+ {
139
+ encoding: 'utf8',
140
+ maxBuffer: 1024 * 1024,
141
+ timeout,
142
+ signal,
143
+ killSignal: 'SIGKILL',
144
+ env: {},
145
+ cwd: staging,
146
+ },
147
+ );
148
+ const receipt = JSON.parse(stdout);
149
+ if (
150
+ receipt.componentSha256 !== componentSha256 ||
151
+ receipt.configuration !== nativeConfiguration ||
152
+ receipt.target !== target ||
153
+ (await digest(output, 512 * 1024 * 1024)) !== receipt.nativeSha256
154
+ )
155
+ throw new Error('Compiled native artifact registration mismatch');
156
+ signal?.throwIfAborted();
157
+ await rename(
158
+ output,
159
+ path.join(destination, `${receipt.nativeSha256}.cwasm`),
160
+ );
161
+ await writeFile(
162
+ path.join(staging, 'registration.json'),
163
+ JSON.stringify(receipt) + '\n',
164
+ {mode: 0o600},
165
+ );
166
+ await rename(
167
+ path.join(staging, 'registration.json'),
168
+ path.join(destination, 'registration.json'),
169
+ );
170
+ return {preparation: 'source', ...receipt};
171
+ }
172
+ finally
173
+ {
174
+ await rm(staging, {recursive: true, force: true});
175
+ }
176
+ }
@@ -0,0 +1,70 @@
1
+ // Installation receipts are trusted package-local state, never guest authority.
2
+ // ref:DEC-wpk-installation-preparation
3
+ import {readFileSync} from 'node:fs';
4
+
5
+ export const nativeConfiguration = 'host-sdk-0.2.0/wasmtime-50.0.1/fuel-v1';
6
+ export const nativeTargets = Object.freeze({
7
+ 'darwin-arm64': 'aarch64-apple-darwin',
8
+ 'darwin-x64': 'x86_64-apple-darwin',
9
+ 'linux-arm64': 'aarch64-unknown-linux-gnu',
10
+ 'linux-x64': 'x86_64-unknown-linux-gnu',
11
+ });
12
+
13
+ /** Reads only receipts approved by the embedding package's generated registration. ref:DEC-wpk-installation-preparation */
14
+ export function installedNativeArtifacts({
15
+ directory,
16
+ componentSha256,
17
+ prebuiltArtifacts = {},
18
+ })
19
+ {
20
+ return Object.freeze(
21
+ Object.defineProperties(
22
+ {},
23
+ Object.fromEntries(
24
+ Object.entries(nativeTargets).map(([platform, target]) => [
25
+ platform,
26
+ {
27
+ enumerable: true,
28
+ get()
29
+ {
30
+ let receipt;
31
+ try
32
+ {
33
+ receipt = JSON.parse(
34
+ readFileSync(
35
+ new URL(`.native/${platform}/registration.json`, directory),
36
+ 'utf8',
37
+ ),
38
+ );
39
+ }
40
+ catch (error)
41
+ {
42
+ if (error.code === 'ENOENT') return prebuiltArtifacts[platform];
43
+ throw error;
44
+ }
45
+ if (
46
+ receipt.componentSha256 !== componentSha256 ||
47
+ receipt.configuration !== nativeConfiguration ||
48
+ receipt.target !== target ||
49
+ !/^[a-f0-9]{64}$/.test(receipt.nativeSha256)
50
+ )
51
+ throw new Error(
52
+ 'Installed native registration mismatch; reinstall the application',
53
+ );
54
+ return Object.freeze({
55
+ componentSha256,
56
+ configuration: nativeConfiguration,
57
+ target,
58
+ nativeSha256: receipt.nativeSha256,
59
+ artifact: new URL(
60
+ `.native/${platform}/${receipt.nativeSha256}.cwasm`,
61
+ directory,
62
+ ),
63
+ });
64
+ },
65
+ },
66
+ ]),
67
+ ),
68
+ ),
69
+ );
70
+ }
package/node.mjs ADDED
@@ -0,0 +1,332 @@
1
+ // One helper process per instance. Revocation destroys its store and resources.
2
+ // ref:DEC-host-sdk-direct-haskell
3
+ import {spawn} from 'node:child_process';
4
+ import {readFile} from 'node:fs/promises';
5
+ import {createHash, randomUUID} from 'node:crypto';
6
+ import {createRequire} from 'node:module';
7
+ import {fileURLToPath} from 'node:url';
8
+ import {
9
+ HostError,
10
+ fail,
11
+ configure,
12
+ createBroker,
13
+ byteLength,
14
+ createResourceScope,
15
+ outcomeCode,
16
+ stringifyTransport,
17
+ parseTransport,
18
+ trustedJavaScript,
19
+ } from './policy.mjs';
20
+ export {HostError, trustedJavaScript};
21
+ export {trustedDOM, trustedNativeFFI, trustedProcess} from './policy.mjs';
22
+ const require = createRequire(import.meta.url);
23
+ const sha256 = bytes => createHash('sha256').update(bytes).digest('hex');
24
+ const live = new Set();
25
+ const cleanup = new FinalizationRegistry(stop => stop());
26
+ process.once('exit', () =>
27
+ {
28
+ for (const stop of live) stop();
29
+ });
30
+
31
+ /** Starts an isolated Wasmtime instance from the matching prebuilt npm platform package. */
32
+ export async function createHost(options = {})
33
+ {
34
+ if (
35
+ !['darwin', 'linux'].includes(process.platform) ||
36
+ !['arm64', 'x64'].includes(process.arch)
37
+ )
38
+ fail(
39
+ 'unsupported',
40
+ 'Node native execution supports macOS/Linux x64 and ARM64 only; use WSL on Windows',
41
+ );
42
+ if (
43
+ process.platform === 'linux' &&
44
+ !process.report.getReport().header.glibcVersionRuntime
45
+ )
46
+ fail(
47
+ 'unsupported',
48
+ 'Linux native execution requires a detectable glibc runtime; musl is unsupported',
49
+ );
50
+ const compilation = options.compilation ?? 'precompiled';
51
+ if (compilation !== 'precompiled')
52
+ fail(
53
+ 'unsupported',
54
+ 'Runtime compilation is unavailable; run WASM_PLATFORM_KIT_BUILD_FROM_SOURCE=1 npm rebuild to prepare native artifacts during installation',
55
+ );
56
+ const platform = `${process.platform}-${process.arch}`;
57
+ const approved = options.nativeArtifacts?.[platform];
58
+ // Snapshot embedding-owned registration before the first await. A guest
59
+ // manifest, including its hashes, is never an authority for native loading.
60
+ const native = approved && {
61
+ artifact: String(approved.artifact),
62
+ componentSha256: approved.componentSha256,
63
+ nativeSha256: approved.nativeSha256,
64
+ configuration: approved.configuration,
65
+ target: approved.target,
66
+ };
67
+ if (!native)
68
+ fail(
69
+ 'unsupported',
70
+ `no embedding-approved native artifact for ${platform}; reinstall with scripts enabled or run npm rebuild`,
71
+ );
72
+ const resources = createResourceScope();
73
+ const configuration = configure(options);
74
+ const {limits, grants} = configuration;
75
+ const controller = new AbortController();
76
+ const broker = createBroker(configuration, {
77
+ signal: controller.signal,
78
+ storage: options.storage,
79
+ });
80
+ let binary;
81
+ try
82
+ {
83
+ binary = require.resolve(
84
+ `wasm-platform-kit-${platform}/bin/host-sdk-runtime`,
85
+ );
86
+ }
87
+ catch
88
+ {
89
+ fail(
90
+ 'unsupported',
91
+ `no prebuilt runtime for ${process.platform}-${process.arch}; build platform packages before installation`,
92
+ );
93
+ }
94
+ if (!options.manifest)
95
+ fail('failed', 'an embedding-approved component manifest is required');
96
+ const manifestURL = new URL(options.manifest, import.meta.url);
97
+ const manifest = JSON.parse(await readFile(manifestURL, 'utf8'));
98
+ if (
99
+ manifest.sdk !== '0.2.0' ||
100
+ !manifest.contract?.interfaces[manifest.interface]
101
+ )
102
+ fail('unsupported', 'SDK 0.2.0 typed manifest required');
103
+ const resultType = type =>
104
+ {
105
+ if (typeof type !== 'number') return undefined;
106
+ const kind = manifest.contract.types[type].kind;
107
+ return kind.type !== undefined ? resultType(kind.type) : kind.result;
108
+ };
109
+ const component = new URL(manifest.component, manifestURL);
110
+ if (
111
+ native.componentSha256 !== manifest.sha256 ||
112
+ native.configuration !== 'host-sdk-0.2.0/wasmtime-50.0.1/fuel-v1' ||
113
+ !/^[a-f0-9]{64}$/.test(native.nativeSha256)
114
+ )
115
+ fail('failed', 'native artifact registration mismatch');
116
+ if (new URL(native.artifact).protocol !== 'file:')
117
+ fail('denied', 'native artifacts must be local files');
118
+ const providerIdentity = sha256(
119
+ Buffer.concat(
120
+ await Promise.all(
121
+ [
122
+ 'policy.mjs',
123
+ 'node.mjs',
124
+ 'browser.mjs',
125
+ 'worker.mjs',
126
+ 'client.mjs',
127
+ ].map(name => readFile(new URL(name, import.meta.url))),
128
+ ),
129
+ ),
130
+ );
131
+ const runtimeIdentity = `wasmtime-50.0.1:${sha256(await readFile(binary))}`;
132
+ const child = spawn(binary, [], {
133
+ env: {},
134
+ cwd: '/',
135
+ stdio: ['pipe', 'pipe', 'pipe'],
136
+ });
137
+ if (options.keepAlive === false)
138
+ {
139
+ child.unref();
140
+ child.stdin.unref();
141
+ child.stdout.unref();
142
+ child.stderr.unref();
143
+ }
144
+
145
+ const nativeGrants = Object.fromEntries(
146
+ [...grants].map(([name, grant]) => [
147
+ name,
148
+ {
149
+ kind: grant.kind,
150
+ ...(grant.kind === 'files'
151
+ ? {root: grant.root, read: !!grant.read, write: !!grant.write}
152
+ : {}),
153
+ },
154
+ ]),
155
+ );
156
+ let closed = false,
157
+ pending,
158
+ text = '',
159
+ stderr = '',
160
+ timer;
161
+ let queue = Promise.resolve();
162
+ const send = message =>
163
+ {
164
+ if (!closed) child.stdin.write(stringifyTransport(message) + '\n');
165
+ };
166
+ const cleanupToken = {};
167
+ const stop = (error = new HostError('cancelled', 'instance revoked')) =>
168
+ {
169
+ if (closed) return;
170
+ closed = true;
171
+ live.delete(stop);
172
+ cleanup.unregister(cleanupToken);
173
+ clearTimeout(timer);
174
+ controller.abort(error);
175
+ broker.dispose();
176
+ child.kill('SIGKILL');
177
+ pending?.reject(error);
178
+ pending = undefined;
179
+ };
180
+ live.add(stop);
181
+ const wait = () =>
182
+ new Promise((resolve, reject) =>
183
+ {
184
+ pending = {resolve, reject};
185
+ timer = setTimeout(
186
+ () => stop(new HostError('exhausted', 'execution deadline')),
187
+ limits.timeout,
188
+ );
189
+ });
190
+ child.stdout.setEncoding('utf8');
191
+ child.stderr.setEncoding('utf8');
192
+ child.on('error', error => stop(new HostError('failed', error.message)));
193
+ child.on('exit', () =>
194
+ stop(new HostError('failed', stderr || 'runtime exited')),
195
+ );
196
+ child.stdin.on('error', error =>
197
+ stop(new HostError('failed', error.message)),
198
+ );
199
+ child.stderr.on('data', bytes =>
200
+ {
201
+ stderr += bytes.toString();
202
+ if (stderr.length > 8192) stderr = stderr.slice(0, 8192);
203
+ });
204
+ child.stdout.on('data', bytes =>
205
+ {
206
+ text += bytes.toString();
207
+ if (byteLength(text) > limits.bytes * 6 + 8192)
208
+ return stop(new HostError('exhausted', 'transport output limit'));
209
+ let newline;
210
+ while ((newline = text.indexOf('\n')) >= 0)
211
+ {
212
+ const line = text.slice(0, newline);
213
+ text = text.slice(newline + 1);
214
+ let message;
215
+ try
216
+ {
217
+ message = parseTransport(line);
218
+ }
219
+ catch
220
+ {
221
+ return stop(new HostError('failed', 'invalid runtime message'));
222
+ }
223
+ if (message.hostRequest)
224
+ {
225
+ const {provider, request} = message.hostRequest;
226
+ broker.perform(provider, request).then(
227
+ value => send({value}),
228
+ error =>
229
+ send({
230
+ error: {
231
+ code:
232
+ error.code ??
233
+ (controller.signal.aborted ? 'cancelled' : 'failed'),
234
+ message: error.message,
235
+ },
236
+ }),
237
+ );
238
+ continue;
239
+ }
240
+ const active = pending;
241
+ pending = undefined;
242
+ clearTimeout(timer);
243
+ if (!active)
244
+ return stop(new HostError('failed', 'unexpected runtime response'));
245
+ if (message.error)
246
+ {
247
+ active.reject(new HostError(message.error.code, message.error.message));
248
+ stop();
249
+ }
250
+ else active.resolve(message);
251
+ }
252
+ });
253
+ const ready = wait();
254
+ send({
255
+ component: fileURLToPath(component),
256
+ compilation,
257
+ ...(compilation === 'precompiled'
258
+ ? {
259
+ nativeArtifact: fileURLToPath(native.artifact),
260
+ nativeRegistration: {
261
+ componentSha256: native.componentSha256,
262
+ nativeSha256: native.nativeSha256,
263
+ configuration: native.configuration,
264
+ target: native.target,
265
+ },
266
+ }
267
+ : {}),
268
+ sha256: manifest.sha256,
269
+ limits,
270
+ grants: nativeGrants,
271
+ });
272
+ const identity = await ready;
273
+ const host = Object.freeze({
274
+ identity: Object.freeze({
275
+ ...identity,
276
+ runtime: runtimeIdentity,
277
+ provider: providerIdentity,
278
+ instance: randomUUID(),
279
+ policy: sha256(JSON.stringify([...grants]) + JSON.stringify(limits)),
280
+ interface: manifest.interface,
281
+ }),
282
+ invoke(method, args = [], {signal} = {})
283
+ {
284
+ const run = async () =>
285
+ {
286
+ if (closed || signal?.aborted) fail('cancelled', 'instance revoked');
287
+ const encoded = resources.encode(args);
288
+ if (byteLength(encoded) > limits.bytes)
289
+ fail('exhausted', 'input byte limit');
290
+ const abort = () => stop();
291
+ signal?.addEventListener('abort', abort, {once: true});
292
+ try
293
+ {
294
+ const result = wait();
295
+ send({interface: manifest.interface, method, args: encoded});
296
+ const response = await result;
297
+ const value = response.value?.[0];
298
+ const resultSchema = resultType(
299
+ manifest.contract.interfaces[manifest.interface][method]?.result,
300
+ );
301
+ if (resultSchema && value?.tag === 'err')
302
+ throw new HostError(
303
+ outcomeCode(value.val?.code),
304
+ typeof value.val === 'string'
305
+ ? value.val
306
+ : (value.val?.message ?? 'component returned an error'),
307
+ resources.decode(value.val),
308
+ );
309
+ return resources.decode(
310
+ resultSchema && value?.tag === 'ok' ? value.val : value,
311
+ );
312
+ }
313
+ finally
314
+ {
315
+ signal?.removeEventListener('abort', abort);
316
+ }
317
+ };
318
+ const result = queue.then(run);
319
+ queue = result.catch(() =>
320
+ {});
321
+ return result;
322
+ },
323
+ drop(resource, controls)
324
+ {
325
+ return this.invoke('[resource-drop]', [resource], controls);
326
+ },
327
+ revoke: () => stop(),
328
+ close: () => stop(),
329
+ });
330
+ cleanup.register(host, stop, cleanupToken);
331
+ return host;
332
+ }
package/package.json CHANGED
@@ -1,6 +1,68 @@
1
1
  {
2
2
  "name": "wasm-platform-kit",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "Capability-scoped WebAssembly components with typed Haskell guests",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "engines": {
8
+ "node": ">=22"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./index.d.ts",
13
+ "browser": "./browser.mjs",
14
+ "default": "./node.mjs"
15
+ },
16
+ "./browser": {
17
+ "types": "./index.d.ts",
18
+ "default": "./browser.mjs"
19
+ },
20
+ "./worker": "./worker.mjs",
21
+ "./package.json": "./package.json",
22
+ "./install": {
23
+ "types": "./install.d.ts",
24
+ "default": "./install.mjs"
25
+ },
26
+ "./native-registration": "./native-registration.mjs"
27
+ },
28
+ "files": [
29
+ "node.mjs",
30
+ "browser.mjs",
31
+ "worker.mjs",
32
+ "client.mjs",
33
+ "policy.mjs",
34
+ "index.d.ts",
35
+ "assets/wasi",
36
+ "README.md",
37
+ "LICENSE",
38
+ "install.mjs",
39
+ "install.d.ts",
40
+ "native-registration.mjs"
41
+ ],
42
+ "scripts": {
43
+ "build": "node tools/build.mjs",
44
+ "test": "node --test test/*.test.mjs",
45
+ "pack:local": "node tools/pack.mjs",
46
+ "format": "node tools/style.mjs",
47
+ "build:platform": "node tools/platform.mjs"
48
+ },
49
+ "devDependencies": {
50
+ "@bytecodealliance/jco": "1.41.0",
51
+ "@bytecodealliance/preview2-shim": "0.31.0",
52
+ "@playwright/test": "1.63.0",
53
+ "prettier": "3.9.10",
54
+ "prettier-plugin-brace-style": "0.10.4",
55
+ "typescript": "6.0.3"
56
+ },
57
+ "optionalDependencies": {
58
+ "wasm-platform-kit-darwin-arm64": "0.2.0",
59
+ "wasm-platform-kit-darwin-x64": "0.2.0",
60
+ "wasm-platform-kit-linux-arm64": "0.2.0",
61
+ "wasm-platform-kit-linux-x64": "0.2.0"
62
+ },
63
+ "repository": {
64
+ "type": "git",
65
+ "url": "git+https://github.com/brain-fuel/wasm-platform-kit.git"
66
+ },
67
+ "homepage": "https://github.com/brain-fuel/wasm-platform-kit#readme"
68
+ }