# @bytecodealliance/preview2-shim

> WASI Preview2 shim for JS environments

Latest version **0.25.0** (published 2026-09-14) · (Apache-2.0 WITH LLVM-exception) license · 0 weekly downloads

## Install

```sh
npm install @bytecodealliance/preview2-shim
pnpm add @bytecodealliance/preview2-shim
yarn add @bytecodealliance/preview2-shim
bun add @bytecodealliance/preview2-shim
```

## Health

**Score 65/100 (B)** — status: active.

Positive: esm support; no vulnerabilities; has provenance; recently updated; high maintenance score.

Warnings: low downloads; no types; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.25.0 |
| Published | 2026-09-14 |
| First published | 2023-02-19 |
| Weekly downloads | 0 |
| License | (Apache-2.0 WITH LLVM-exception) |
| TypeScript types | none |
| Module format | ESM |
| Dependencies | 1 |
| Unpacked size | 579.2 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 1004 |
| Author | Guy Bedford, Eduardo Rodrigues<16357187+eduardomourar@users.noreply.github.com> |
| Maintainers | tschneidereit, cfallin, guybedford, vados |

## Links

- npm: https://www.npmjs.com/package/@bytecodealliance/preview2-shim
- Repository: https://github.com/bytecodealliance/jco
- Homepage: https://github.com/bytecodealliance/jco#readme
- Issues: https://github.com/bytecodealliance/jco/issues
- npm.io page: https://npm.io/package/@bytecodealliance/preview2-shim

## Dependencies (1)

- [@bytecodealliance/jco-node-fs](https://npm.io/package/@bytecodealliance/jco-node-fs.md) 0.3.2

## Recent versions

- 0.25.0 (latest) — 2026-09-14
- 0.24.1 — 2026-09-07
- 0.24.0 — 2026-09-07
- 0.23.0 — 2026-08-24
- 0.22.0 — 2026-08-23
- 0.21.0 — 2026-08-21
- 0.20.2 — 2026-08-19
- 0.20.1 — 2026-08-04
- 0.20.0 — 2026-08-03
- 0.19.0 — 2026-06-19
- 0.18.1 — 2026-06-01
- 0.18.0 — 2026-05-22
- 0.17.9 — 2026-04-17
- 0.17.8 — 2026-02-08
- 0.17.7 — 2026-01-31
- … 41 more at https://npm.io/package/@bytecodealliance/preview2-shim/versions

## README

# Preview2 Shim

WASI Preview2 implementations for Node.js & browsers.

Node.js support is fully tested and conformant against the Wasmtime test suite.

Browser support is available with the platform limitations documented below.

The Node.js implementation owns its worker artifact. Direct package use and supported downstream
bundlers should resolve it through the public shim imports; applications do not need to import or
copy files from `dist/io`.

## Browser support matrix

Browser defaults are capability-safe: clocks and secure randomness use Web APIs, stdout and stderr
write to the console, stdin is closed, outbound HTTP uses `fetch`, filesystem preopens must be
configured explicitly, and raw sockets are unavailable unless an embedding supplies an adapter.

| WASI area                     | Browser status                                                | Default capability                                                |
| ----------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------- |
| CLI environment and arguments | Configurable per `WASIShim`; compatibility setters are global | Empty snapshots unless configured                                 |
| CLI stdin                     | Adapter-backed                                                | Closed stream                                                     |
| CLI stdout and stderr         | Web API                                                       | Console-backed, preserving split UTF-8 writes until flush/newline |
| CLI terminals                 | Adapter-backed                                                | No terminal resource                                              |
| Clocks                        | Web API                                                       | `performance.now`, `Date.now`, and timer-backed pollables         |
| Random                        | Web API                                                       | `crypto.getRandomValues`, including requests larger than 64 KiB   |
| I/O streams and poll          | Implemented browser resources                                 | Non-blocking streams depend on their injected handlers            |
| Filesystem                    | Adapter-backed; opt-in in-memory compatibility implementation | No persistent storage is selected implicitly                      |
| Outbound HTTP                 | Web API                                                       | Delegates to `fetch`                                              |
| Incoming HTTP                 | Adapter-backed; opt-in in-memory client                       | Browsers cannot listen for arbitrary inbound HTTP                 |
| TCP and UDP                   | Adapter-backed; opt-in in-memory implementations              | Raw sockets are not exposed by standard browsers                  |
| DNS                           | Host adapter required                                         | DNS is not exposed independently by standard browsers             |
| `WASIShim` instantiation      | Implemented                                                   | Interface namespaces can be overridden per instance               |

An operation is not considered supported merely because its interface shape exists. Adapter-backed
rows require the embedding application to provide that capability; unavailable operations fail with
a WASI-domain error instead of logging or returning a placeholder resource.

### Detailed browser capabilities

The following table describes the built-in browser implementation. An application-provided
namespace can replace any row through `WASIShim`.

| Interface                     | Implemented                                                                                       | Host adapter required                                      | Unsupported by browser implementation          |
| ----------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------- |
| `wasi:cli`                    | environment, arguments, initial cwd, exit, stream and terminal accessors                          | stdin/stdout/stderr handlers and terminal resources        | —                                              |
| `wasi:clocks`                 | wall clock, monotonic clock, timer subscriptions                                                  | —                                                          | timezone APIs (not part of Preview 2)          |
| `wasi:random`                 | secure and insecure bytes, insecure seed                                                          | —                                                          | —                                              |
| `wasi:io`                     | errors, input/output streams, poll and pollables                                                  | readiness and I/O behavior for injected stream handlers    | synchronous blocking of the browser event loop |
| `wasi:filesystem`             | descriptors, files, directories, links, metadata, streams, preopens through the ephemeral adapter | persistent storage, permissions, and external file handles | symbolic-link creation and reading             |
| `wasi:http/outgoing-handler`  | Fetch-backed requests and buffered request bodies                                                 | Fetch implementation and network permission                | request/response trailers; streaming uploads   |
| `wasi:http/incoming-handler`  | request/response translation, injectable handler, and in-memory client                            | HTTP server, service worker, or other request source       | direct browser listening                       |
| `wasi:sockets/ip-name-lookup` | interface shape only                                                                              | complete interface replacement                             | built-in DNS lookup                            |
| `wasi:sockets/tcp*`           | opt-in in-memory server/client implementation                                                     | adapter for external connectivity                          | built-in raw TCP                               |
| `wasi:sockets/udp*`           | opt-in in-memory server/client implementation                                                     | adapter for external connectivity                          | built-in raw UDP                               |

Outbound HTTP buffers a requested body until `outgoing-body.finish` before calling `fetch`.
This preserves complete-body semantics across browsers but does not provide streaming upload or
upload backpressure. Incoming Fetch bodies retain their asynchronous stream behavior. HTTP
trailers are not implemented.

Chromium-based browsers can opt into Fetch request streaming. This setting uses a
`ReadableStream` request body with `duplex: "half"`; unsupported browsers reject the request, so
applications should enable it only after applying their own browser support policy or feature
detection:

```js
import { http } from "@bytecodealliance/preview2-shim";

http._setRequestStreaming(true);
```

The setting affects subsequent requests made through the browser HTTP shim. Call
`http._setRequestStreaming(false)` to restore portable completion buffering.

Browser applications select storage explicitly. The bundled file-data adapter is ephemeral and must
be opted into:

```js
import { filesystem } from "@bytecodealliance/preview2-shim";
import { WASIShim } from "@bytecodealliance/preview2-shim/instantiation";

const shim = new WASIShim({
    environment: { MODE: "browser" },
    arguments: ["component"],
    stdout: { write: (bytes) => terminal.write(bytes) },
    browserFilesystem: {
        adapter: new filesystem.InMemoryFilesystemAdapter(),
        preopens: { "/data": { dir: {} } },
    },
    sandbox: { enableNetwork: false },
});
```

The browser shim does not request File System Access permissions or choose IndexedDB/OPFS on an
application's behalf. Applications that need another storage model implement the generated
`wasi:filesystem/types` and `wasi:filesystem/preopens` namespaces and inject them through the
`filesystem` option:

```js
const shim = new WASIShim({
    filesystem: {
        types: applicationFilesystemTypes,
        preopens: applicationFilesystemPreopens,
    },
});
```

This keeps permission prompts, handle acquisition, persistence, and synchronization policy in
application code. Raw TCP, UDP, and DNS are denied by default; outbound HTTP remains a separate
`fetch` capability.

Deterministic in-memory transports are available for components that act as servers and for tests:

```js
import { http, sockets } from "@bytecodealliance/preview2-shim";

const tcpSockets = new sockets.InMemoryTcpSockets();
const tcpClient = tcpSockets.connect(serverAddress);
const udpSockets = new sockets.InMemoryUdpSockets();
const udpClient = udpSockets.createClient(clientAddress);
const httpClient = new http.InMemoryHttpClient(component.incomingHandler);

const shim = new WASIShim({ tcpSockets, udpSockets });
```

These implementations route bytes only within the current JavaScript realm; they do not grant raw
browser network access. `InMemoryHttpClient.fetch(request)` returns a standard Web `Response`.

For a small application-owned implementation, see the
[Map-backed browser filesystem test shim](./test/fixtures/filesystem-shim/in-memory-map.ts). It keeps named
roots in an in-memory `Map`, implements `createPreopens`, and is intentionally example code rather
than a published or supported filesystem package. The example is exercised through the reusable
[filesystem implementation test suite](./test/filesystem-conformance.ts), which can also be pointed
at other implementations.

Browser filesystem adapters own the capabilities passed in `preopens` and the roots returned from
`getRoot`. A root may be shared by multiple descriptors and preopen names; the adapter is therefore
responsible for persistence and synchronization of shared mutations. Calling `dispose` on the
namespace returned by `createFilesystem` calls the adapter's optional `dispose` method once and
invalidates further preopen access. `WASIShim` does not currently cascade disposal, so embeddings
using external handles must retain and dispose their application-owned filesystem namespace or
adapter themselves. The bundled in-memory adapter keeps all state in memory and shares mutations
for the same file-data object.

# Features

## WASI Shim object for easy instantiation

An default instantiation object can be used via the `WASIShim` class in `@bytecodealliance/preview2-shim/instantiation`:

```typescript
import { WASIShim } from "@bytecodealliance/preview2-shim/instantiation";
import type {
    VersionedWASIImportObject,
    WASIImportObject,
} from "@bytecodealliance/preview2-shim/instantiation";

const shim = new WASIShim();

const unversioned: WASIImportObject = shim.getImportObject();
// console.log('unversioned', unversioned);
unversioned satisfies WASIImportObject;
unversioned satisfies VersionedWASIImportObject<"">;

const versioned: VersionedWASIImportObject<"0.2.3"> = shim.getImportObject({
    asVersion: "0.2.3",
});
//console.log('versioned', versioned);
versioned satisfies VersionedWASIImportObject<"0.2.3">;
```

The import object generated by `getImportObject` can be easily used in `instantiate()` calls
produced by [`jco transpile`][jco] (with `--instantiation=async`):

```js
import { WASIShim } from '@bytecodealliance/preview2-shim/instantiation';

// The code below assumes that you have output your transpiled WebAssembly component to `dist/transpiled`
import { instantiate } from './dist/transpiled/component.js';

const loader = async (path: string) => {
    const buf = await readFile(`./dist/transpiled/${path}`);
    return await WebAssembly.compile(buf.buffer as ArrayBuffer);
};
const component = await instantiate(loader, new WASIShim().getImportObject());

// TODO: Code that uses your component's exports goes here.
```

## Sandboxing

On Node.js, the preview2-shim provides host filesystem, environment, and network access by default,
matching the usual behavior of Node.js libraries. Browser defaults expose no filesystem preopens or
raw sockets. Both platforms can configure which capabilities a guest receives.

### Using WASIShim for sandboxing

The `WASIShim` class accepts a `sandbox` configuration option to control access:

```js
import { WASIShim } from "@bytecodealliance/preview2-shim/instantiation";

// Fully sandboxed - no filesystem, network, or env access
const sandboxedShim = new WASIShim({
    sandbox: {
        preopens: {}, // No filesystem access
        env: {}, // No environment variables
        args: ["arg1"], // Custom arguments
        enableNetwork: false, // Disable network access
    },
});

// Node.js only: map virtual paths to host paths
const limitedShim = new WASIShim({
    sandbox: {
        preopens: {
            "/data": "/tmp/guest-data", // Guest sees /data, maps to /tmp/guest-data
            "/config": "/etc/app", // Guest sees /config, maps to /etc/app
        },
        env: { ENV1: "42" }, // Only expose specific env vars
    },
});

const component = await instantiate(loader, sandboxedShim.getImportObject());
```

### Notes on sandboxing

- By default (when no options are passed), the shim is providing full access to match typical
  Node.js library behavior. In browsers, filesystem preopens remain empty until the application
  explicitly injects filesystem namespaces or selects the ephemeral file-data adapter.
- `sandbox.preopens` maps guest paths to Node.js host paths on Node.js. With
  `browserFilesystem`, the same option maps guest paths to capabilities understood by its adapter
  and overrides `browserFilesystem.preopens`. A custom `filesystem` can implement
  `createPreopens(preopens)` to interpret the provided properties and return its own
  `wasi:filesystem/preopens` namespace. The shim passes those properties through unchanged.
- Each `WASIShim` instance has its own isolated preopens, environment variables, and arguments.
  Multiple instances with different configurations will not affect each other.
- The direct preopen functions (`_setPreopens`, `_clearPreopens`, etc.) modify global state and
  affect all components not using `WASIShim` with explicit configuration. For isolation, prefer
  using `WASIShim` with the `sandbox` option containing `preopens` and `env`.
- When `sandbox.enableNetwork: false`, Node.js socket operations receive an instance-local denied
  network capability. Outbound HTTP is a separate Fetch capability; replace or omit the HTTP
  namespace when the embedding must deny it as well.

[jco]: https://www.npmjs.com/package/@bytecodealliance/jco

# License

This project is licensed under the Apache 2.0 license with the LLVM exception.
See [LICENSE](LICENSE) for more details.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this project by you, as defined in the Apache-2.0 license,
shall be licensed as above, without any additional terms or conditions.

### Host IO extensions

Opt-in providers can use the Node-only `@bytecodealliance/preview2-shim/io-worker`
entry point to operate on existing streams in the shim's IO worker. Host-selected
modules load lazily and share the worker's stream, future, and poll ownership rules.
Guest code cannot select extension modules.

The Node `wasi:tls` provider and its TLS policy live in
[`jco-std`](../jco-std/README.md#http-1), which wraps the supplied TCP streams
without opening a replacement connection.

---
_Source: https://npm.io/package/@bytecodealliance/preview2-shim · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
