Skip to content

feat(ext/node): implement node:wasi - #34089

Merged
littledivy merged 1 commit into
mainfrom
orch/issue-93
May 15, 2026
Merged

littledivy merged 1 commit into
mainfrom
orch/issue-93

Conversation

@divybot

@divybot divybot commented May 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the node:wasi polyfill, taking over #32413.

  • Adds ext/node/ops/wasi.rs: a WasiContext cppgc object exposing the WASI preview1 ABI (args/env, clocks, random, fd_, path_, sched_yield) backed by std::fs + std::io::stdin/stdout/stderr. Path-based ops resolve against preopened directories and are gated by Deno's PermissionsContainer (OpenAccessKind::Read|Write|ReadWrite) on the canonicalized path, refusing to escape the preopen root.
  • Rewrites ext/node/polyfills/wasi.ts from a stub to a full WASI class (constructor option validation, wasiImport, getImportObject, start, initialize) that delegates to WasiContext. Cross-VM-context support uses Object.prototype.toString for WebAssembly.Memory checks.
  • Lazy loaded: wasi.ts is registered via lazy_loaded_js, fronted by the existing thin wasi_esm.ts synthetic-ESM wrapper. The Rust ops aren't reachable until something actually imports node:wasi.
  • Adds ERR_WASI_NOT_STARTED (Node parity).
  • Enables wasi/test-wasi-options-validation.js, wasi/test-wasi-start-validation.js, wasi/test-wasi-initialize-validation.js in the node_compat suite, and removes wasi from IGNORED_TEST_DIRS so they're discovered.
  • Adds tests/unit_node/wasi_test.ts with 14 cases covering the constructor, getImportObject, real WASM start/initialize, and the import-object surface area.

Closes #24289
Closes #21025
Closes denoland/orchid#93

Notes

  • Other tests/node_compat/runner/suite/test/wasi/* tests aren't enabled because they go through tests/node_compat/runner/suite/test/fixtures/wasi-preview-1.js, which calls common.expectWarning('ExperimentalWarning', ...) for Node's WASI experimental warning. Deno doesn't emit that warning, so the fixture itself fails before the WASM runs. Enabling those tests is orthogonal to the WASI implementation and would require either a expectWarning shim or filtering at the fixture layer.
  • poll_oneoff, sock_*, proc_raise, path_filestat_set_times, fd_filestat_set_times return ERRNO_NOSYS — sufficient for the validation tests and the WASI interface surface, can be implemented incrementally as compat tests get enabled.

Test plan

  • cargo test unit_node::wasi_test — 14 tests pass
  • cargo test --test node_compat -- wasi-options-validation — pass
  • cargo test --test node_compat -- wasi-start-validation — pass
  • cargo test --test node_compat -- wasi-initialize-validation — pass
  • ./x lint — clean
  • ./x fmt — clean

🤖 Generated with Claude Code

Implements the `node:wasi` polyfill backed by Rust ops that talk
directly to the host filesystem (the Deno permissions container still
gates each path access with `OpenAccessKind`).

The polyfill ships as a lazy-loaded IIFE script (`wasi.ts`) plus a
thin synthetic ESM wrapper (`wasi_esm.ts`) — keeps node:wasi out of
startup work for programs that never `import "node:wasi"`.

Co-Authored-By: Divy Srivastava <[email protected]>
Co-Authored-By: Kaju <[email protected]>
Co-Authored-By: Bartek Iwańczuk <[email protected]>
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@littledivy
littledivy merged commit be72317 into main May 15, 2026
136 checks passed
@littledivy
littledivy deleted the orch/issue-93 branch May 15, 2026 18:59
littledivy added a commit to crowlKats/deno that referenced this pull request Jun 10, 2026
## Summary

Implements the `node:wasi` polyfill, taking over
[denoland#32413](denoland#32413).

- Adds `ext/node/ops/wasi.rs`: a `WasiContext` cppgc object exposing the
WASI preview1 ABI (args/env, clocks, random, fd_*, path_*, sched_yield)
backed by `std::fs` + `std::io::stdin/stdout/stderr`. Path-based ops
resolve against preopened directories and are gated by Deno's
`PermissionsContainer` (`OpenAccessKind::Read|Write|ReadWrite`) on the
canonicalized path, refusing to escape the preopen root.
- Rewrites `ext/node/polyfills/wasi.ts` from a stub to a full `WASI`
class (constructor option validation, `wasiImport`, `getImportObject`,
`start`, `initialize`) that delegates to `WasiContext`. Cross-VM-context
support uses `Object.prototype.toString` for `WebAssembly.Memory`
checks.
- Lazy loaded: `wasi.ts` is registered via `lazy_loaded_js`, fronted by
the existing thin `wasi_esm.ts` synthetic-ESM wrapper. The Rust ops
aren't reachable until something actually imports `node:wasi`.
- Adds `ERR_WASI_NOT_STARTED` (Node parity).
- Enables `wasi/test-wasi-options-validation.js`,
`wasi/test-wasi-start-validation.js`,
`wasi/test-wasi-initialize-validation.js` in the node_compat suite, and
removes `wasi` from `IGNORED_TEST_DIRS` so they're discovered.
- Adds `tests/unit_node/wasi_test.ts` with 14 cases covering the
constructor, `getImportObject`, real WASM `start`/`initialize`, and the
import-object surface area.

Closes denoland#24289
Closes denoland#21025
Closes denoland/orchid#93

## Notes

- Other `tests/node_compat/runner/suite/test/wasi/*` tests aren't
enabled because they go through
`tests/node_compat/runner/suite/test/fixtures/wasi-preview-1.js`, which
calls `common.expectWarning('ExperimentalWarning', ...)` for Node's WASI
experimental warning. Deno doesn't emit that warning, so the fixture
itself fails before the WASM runs. Enabling those tests is orthogonal to
the WASI implementation and would require either a `expectWarning` shim
or filtering at the fixture layer.
- `poll_oneoff`, `sock_*`, `proc_raise`, `path_filestat_set_times`,
`fd_filestat_set_times` return `ERRNO_NOSYS` — sufficient for the
validation tests and the WASI interface surface, can be implemented
incrementally as compat tests get enabled.

## Test plan

- [x] `cargo test unit_node::wasi_test` — 14 tests pass
- [x] `cargo test --test node_compat -- wasi-options-validation` — pass
- [x] `cargo test --test node_compat -- wasi-start-validation` — pass
- [x] `cargo test --test node_compat -- wasi-initialize-validation` —
pass
- [x] `./x lint` — clean
- [x] `./x fmt` — clean

Co-authored-by: divybot <[email protected]>
Co-authored-by: Divy Srivastava <[email protected]>
Co-authored-by: Kaju <[email protected]>
Co-authored-by: Bartek Iwańczuk <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement WASI 0.2 support for Deno Implement node:wasi

3 participants