npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bytecodealliance/preview2-shim

v0.28.0

Published

WASI Preview2 shim for JS environments

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:

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:

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:

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

This keeps permission prompts, handle acquisition, persistence, and synchronization policy in application code. sandbox.enableNetwork: false denies raw TCP, UDP, DNS, and outbound HTTP.

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

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. 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, 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:

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 (with --instantiation=async):

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:

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, socket operations and outbound HTTP receive instance-local denied network capabilities.

License

This project is licensed under the Apache 2.0 license with the LLVM exception. See 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, which wraps the supplied TCP streams without opening a replacement connection.