Define Node stdlib compatibility behavior including module resolution boundaries, support tiers, and deterministic fallback errors.
The require system MUST NOT contain inline stubs or shims for third-party npm packages. Packages that are not Node.js built-in modules SHALL resolve exclusively through sandboxed node_modules filesystem resolution.
- WHEN sandboxed code calls
require('chalk')orrequire('supports-color') - THEN the require system MUST attempt filesystem resolution from sandboxed
node_modulesand MUST NOT return a hardcoded stub
- WHEN sandboxed code requires a third-party package not present in sandboxed
node_modules - THEN the require system MUST throw a standard "Cannot find module" error
When node-stdlib-browser provides a polyfill for a Node built-in module, the require system MUST load that polyfill through the standard polyfill loader rather than returning a custom inline stub.
- WHEN sandboxed code calls
require('tty') - THEN the require system MUST load
tty-browserifyvia the polyfill loader, not a hand-rolled stub
- WHEN sandboxed code calls
require('constants') - THEN the require system MUST load
constants-browserifyvia the polyfill loader, not a hand-rolled stub
Node built-in modules that have no node-stdlib-browser polyfill and no bridge implementation SHALL be handled by pre-registered stub entries in the module cache, not by inline conditionals in the require function body.
- WHEN sandboxed code calls
require('v8') - THEN the module MUST resolve from a pre-populated
_moduleCacheentry set during isolate setup
- WHEN sandboxed code accesses
require('v8').getHeapStatistics() - THEN the stub MUST return a plausible heap statistics object without throwing
Known gaps in node-stdlib-browser polyfills (missing methods, incorrect behavior) SHALL be fixed by a dedicated patch function applied after polyfill evaluation, not by inline conditional blocks scattered in the require function.
- WHEN the
utilpolyfill is loaded and lacksformatWithOptions - THEN the patch layer MUST add a
formatWithOptionsimplementation that delegates toutil.format
- WHEN the
urlpolyfill is loaded - THEN the patch layer MUST wrap
URLto handle relativefile:URLs (e.g.,file:.) by falling back toprocess.cwd()as base
- WHEN the
pathpolyfill is loaded - THEN the patch layer MUST ensure
path.win32andpath.posixexist and MUST wrappath.resolveto prependprocess.cwd()when no absolute path argument is provided
- WHEN a polyfill module has no known gaps (e.g.,
events,buffer) - THEN the patch layer MUST return the polyfill exports unmodified
Every Node.js core module referenced in the stdlib compatibility matrix SHALL be classified into exactly one of five tiers: Bridge, Polyfill, Stub, Deferred, or Unsupported.
- WHEN a Node.js core module is added to or already exists in the compatibility matrix
- THEN it MUST carry an explicit tier classification with defined runtime behavior
- WHEN a contributor checks the compatibility matrix for a module's support level
- THEN the tier, supported API surface, and runtime behavior for unsupported APIs MUST be clearly documented
APIs classified as unsupported within any tier MUST throw a descriptive error following the format "<module>.<api> is not supported in sandbox" rather than returning undefined or silently failing.
- WHEN sandboxed code calls
fs.watch()(a known-unsupported API in the fs bridge) - THEN the call MUST throw an error with message matching
"fs.watch is not supported in sandbox"
- WHEN sandboxed code requires an unsupported (Tier 5) module and calls a method on it
- THEN the method call MUST throw an error indicating the module is not supported in sandbox
Modules classified as Deferred (Tier 4) SHALL be requireable without error, returning a stub object whose methods throw descriptive errors on invocation.
- WHEN sandboxed code calls
require("net") - THEN the call MUST succeed and return a stub object
- WHEN sandboxed code calls
require("net").createConnection() - THEN the call MUST throw an error indicating the API is not yet supported
Modules classified as Unsupported (Tier 5) SHALL throw immediately when required, indicating they will not be implemented.
- WHEN sandboxed code calls
require("cluster") - THEN the call MUST throw an error indicating the module is not supported in sandbox
The following fs watcher APIs SHALL be classified as Deferred with deterministic error behavior: watch, watchFile, and fs/promises.watch. The sandbox VFS/kernel has no inotify/kqueue/FSEvents-equivalent primitive, so these APIs MUST fail fast instead of hanging while waiting for events that can never arrive. The APIs chmod, chown, link, symlink, readlink, truncate, utimes, access, and realpath SHALL be documented as implemented (Bridge tier), delegating to the VFS with permission checks.
- WHEN sandboxed code calls
fs.watch() - THEN the call MUST throw
"fs.watch is not supported in sandbox — use polling"
- WHEN sandboxed code iterates
require("fs/promises").watch(...) - THEN the iterator MUST reject with
"fs.promises.watch is not supported in sandbox — use polling" - AND it MUST preserve Node-compatible
ERR_INVALID_ARG_TYPE,ERR_INVALID_ARG_VALUE, andAbortErrorvalidation behavior before the deferred unsupported error path
- WHEN sandboxed code calls
fs.access("/some/path", callback) - THEN the call MUST execute normally via the fs bridge without error
Bridge-provided fs APIs SHALL throw Node-compatible validation errors before asynchronous dispatch when the argument contract is violated.
- WHEN sandboxed code calls callback-style APIs such as
fs.open(),fs.close(),fs.exists(),fs.stat(), orfs.mkdtemp()without a valid callback - THEN the bridge MUST throw
ERR_INVALID_ARG_TYPEsynchronously instead of returning a Promise or reporting the validation failure through the callback
- WHEN sandboxed code passes an invalid encoding to
fs.readFile*(),fs.readdir*(),fs.readlink*(),fs.writeFile*(),fs.appendFile*(),fs.realpath*(),fs.mkdtemp*(),fs.ReadStream(),fs.WriteStream(), orfs.watch() - THEN the bridge MUST throw
ERR_INVALID_ARG_VALUE - AND invalid numeric
start/endstream options or fd/path argument types MUST throwERR_INVALID_ARG_TYPEorERR_OUT_OF_RANGEwith Node-compatible names
child_process.fork() SHALL be classified as Unsupported and MUST throw a deterministic error explaining that IPC across the isolate boundary is not supported.
- WHEN sandboxed code calls
require("child_process").fork("script.js") - THEN the call MUST throw an error matching
"child_process.fork is not supported in sandbox"
The crypto module SHALL be classified as Stub (Tier 3). getRandomValues() and randomUUID() MUST use host node:crypto cryptographically secure randomness when available, and MUST throw deterministic unsupported errors if secure host entropy cannot be obtained. subtle.* methods MUST throw unsupported errors.
- WHEN a user or contributor reads the crypto section of the compatibility matrix
- THEN the entry MUST document host-backed secure randomness behavior for
getRandomValues()/randomUUID()and MUST NOT claimMath.random()-backed entropy
- WHEN sandboxed code calls
crypto.getRandomValues(array)and host secure entropy is unavailable - THEN the call MUST throw a deterministic error indicating
crypto.getRandomValuesis not supported in sandbox
- WHEN sandboxed code calls
crypto.randomUUID()and host secure entropy is unavailable - THEN the call MUST throw a deterministic error indicating
crypto.randomUUIDis not supported in sandbox
- WHEN sandboxed code calls
crypto.subtle.digest("SHA-256", data) - THEN the call MUST delegate to host
node:cryptoand return an ArrayBuffer containing the hash
- WHEN sandboxed code calls any
crypto.subtlemethod (digest, encrypt, decrypt, sign, verify, generateKey, importKey, exportKey) - THEN the operation MUST delegate to host
node:cryptovia the_cryptoSubtlebridge ref - AND all cryptographic material MUST be transferred as base64-encoded JSON across the isolate boundary
- AND CryptoKey objects in the sandbox MUST be opaque wrappers holding serialized key data
The following modules SHALL be classified as Deferred (Tier 4): net, tls, readline, perf_hooks, async_hooks, worker_threads, diagnostics_channel. The following modules SHALL be classified as Unsupported (Tier 5): dgram, http2 (full), cluster, wasi, inspector, repl, trace_events, domain.
- WHEN sandboxed code calls
require("net") - THEN the call MUST return a stub object (Tier 4 behavior)
- WHEN sandboxed code calls
require("cluster") - THEN the call MUST throw immediately (Tier 5 behavior)
The compatibility matrix MUST NOT contain entries for third-party modules that are no longer bridged or stubbed in code. Specifically, the @hono/node-server entry SHALL be removed.
- WHEN a third-party module bridge has been deleted from the codebase
- THEN its entry MUST be removed from the compatibility matrix in the same or next change
Builtin module resolution through helper APIs MUST return builtin identifiers directly instead of attempting filesystem lookup.
- WHEN sandboxed code calls
require.resolve("fs") - THEN the call MUST succeed and return a builtin identifier for
fs(for example"fs"or"node:fs")
- WHEN sandboxed code calls
createRequire("/app/entry.js").resolve("path") - THEN the call MUST succeed and return a builtin identifier for
path(for example"path"or"node:path")
For bridged built-in modules exposed to ESM, the runtime MUST provide both default export access and named-import access for supported APIs.
- WHEN sandboxed ESM code executes
import { readFileSync } from "node:fs" - THEN
readFileSyncMUST resolve to a callable function equivalent todefault.readFileSync
- WHEN sandboxed ESM code executes
import { sep } from "node:path" - THEN
sepMUST resolve to the same value asdefault.sep