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

@jellevdh/wcjs

v0.1.3

Published

Runtime, codegen, and CLI for using [WebAssembly components](https://component-model.bytecodealliance.org/) and [WASI P3](https://wasi.dev/roadmap#upcoming-wasi-03-releases) in the browser and Node.js. Call and expose asynchronous WebAssembly code with er

Readme

wcjs

Runtime, codegen, and CLI for using WebAssembly components and WASI P3 in the browser and Node.js. Call and expose asynchronous WebAssembly code with ergonomic, fully-typed TypeScript bindings. Try the live demo.

Warning: This project is extremely experimental. APIs will change, things will break, and it's not easy to use yet. All code was written by LLM, with plenty of review and feedback. That said, a large test suite passes (including the component model spec tests and ported wasmtime integration tests) and it does seem to work.

Implements the full async component model including streams, futures, and concurrent tasks, with both stackless and stackful async ABIs.

How it compares to jco

| | wcjs | jco | |---|---|---| | Maturity | Extremely experimental | More usage and production experience | | Dependencies | Zero. Parser, codegen, and runtime all from scratch in TypeScript | Compiles wasmtime-environ and other Rust crates to Wasm for use in its JS-based compiler | | Language | Fully TypeScript (even generated code) | Mix of JavaScript and Rust | | Generated size | Small. Generated code calls into a shared typed runtime (@jellevdh/wcjs/runtime) | Large. Each component gets its own copy of lift/lower helpers | | JS components | No, embedding/running Wasm components only | Yes, can create components from JS |

Note: Currently Node.js only — the WASI host implementation uses low-level Node APIs (net, fs, etc.). Deno and Bun are not yet supported.

What's supported

WASI P3

Targets WASI P3 version 0.3.0-rc-2026-02-09. WASI P2 compatibility stubs are provided for 0.2.0 through 0.2.6.

| Interface | Node.js | Browser | |---|---|---| | wasi:cli (args, env, exit, stdio) | Yes | Yes | | wasi:clocks (monotonic, wall) | Yes | Yes | | wasi:random | Yes | Yes | | wasi:filesystem (read, write, stat, readdir, remove, preopens) | Yes | No | | wasi:sockets (TCP, UDP, DNS) | Yes | No | | wasi:http (client, handler) | Yes | No |

Tests:

  • Go stdlib tests: Go standard library tests (os, time, path/filepath, net) compiled to wasip3 with a custom Go fork and run against wcjs
  • Ported wasmtime tests: the Rust integration tests wasmtime uses to test its own wasip3 implementation, ported and passing on wcjs

Async component model

Full implementation of the async component model: sync/async lifting and lowering, streams, futures, tasks, subtasks, waitable sets, backpressure, resources, error contexts, and cooperative threading.

Tested by all 24 spec WAST tests from the component-model repo, as well as indirectly by the WASI P3 tests above which exercise the async component model end-to-end. Tracks the component-model spec at c7176a5 (2026-02-17).

JavaScript integration

npx @jellevdh/wcjs generate produces a JS module with an async API to instantiate and interact with a component. Exported functions map to async JS functions; streams and futures map to handle numbers. The generated .d.ts file provides full TypeScript types for all imports and exports, so host implementations are type-checked at compile time.

Demo

The demo/ directory contains a complete example: a Rust WASI P3 component running in both Node.js and the browser.

WIT definition

package demo:calculator;

interface host {
  slow-double: async func(n: u32) -> u32;
  log: func(msg: string);
}

interface calc {
  add: func(a: s32, b: s32) -> s32;
  double-and-add: async func(a: u32, b: u32) -> u32;
}

world calculator {
  import host;
  export calc;
}

Guest code (Rust)

impl Guest for Component {
    fn add(a: i32, b: i32) -> i32 {
        a + b
    }

    async fn double_and_add(a: u32, b: u32) -> u32 {
        let (da, db) = futures::join!(host::slow_double(a), host::slow_double(b));
        da + db
    }
}

The guest calls slow-double concurrently on both arguments using futures::join!. With a 1-second delay per call, both resolve in ~1s instead of ~2s.

Host code (TypeScript)

import { instantiate } from './generated/calculator.js';

const instance = await instantiate({
  'demo:calculator/host': {
    'slow-double': async (n: number) => {
      await new Promise(r => setTimeout(r, 1000));
      return n * 2;
    },
    log: (msg: string) => console.log(msg),
  },
});

const calc = instance['demo:calculator/calc'];
console.log(await calc.add(3, 4));           // 7
console.log(await calc.doubleAndAdd(5, 7));  // 24 (in ~1s, not ~2s)

Async WIT functions map to async JS functions that return a Promise. The guest suspends until it resolves. All exports are async and return Promises. The generated .d.ts provides full types for imports and exports.

Building and running

# Build guest, generate bindings, bundle for browser
npm run demo:build

# Run in Node.js
npm run demo:node

# Serve browser demo
npm run demo:serve

CLI

# Run a WASI component
npx @jellevdh/wcjs run <component.wasm> [--dir guest=host] [--env K=V] [--inherit-env] [--inherit-network] [--no-jspi] [-- guest-args...]

# Generate importable JS + .d.ts + .core.wasm from a component
npx @jellevdh/wcjs generate <component.wasm> [-o <dir>] [--name <name>] [--no-jspi]

# Generate TypeScript host type declarations from WIT
npx @jellevdh/wcjs gen-types <p3-wit-path>... [--p2 <p2-wit-path>...] [-o <output>]

npx @jellevdh/wcjs run

Instantiates and runs a WASI component directly. Supports filesystem mapping, environment variables, and network access:

npx @jellevdh/wcjs run my-app.wasm --dir /data=./local-data --inherit-env --inherit-network

npx @jellevdh/wcjs generate

Generates a standalone ES module from a component binary. The output includes a .js file, .d.ts type declarations, and .core.wasm files:

npx @jellevdh/wcjs generate my-component.wasm -o lib/ --name my-component

The generated code imports from @jellevdh/wcjs/runtime and @jellevdh/wcjs/wasi, and can be bundled for the browser with esbuild or similar.

How it works

A WebAssembly component bundles one or more core wasm modules together with type information and canonical ABI adapter instructions describing how to convert between wasm's flat integer/float values and high-level types like strings, records, variants, lists, and streams. wcjs processes these components in three steps:

  1. Parse. A from-scratch binary parser reads the .wasm bytes into an in-memory IR, extracting core modules, type definitions, imports, exports, and adapter instructions.

  2. Generate code. The codegen analyzes the parsed component's types and adapter instructions, then generates JavaScript that instantiates the core wasm modules via WebAssembly.instantiate and wires them together with trampoline functions that lift (wasm to JS) and lower (JS to wasm) values according to the canonical ABI. The generated code delegates to the shared wcjs/runtime package for async operations.

  3. Generate types. A .d.ts file is generated with full TypeScript types for all imports and exports. WIT types map to TypeScript: records become interfaces, variants become discriminated unions, enums become string unions, async functions become Promise-returning functions. Hosts get compile-time type checking against the component's interface. Types can also be generated directly from WIT files via wcjs gen-types.

wcjs generate bundles all of this into a self-contained ES module (.js + .d.ts + .core.wasm files). The output uses the browser's standard WebAssembly.compileStreaming / WebAssembly.instantiate APIs with no custom loader or bundler plugin required.

Async runtime

The runtime implements the async component model on top of JavaScript promises. Each async export call creates a task; async import calls create subtasks backed by promises that deliver events when the host resolves them. Streams are pairs of readable/writable ends with a shared buffer and backpressure, where writes from one component resolve reads in another. Futures are one-shot streams. An event loop drives it all: the guest yields control back to the host, the event loop waits for promises to settle, delivers events, and calls back into the guest until the task completes.

For guests that make synchronous imports into asynchronous hosts, wcjs uses JSPI (WebAssembly.promising / WebAssembly.Suspending) to suspend the wasm stack while a promise resolves. JSPI is optional but most guests need it. Currently available in Chrome and Node.js; all major browsers plan to ship support in 2026.

WASI host

wcjs includes a WASI P3 host implementation (src/wasi/) that maps the WASI spec interfaces to platform APIs. On Node.js this includes filesystem, sockets, and HTTP. In the browser it covers clocks, random, stdio, and environment. WASI P2 compatibility stubs let existing P2 guests run without modification.

Development

No build step. TypeScript runs directly via node --experimental-transform-types.

Quick start

npm install
npm test        # runs unit tests + WAT/WAST integration tests
npm run check   # type check with tsgo

This requires wasm-tools in your PATH (install via cargo install wasm-tools). Guest integration tests and wasmtime P3 tests will be skipped — see below for full setup.

# Filter tests by name
npm test -- stream
npm test -- "test4-deferred"

# With runtime tracing
P3_TRACE=1 npm test -- test1-callback

Full test setup

To run all tests (including Go guest and wasmtime P3 integration tests), clone sibling repos into the same parent directory. The pinned dependency versions are in deps.env — use these commits for reproducible builds:

parent/
  wcjs/                  # this repo
  component-model/       # spec reference (not needed for tests, useful for development)
  go/                    # Go wasip3 fork (needed for Go guest tests)
  wasmtime/              # wasmtime (needed for wasmtime P3 tests)
# Load pinned commit SHAs
source deps.env

# Component model spec (reference only)
git clone https://github.com/WebAssembly/component-model ../component-model

# Go wasip3 fork — build the toolchain
git clone https://github.com/jellevandenhooff/go ../go
cd ../go && git checkout $GO_COMMIT && cd src && ./make.bash && cd -

# Wasmtime — build test programs
git clone https://github.com/bytecodealliance/wasmtime ../wasmtime
cd ../wasmtime && git checkout $WASMTIME_COMMIT && git submodule update --init && cargo test -p test-programs-artifacts --no-run && cd -

Then build the guest test components:

bash test/guest/build.sh              # build Go + Rust guest components
bash test/guest/copy-wasmtime-tests.sh # copy wasmtime P3 test binaries
npm test                               # all ~410 tests

Project structure

cli.ts                        CLI entry point (run, generate, gen-types)
src/
  runtime/                    Async component model runtime
    index.ts                    Package exports
    types.ts                    EventCode, CallbackCode, SubtaskState, constants
    component-state.ts          Per-component tables, exclusive lock, backpressure
    event-loop.ts               EventLoop (drives callback-mode tasks)
    stream.ts                   SharedStreamImpl + ReadableStreamEnd/WritableStreamEnd
    future.ts                   ReadableFutureEnd/WritableFutureEnd (one-shot)
    subtask.ts                  Subtask (tracks async import calls)
    task.ts                     AsyncTask (id, result, context storage)
    waitable.ts                 Waitable base class (has pending event, belongs to set)
    waitable-set.ts             WaitableSet (poll/wait for events)
    handle-table.ts             Generic sparse array for handles
    call-context.ts             Cross-component call support
    jspi.ts                     JSPI helpers (promising/suspending)
    trace.ts                    Runtime tracing (P3_TRACE=1)
  parser/                     Component binary parser
    parse.ts                    Entry point: Uint8Array → ParsedComponent
    types.ts                    IR types for parsed component binary
    binary-reader.ts            Low-level binary cursor (LEB128, strings, vectors)
    component-parser.ts         Main component binary parser
    canonical-parser.ts         Canon lift/lower/builtin opcodes
    type-parser.ts              Component type section parser
    section-parsers.ts          Other section parsers
    name-section-parser.ts      Name section parser
    print.ts                    WAT-like text printer for ParsedComponent
  codegen/                    Code generator
    index.ts                    Package exports
    codegen.ts                  Entry point: ParsedComponent → generated source
    link.ts                     Phase 1: index space linking
    link-types.ts               Linked IR types (trampolines, instances, memories)
    link-host-types.ts          Instance type scope resolution for host imports
    emit.ts                     Phase 2: JS/TS source emission
    flatten.ts                  Canonical ABI type flattening
    host-types.ts               Host import type descriptors and TS conversion
  wasi/                       WASI host implementations
    index.ts                    Package exports
    wasi-host.ts                Node.js WASI host
    wasi-browser.ts             Browser WASI host
    wasi-shared.ts              Shared WASI helpers (P2/P3 stubs, version maps)
    wasi-filesystem.ts          Filesystem implementation
    wasi-sockets.ts             TCP/UDP/DNS implementation
    wasi-http.ts                HTTP client/handler implementation
    wasi-types.generated.ts     Generated TypeScript types from WIT
  wit/                        WIT parser and type emitter
    parser.ts                   WIT text parser (tokenizer + recursive descent)
    emit-types.ts               WIT → TypeScript type declarations
test/
    runner.ts                   Custom parallel test runner
    run.ts                      Entry point (imports all tests, calls run())
    integration.ts              WAT + spec WAST integration pipeline
    generate.test.ts            End-to-end test for standalone codegen
    guest-integration.ts        Go/Rust guest integration tests
    pipeline.ts                 Test pipeline helpers
    wasmtime-p3.ts              Ported wasmtime P3 tests
    unit/                       Runtime unit tests
    wat/                        Custom WAT integration tests
    spec/                       Component model spec WAST tests
    guest/                      Go and Rust guest test components
    imports/                    Host import implementations for tests
demo/                         Calculator demo (Rust guest, browser + Node.js)

License

Dual-licensed under MIT or Apache 2.0, at your option.