@bytecodealliance/preview2-shim 0.17.5 → 0.17.7

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
@@ -51,6 +51,54 @@ const component = await instantiate(loader, new WASIShim().getImportObject());
51
51
  // TODO: Code that uses your component's exports goes here.
52
52
  ```
53
53
 
54
+ ## Sandboxing
55
+
56
+ By default, the preview2-shim provides full access to the host filesystem, environment variables,
57
+ and network - matching the default behavior of Node.js libraries. However, you can configure
58
+ sandboxing to restrict what guests can access.
59
+
60
+ ### Using WASIShim for sandboxing
61
+
62
+ The `WASIShim` class accepts a `sandbox` configuration option to control access:
63
+
64
+ ```js
65
+ import { WASIShim } from '@bytecodealliance/preview2-shim/instantiation';
66
+
67
+ // Fully sandboxed - no filesystem, network, or env access
68
+ const sandboxedShim = new WASIShim({
69
+ sandbox: {
70
+ preopens: {}, // No filesystem access
71
+ env: {}, // No environment variables
72
+ args: ['arg1'], // Custom arguments
73
+ enableNetwork: false, // Disable network access
74
+ }
75
+ });
76
+
77
+ // Limited filesystem access - map virtual paths to host paths
78
+ const limitedShim = new WASIShim({
79
+ sandbox: {
80
+ preopens: {
81
+ '/data': '/tmp/guest-data', // Guest sees /data, maps to /tmp/guest-data
82
+ '/config': '/etc/app' // Guest sees /config, maps to /etc/app
83
+ },
84
+ env: { 'ENV1': '42' }, // Only expose specific env vars
85
+ }
86
+ });
87
+
88
+ const component = await instantiate(loader, sandboxedShim.getImportObject());
89
+ ```
90
+
91
+ ### Notes on sandboxing
92
+
93
+ - By default (when no options are passed), the shim is providing full access to match typical
94
+ Node.js library behavior.
95
+ - Each `WASIShim` instance has its own isolated preopens, environment variables, and arguments.
96
+ Multiple instances with different configurations will not affect each other.
97
+ - The direct preopen functions (`_setPreopens`, `_clearPreopens`, etc.) modify global state and
98
+ affect all components not using `WASIShim` with explicit configuration. For isolation, prefer
99
+ using `WASIShim` with the `sandbox` option containing `preopens` and `env`.
100
+ - When `sandbox.enableNetwork: false`, all socket and HTTP operations will throw "access-denied" errors.
101
+
54
102
  [jco]: https://www.npmjs.com/package/@bytecodealliance/jco
55
103
 
56
104
  # License
@@ -1,4 +1,3 @@
1
- // eslint-disable-next-line no-unused-vars
2
1
  let _cwd = '/';
3
2
 
4
3
  export function _setCwd(cwd) {
@@ -6,6 +6,25 @@ export { _setCwd } from './config.js';
6
6
 
7
7
  const { InputStream, OutputStream } = streams;
8
8
 
9
+ /**
10
+ * @typedef {Object} FileDataEntry
11
+ * @property {Record<string, FileDataEntry>} [dir] - Directory contents (present for directories)
12
+ * @property {Uint8Array|string} [source] - File contents (present for files)
13
+ */
14
+
15
+ /**
16
+ * @typedef {FileDataEntry} FileData
17
+ * Root file data structure representing a filesystem tree.
18
+ * Each entry is either a directory (has `dir` property) or a file (has `source` property).
19
+ * @example
20
+ * // A simple filesystem with one directory containing one file:
21
+ * const fileData = {
22
+ * dir: {
23
+ * 'myfile.txt': { source: new Uint8Array([72, 101, 108, 108, 111]) }
24
+ * }
25
+ * };
26
+ */
27
+
9
28
  export function _setFileData(fileData) {
10
29
  _fileData = fileData;
11
30
  _rootPreopen[0] = new Descriptor(fileData);
@@ -322,9 +341,159 @@ export const preopens = {
322
341
  },
323
342
  };
324
343
 
344
+ /**
345
+ * Replace all preopens with the given set.
346
+ * @param {Record<string, FileData>} preopensConfig - Map of virtual paths to file data entries
347
+ */
348
+ export function _setPreopens(preopensConfig) {
349
+ _preopens = [];
350
+ for (const [virtualPath, fileData] of Object.entries(preopensConfig)) {
351
+ _addPreopen(virtualPath, fileData);
352
+ }
353
+ }
354
+
355
+ /**
356
+ * Add a single preopen mapping.
357
+ * @param {string} virtualPath - The virtual path visible to the guest
358
+ * @param {FileData} fileData - The file data object representing the directory
359
+ */
360
+ export function _addPreopen(virtualPath, fileData) {
361
+ const descriptor = new Descriptor(fileData);
362
+ _preopens.push([descriptor, virtualPath]);
363
+ if (virtualPath === '/') {
364
+ _rootPreopen = [descriptor, virtualPath];
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Clear all preopens, giving the guest no filesystem access.
370
+ *
371
+ * This functionality exists mostly to maintain backwards compatibility. Prefer setting preopens
372
+ * via `WASIShim` rather than making top level changes to preopens using these functions.
373
+ */
374
+ export function _clearPreopens() {
375
+ _preopens = [];
376
+ _rootPreopen = null;
377
+ }
378
+
379
+ /**
380
+ * Get current preopens configuration.
381
+ * @returns {Array<[Descriptor, string]>} Array of [descriptor, virtualPath] pairs
382
+ */
383
+ export function _getPreopens() {
384
+ return [..._preopens];
385
+ }
386
+
387
+ /**
388
+ * Create a preopen descriptor for file data.
389
+ * This is used internally to create isolated preopen instances.
390
+ * @param {FileData} fileData - The file data object representing the directory
391
+ * @returns {Descriptor} A preopen descriptor
392
+ */
393
+ export function _createPreopenDescriptor(fileData) {
394
+ return new Descriptor(fileData);
395
+ }
396
+
325
397
  export const types = {
326
398
  Descriptor,
327
399
  DirectoryEntryStream,
400
+ filesystemErrorCode(err) {
401
+ return convertFsError(err.payload);
402
+ },
328
403
  };
329
404
 
405
+ function convertFsError(e) {
406
+ switch (e.code) {
407
+ case 'EACCES':
408
+ return 'access';
409
+ case 'EAGAIN':
410
+ case 'EWOULDBLOCK':
411
+ return 'would-block';
412
+ case 'EALREADY':
413
+ return 'already';
414
+ case 'EBADF':
415
+ return 'bad-descriptor';
416
+ case 'EBUSY':
417
+ return 'busy';
418
+ case 'EDEADLK':
419
+ return 'deadlock';
420
+ case 'EDQUOT':
421
+ return 'quota';
422
+ case 'EEXIST':
423
+ return 'exist';
424
+ case 'EFBIG':
425
+ return 'file-too-large';
426
+ case 'EILSEQ':
427
+ return 'illegal-byte-sequence';
428
+ case 'EINPROGRESS':
429
+ return 'in-progress';
430
+ case 'EINTR':
431
+ return 'interrupted';
432
+ case 'EINVAL':
433
+ return 'invalid';
434
+ case 'EIO':
435
+ return 'io';
436
+ case 'EISDIR':
437
+ return 'is-directory';
438
+ case 'ELOOP':
439
+ return 'loop';
440
+ case 'EMLINK':
441
+ return 'too-many-links';
442
+ case 'EMSGSIZE':
443
+ return 'message-size';
444
+ case 'ENAMETOOLONG':
445
+ return 'name-too-long';
446
+ case 'ENODEV':
447
+ return 'no-device';
448
+ case 'ENOENT':
449
+ return 'no-entry';
450
+ case 'ENOLCK':
451
+ return 'no-lock';
452
+ case 'ENOMEM':
453
+ return 'insufficient-memory';
454
+ case 'ENOSPC':
455
+ return 'insufficient-space';
456
+ case 'ENOTDIR':
457
+ case 'ERR_FS_EISDIR':
458
+ return 'not-directory';
459
+ case 'ENOTEMPTY':
460
+ return 'not-empty';
461
+ case 'ENOTRECOVERABLE':
462
+ return 'not-recoverable';
463
+ case 'ENOTSUP':
464
+ return 'unsupported';
465
+ case 'ENOTTY':
466
+ return 'no-tty';
467
+ // windows gives this error for badly structured `//` reads
468
+ // this seems like a slightly better error than unknown given
469
+ // that it's a common footgun
470
+ case -4094:
471
+ case 'ENXIO':
472
+ return 'no-such-device';
473
+ case 'EOVERFLOW':
474
+ return 'overflow';
475
+ case 'EPERM':
476
+ return 'not-permitted';
477
+ case 'EPIPE':
478
+ return 'pipe';
479
+ case 'EROFS':
480
+ return 'read-only';
481
+ case 'ESPIPE':
482
+ return 'invalid-seek';
483
+ case 'ETXTBSY':
484
+ return 'text-file-busy';
485
+ case 'EXDEV':
486
+ return 'cross-device';
487
+ case 'UNKNOWN':
488
+ switch (e.errno) {
489
+ case -4094:
490
+ return 'no-such-device';
491
+ default:
492
+ throw e;
493
+ }
494
+ default:
495
+ throw e;
496
+ }
497
+ }
498
+
330
499
  export { types as filesystemTypes };
@@ -142,4 +142,14 @@ export const types = {
142
142
  listenToFutureIncomingResponse(_f) {
143
143
  console.log('[types] Listen to future incoming response');
144
144
  },
145
+ Fields: class Fields {},
146
+ FutureIncomingResponse: new class FutureIncomingResponse {},
147
+ IncomingBody: new class IncomingBody {},
148
+ IncomingRequest: new class IncomingRequest {},
149
+ IncomingResponse: new class IncomingResponse {},
150
+ OutgoingBody: new class OutgoingBody {},
151
+ OutgoingRequest: new class OutgoingRequest {},
152
+ OutgoingResponse: new class OutgoingResponse {},
153
+ RequestOptions: new class RequestOptions {},
154
+ ResponseOutparam: new class ResponseOutparam {},
145
155
  };
package/lib/browser/io.js CHANGED
@@ -17,7 +17,7 @@ const IoError = class Error {
17
17
  * blockingRead: (len: BigInt) => Uint8Array,
18
18
  * skip?: (len: BigInt) => BigInt,
19
19
  * blockingSkip?: (len: BigInt) => BigInt,
20
- * subscribe: () => void,
20
+ * subscribe: () => Pollable,
21
21
  * drop?: () => void,
22
22
  * }} InputStreamHandler
23
23
  *
@@ -33,7 +33,7 @@ const IoError = class Error {
33
33
  * splice?: (src: InputStream, len: BigInt) => BigInt,
34
34
  * blockingSplice?: (src: InputStream, len: BigInt) => BigInt,
35
35
  * forward?: (src: InputStream) => void,
36
- * subscribe?: () => void,
36
+ * subscribe?: () => Pollable,
37
37
  * drop?: () => void,
38
38
  * }} OutputStreamHandler
39
39
  *
@@ -78,6 +78,7 @@ class InputStream {
78
78
  }
79
79
  subscribe() {
80
80
  console.log(`[streams] Subscribe to input stream ${this.id}`);
81
+ return new Pollable();
81
82
  }
82
83
  [symbolDispose]() {
83
84
  if (this.handler.drop) {
@@ -168,6 +169,7 @@ class OutputStream {
168
169
  }
169
170
  subscribe() {
170
171
  console.log(`[streams] Subscribe to output stream ${this.id}`);
172
+ return new Pollable();
171
173
  }
172
174
  [symbolDispose]() {}
173
175
  }
@@ -190,4 +192,5 @@ export const poll = {
190
192
  Pollable,
191
193
  pollList,
192
194
  pollOne,
195
+ poll: pollOne,
193
196
  };
@@ -44,6 +44,33 @@ import * as wasi from '@bytecodealliance/preview2-shim';
44
44
  * const component = await instantiate(null, customWASIShim.getImportObject())
45
45
  * ```
46
46
  *
47
+ * For sandboxing, you can configure preopens, environment variables, and other
48
+ * capabilities via the `sandbox` option:
49
+ *
50
+ * ```js
51
+ * import { WASIShim } from "@bytecodealliance/preview2-shim/instantiation"
52
+ *
53
+ * // Fully sandboxed - no filesystem, network, or env access
54
+ * const sandboxedShim = new WASIShim({
55
+ * sandbox: {
56
+ * preopens: {}, // No filesystem access
57
+ * env: {}, // No environment variables
58
+ * args: ['program'], // Custom arguments
59
+ * enableNetwork: false, // Disable network (default: true for backward compat)
60
+ * }
61
+ * });
62
+ *
63
+ * // Limited filesystem access
64
+ * const limitedShim = new WASIShim({
65
+ * sandbox: {
66
+ * preopens: {
67
+ * '/data': '/tmp/guest-data', // Guest sees /data, maps to /tmp/guest-data
68
+ * '/config': '/etc/app' // Guest sees /config, maps to /etc/app
69
+ * }
70
+ * }
71
+ * });
72
+ * ```
73
+ *
47
74
  * Note that this object is similar but not identical to the Node `WASI` object --
48
75
  * it is solely concerned with shimming of preview2 when dealing with a WebAssembly
49
76
  * component transpiled by Jco. While this object *does* work with Node (and the browser)
@@ -66,8 +93,20 @@ export class WASIShim {
66
93
  #sockets;
67
94
  /** Object that confirms to the shim interface for `wasi:http` */
68
95
  #http;
96
+ /** Isolated preopens for this instance */
97
+ #preopens;
98
+ /** Isolated environment for this instance */
99
+ #environment;
100
+
101
+ /**
102
+ * Create a new WASIShim instance.
103
+ *
104
+ * @param {import('../types/instantiation.d.ts').WASIShimConfig} [config] - Configuration options
105
+ */
106
+ constructor(config) {
107
+ // Support both old 'shims' parameter name and new 'config' style
108
+ const shims = config;
69
109
 
70
- constructor(shims) {
71
110
  this.#cli = shims?.cli ?? wasi.cli;
72
111
  this.#filesystem = shims?.filesystem ?? wasi.filesystem;
73
112
  this.#io = shims?.io ?? wasi.io;
@@ -75,6 +114,37 @@ export class WASIShim {
75
114
  this.#clocks = shims?.clocks ?? wasi.clocks;
76
115
  this.#sockets = shims?.sockets ?? wasi.sockets;
77
116
  this.#http = shims?.http ?? wasi.http;
117
+
118
+ // Extract sandbox options
119
+ const sandbox = shims?.sandbox;
120
+
121
+ // Create isolated preopens if configured
122
+ if (sandbox?.preopens !== undefined) {
123
+ this.#preopens = createIsolatedPreopens(sandbox.preopens);
124
+ }
125
+
126
+ // Create isolated environment if env or args are configured
127
+ if (sandbox?.env !== undefined || sandbox?.args !== undefined) {
128
+ this.#environment = createIsolatedEnvironment(
129
+ sandbox?.env,
130
+ sandbox?.args,
131
+ this.#cli
132
+ );
133
+ }
134
+
135
+ // Apply network restrictions if disabled
136
+ if (sandbox?.enableNetwork === false) {
137
+ // Use the sockets module's built-in deny functions
138
+ if (this.#sockets._denyTcp) {
139
+ this.#sockets._denyTcp();
140
+ }
141
+ if (this.#sockets._denyUdp) {
142
+ this.#sockets._denyUdp();
143
+ }
144
+ if (this.#sockets._denyDnsLookup) {
145
+ this.#sockets._denyDnsLookup();
146
+ }
147
+ }
78
148
  }
79
149
 
80
150
  /**
@@ -93,7 +163,8 @@ export class WASIShim {
93
163
  const versionSuffix = opts?.asVersion ? `@${opts.asVersion}` : '';
94
164
 
95
165
  const obj = {};
96
- obj[`wasi:cli/environment${versionSuffix}`] = this.#cli.environment;
166
+
167
+ obj[`wasi:cli/environment${versionSuffix}`] = this.#environment ?? this.#cli.environment;
97
168
  obj[`wasi:cli/exit${versionSuffix}`] = this.#cli.exit;
98
169
  obj[`wasi:cli/stderr${versionSuffix}`] = this.#cli.stderr;
99
170
  obj[`wasi:cli/stdin${versionSuffix}`] = this.#cli.stdin;
@@ -112,7 +183,7 @@ export class WASIShim {
112
183
  obj[`wasi:sockets/udp${versionSuffix}`] = this.#sockets.udp;
113
184
  obj[`wasi:sockets/udp-create-socket${versionSuffix}`] = this.#sockets.udpCreateSocket;
114
185
 
115
- obj[`wasi:filesystem/preopens${versionSuffix}`] = this.#filesystem.preopens;
186
+ obj[`wasi:filesystem/preopens${versionSuffix}`] = this.#preopens ?? this.#filesystem.preopens;
116
187
  obj[`wasi:filesystem/types${versionSuffix}`] = this.#filesystem.types;
117
188
 
118
189
  obj[`wasi:io/error${versionSuffix}`] = this.#io.error;
@@ -132,3 +203,55 @@ export class WASIShim {
132
203
  return obj;
133
204
  }
134
205
  }
206
+
207
+ /**
208
+ * Create an isolated preopens object with its own preopen entries.
209
+ *
210
+ * @param {Record<string, string>} preopensConfig - Map of virtual paths to host paths
211
+ * @returns {object} A preopens object with Descriptor and getDirectories()
212
+ */
213
+ function createIsolatedPreopens(preopensConfig) {
214
+ const { types, _createPreopenDescriptor } = wasi.filesystem;
215
+ const entries = [];
216
+
217
+ // Populate entries using the filesystem's descriptor creation
218
+ if (_createPreopenDescriptor) {
219
+ for (const [virtualPath, hostPath] of Object.entries(preopensConfig)) {
220
+ const descriptor = _createPreopenDescriptor(hostPath);
221
+ entries.push([descriptor, virtualPath]);
222
+ }
223
+ }
224
+
225
+ return {
226
+ Descriptor: types.Descriptor,
227
+ getDirectories() {
228
+ return entries;
229
+ },
230
+ };
231
+ }
232
+
233
+ /**
234
+ * Create an isolated CLI environment with its own env and args.
235
+ *
236
+ * @param {Record<string, string>} env - Environment variables
237
+ * @param {string[]} args - Command-line arguments
238
+ * @param {object} baseCli - The base CLI module to extend
239
+ * @returns {object} An isolated CLI environment object
240
+ */
241
+ function createIsolatedEnvironment(env, args, baseCli) {
242
+ const envEntries = env ? Object.entries(env) : null;
243
+ const argsArray = args || null;
244
+
245
+ return {
246
+ ...baseCli.environment,
247
+ getEnvironment() {
248
+ return envEntries ?? baseCli.environment.getEnvironment();
249
+ },
250
+ getArguments() {
251
+ return argsArray ?? baseCli.environment.getArguments();
252
+ },
253
+ initialCwd() {
254
+ return baseCli.environment.initialCwd();
255
+ },
256
+ };
257
+ }
@@ -738,6 +738,10 @@ export const types = {
738
738
  },
739
739
  };
740
740
 
741
+ /**
742
+ * Replace all preopens with the given set.
743
+ * @param {Record<string, string>} preopens - Map of virtual paths to host paths
744
+ */
741
745
  export function _setPreopens(preopens) {
742
746
  preopenEntries = [];
743
747
  for (const [virtualPath, hostPreopen] of Object.entries(preopens)) {
@@ -745,11 +749,46 @@ export function _setPreopens(preopens) {
745
749
  }
746
750
  }
747
751
 
752
+ /**
753
+ * Add a single preopen mapping.
754
+ * @param {string} virtualPath - The virtual path visible to the guest
755
+ * @param {string} hostPreopen - The host filesystem path
756
+ */
748
757
  export function _addPreopen(virtualPath, hostPreopen) {
749
758
  const preopenEntry = [descriptorCreatePreopen(hostPreopen), virtualPath];
750
759
  preopenEntries.push(preopenEntry);
751
760
  }
752
761
 
762
+ /**
763
+ * Clear all preopens, giving the guest no filesystem access.
764
+ * Call this immediately after import to disable default full filesystem access.
765
+ *
766
+ * @example
767
+ * import { _clearPreopens } from '@bytecodealliance/preview2-shim/filesystem';
768
+ * _clearPreopens(); // Now guest has no filesystem access by default
769
+ */
770
+ export function _clearPreopens() {
771
+ preopenEntries = [];
772
+ }
773
+
774
+ /**
775
+ * Get current preopens configuration.
776
+ * @returns {Array<[Descriptor, string]>} Array of [descriptor, virtualPath] pairs
777
+ */
778
+ export function _getPreopens() {
779
+ return [...preopenEntries];
780
+ }
781
+
782
+ /**
783
+ * Create a preopen descriptor for a host path.
784
+ * This is used internally to create isolated preopen instances.
785
+ * @param {string} hostPreopen - The host filesystem path
786
+ * @returns {Descriptor} A preopen descriptor
787
+ */
788
+ export function _createPreopenDescriptor(hostPreopen) {
789
+ return descriptorCreatePreopen(hostPreopen);
790
+ }
791
+
753
792
  function convertFsError(e) {
754
793
  switch (e.code) {
755
794
  case 'EACCES':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytecodealliance/preview2-shim",
3
- "version": "0.17.5",
3
+ "version": "0.17.7",
4
4
  "description": "WASI Preview2 shim for JS environments",
5
5
  "author": "Guy Bedford, Eduardo Rodrigues<16357187+eduardomourar@users.noreply.github.com>",
6
6
  "contributors": [
@@ -1,2 +1,29 @@
1
1
  export type * as preopens from './interfaces/wasi-filesystem-preopens.d.ts';
2
2
  export type * as types from './interfaces/wasi-filesystem-types.d.ts';
3
+
4
+ import type { Descriptor } from './interfaces/wasi-filesystem-types.d.ts';
5
+
6
+ /**
7
+ * Replace all preopens with the given set.
8
+ * @param preopens - Map of virtual paths to host paths
9
+ */
10
+ export function _setPreopens(preopens: Record<string, string>): void;
11
+
12
+ /**
13
+ * Add a single preopen mapping.
14
+ * @param virtualPath - The virtual path visible to the guest
15
+ * @param hostPreopen - The host filesystem path
16
+ */
17
+ export function _addPreopen(virtualPath: string, hostPreopen: string): void;
18
+
19
+ /**
20
+ * Clear all preopens, giving the guest no filesystem access.
21
+ * Call this immediately after import to disable default full filesystem access.
22
+ */
23
+ export function _clearPreopens(): void;
24
+
25
+ /**
26
+ * Get current preopens configuration.
27
+ * @returns Array of [descriptor, virtualPath] pairs
28
+ */
29
+ export function _getPreopens(): Array<[Descriptor, string]>;
@@ -64,6 +64,42 @@ type AppendVersion<
64
64
  : never
65
65
  : never;
66
66
 
67
+ /**
68
+ * Sandbox configuration options for WASIShim
69
+ */
70
+ interface SandboxConfig {
71
+ /** Filesystem preopens mapping (virtual path -> host path) */
72
+ preopens?: Record<string, string>;
73
+ /** Environment variables visible to the guest */
74
+ env?: Record<string, string>;
75
+ /** Command-line arguments */
76
+ args?: string[];
77
+ /** Whether to enable network access (sockets, HTTP). Default: true */
78
+ enableNetwork?: boolean;
79
+ }
80
+
81
+ /**
82
+ * Configuration options for WASIShim
83
+ */
84
+ interface WASIShimConfig {
85
+ /** Custom CLI shim */
86
+ cli?: object;
87
+ /** Custom filesystem shim */
88
+ filesystem?: object;
89
+ /** Custom I/O shim */
90
+ io?: object;
91
+ /** Custom random shim */
92
+ random?: object;
93
+ /** Custom clocks shim */
94
+ clocks?: object;
95
+ /** Custom sockets shim */
96
+ sockets?: object;
97
+ /** Custom HTTP shim */
98
+ http?: object;
99
+ /** Sandbox configuration for restricting guest capabilities */
100
+ sandbox?: SandboxConfig;
101
+ }
102
+
67
103
  /**
68
104
  * (EXPERIMENTAL) A class that holds WASI shims and can be used to configure
69
105
  * an instantiation of a WebAssembly component transpiled with jco
@@ -108,6 +144,33 @@ type AppendVersion<
108
144
  * const component = await instantiate(null, customWASIShim.getImportObject())
109
145
  * ```
110
146
  *
147
+ * For sandboxing, you can configure preopens, environment variables, and other
148
+ * capabilities via the `sandbox` option:
149
+ *
150
+ * ```js
151
+ * import { WASIShim } from "@bytecodealliance/preview2-shim/instantiation"
152
+ *
153
+ * // Fully sandboxed - no filesystem, network, or env access
154
+ * const sandboxedShim = new WASIShim({
155
+ * sandbox: {
156
+ * preopens: {}, // No filesystem access
157
+ * env: {}, // No environment variables
158
+ * args: ['program'], // Custom arguments
159
+ * enableNetwork: false, // Disable network
160
+ * }
161
+ * });
162
+ *
163
+ * // Limited filesystem access
164
+ * const limitedShim = new WASIShim({
165
+ * sandbox: {
166
+ * preopens: {
167
+ * '/data': '/tmp/guest-data', // Guest sees /data, maps to /tmp/guest-data
168
+ * '/config': '/etc/app' // Guest sees /config, maps to /etc/app
169
+ * }
170
+ * }
171
+ * });
172
+ * ```
173
+ *
111
174
  * Note that this object is similar but not identical to the Node `WASI` object --
112
175
  * it is solely concerned with shimming of preview2 when dealing with a WebAssembly
113
176
  * component transpiled by Jco. While this object *does* work with Node (and the browser)
@@ -116,7 +179,7 @@ type AppendVersion<
116
179
  * @class WASIShim
117
180
  */
118
181
  export class WASIShim {
119
- constructor(shims?: Partial<WASIImportObject>);
182
+ constructor(config?: WASIShimConfig);
120
183
 
121
184
  /**
122
185
  * Generate an import object for the shim that can be used with