Assertion failures throw an assert.AssertionError with Node 24.22's
generatedMessage, code, actual, expected, operator and diff properties,
in Node's key order. new AssertionError(options) validates its options
and builds Node's message from operator, actual and expected.
AssertionError type annotations, instanceof and assert.throws(fn,
AssertionError) compile.
Failure paths record actual, expected and operator before they throw;
passing assertions do no extra work. The deep forms lower through a
per-type function that returns the verdict, so the operands stay call
temporaries. assert.equal and notEqual inspect their operands only when
they fail.
Values without a checked-dynamic form, and values whose type can be
cyclic, record undefined.
crypto.createSecretKey and generateKey/generateKeySync for "hmac" and
"aes" return SecretKeyObject values, native dyn handles over a copy of
the key bytes. The type and symmetricKeySize getters, export() as a
Buffer or a JWK, equals(), instanceof KeyObject, String(),
JSON.stringify and util.inspect follow Node 24.22, as do the argument
checks, their order and their errors. createHmac and hkdf/hkdfSync
accept these keys. toCryptoKey() and KeyObject.from() need WebCrypto
values and are refused with SC2020.
Dyn handle ops gain a @@toStringTag that differs from the class name
and a flag for views with no properties, which util.inspect prints at
any depth. KeyObject method calls dispatch through dynInvoke.
crypto.timingSafeEqual accepts every TypedArray, DataView, Buffer,
ArrayBuffer and SharedArrayBuffer and compares their bytes. Values of
other types throw Node 24.22's ERR_INVALID_ARG_TYPE for buf1 and then
buf2, before the byte lengths are compared. Views of every element kind
keep the typed call; other arguments take the checks at run time.
randomFillSync accepts every TypedArray, DataView, Buffer, ArrayBuffer and
SharedArrayBuffer and returns its argument at its own type. Offsets and
sizes count elements and are checked in bytes with Node 24.22's
ERR_OUT_OF_RANGE and ERR_INVALID_ARG_TYPE errors. randomFill fills the
same buffers and calls back in a later macrotask, or synchronously when
nothing is filled, as Node does.
randomInt takes a callback in both forms, and its errors carry Node's
received values and the max or "max - min" label. Values come from a
6 KiB cache, as in Node, so a callback runs on the next tick while the
cache has data and after an asynchronous refill when it is empty.
randomUUID and the new randomUUIDv7 validate options.disableEntropyCache
and draw from a 128-UUID batch unless it is set.
A non-u8 view passed to randomFillSync no longer needs a Uint8Array
type, and the bytes callback adapters pass views of any element kind
and dyn values through.
Blob and File (globals and node:buffer exports) compile to native
handles in the new scr_blob.c, following Node 24.22's
lib/internal/blob.js and file.js. A Blob is a window over a shared,
immutable byte store plus the byte length of each part. Sources (strings,
typed arrays, DataView, ArrayBuffer, Buffer, other Blobs, Set and Map)
convert as a Web IDL sequence, with each non-buffer part converted to a
string, before the options are read, and are copied when the Blob is
built. The constructors throw Node's Web IDL TypeErrors and its
ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE and ERR_MISSING_ARGS errors,
and read and convert their options in Node's order. The type is
lowercased, or cleared when it holds a character outside U+0020..U+007E.
endings: "native" rewrites CRLF, CR and LF to the platform's line break.
File takes its name with lone surrogates replaced and lastModified as a
number (Date.now() when absent).
slice() converts its offsets as a [Clamp] long long (rounded half to
even) and keeps the parts Node's data queue keeps. text(), bytes() and
arrayBuffer() settle on the same microtask turn as in Node, which depends
on the part count. util.inspect prints Node's `Blob { size, type }` and
`File { ..., name, lastModified }` forms, with `[Blob]` past the depth
limit. String() and toString() give the class tag, JSON.stringify gives
{}, and structuredClone returns a new Blob or File over the same bytes.
instanceof works for both spellings. stream(), textStream() and the
Object.prototype members other than toString() fail at compile time.
Non-array iterables other than Set and Map throw SC2020.
Three handle-table additions support this: a structuredClone hook, a
JSON `{}` flag, and a bracketed past-depth inspect flag. scr_blob.c is an
optional unit selected by dynAsync, because the dynamic dispatch path
boxes its reads as dyn promises through scr_async_dyn.c.
Corpus 5285-5290 and a node-types fixture check the behavior against
Node.
Pin Node v24.22.0 (commit f14cd3aa7bf9, Undici 7.29.1, OpenSSL 3.5.8) in
.node-version, Dockerfile.sandbox, the docs matrix fallback, the
compatibility pin, the fetch profile, and process.version. A node-pin test
checks that these pins agree. The Node compatibility snapshot is
regenerated from the v24.22.0 API docs; the new stream_iter chapter maps
to node:stream/iter, and the SuiteContext rows no longer match the
TestContext evidence.
Runtime and compiler changes follow Node 24.22 behavior:
- fs.read, fs.readSync, and FileHandle.read validate the position before
the zero-length return.
- fs.statfs results include frsize; Windows reads
FileFsFullSizeInformation and reports bfree and bavail separately.
- fs.utimes, futimes, and lutimes keep nanosecond precision.
- ServerResponse sets writableFinished where 'finish' is emitted and runs
end() callbacks before the 'finish' listeners while the socket is still
attached; a request read to 'end' closes before its response.
- socket.write(string, 'buffer') throws ERR_UNKNOWN_ENCODING.
- URL protocol-setter rejections keep the current URL, the host setter
no longer leaves a "/." escape when it adds a port to a "//" path, and
new URLSearchParams(null) parses "null".
- util.stripVTControlCharacters uses Node 24.22's ANSI pattern,
util.styleText accepts #RGB and #RRGGBB colors, and
util.types.isDataView has its JS name and length.
- structuredClone and AbortSignal.any use the "cannot be converted to
sequence" message.
- crypto.getCiphers, getHashes, and constants match Node 24.22.
- dns.lookup, net.connect, and tls.connect throw ERR_INVALID_ARG_VALUE for
hosts with null bytes.
- fs.readFile validates options.buffer and refuses its valid forms;
httpValidation and certificateCompression refuse by name.
- url.domainToASCII, url.domainToUnicode, and url.parse hostnames follow
ada 4.0: ASCII domains are lowercased without checking their xn--
labels, the RFC 5893 rule checks how LTR labels end and how RTL labels
start, a Punycode label whose decoded form begins with "xn--" fails, and
ToUnicode decodes only labels that pass the ToASCII checks. The url
legacy test cases are regenerated with Node 24.22.
Corpus programs 5275-5279 cover the new behavior. 1640, 2283, 2599, and
3136 are updated where they pinned Node 24.15 output.
- Support `new Console(...)` over process stdio and writable streams
- Write `log`/`info`/`debug`/`error`/`warn` output like Node, including `ignoreErrors`
- Mark the `Console` class as partially supported in the compatibility data
- Support `arrayBuffer()` from `node:stream/consumers`
- Print ArrayBuffer and SharedArrayBuffer values like Node
- Mark the stream consumers as partially supported in the compatibility data
- NoThrow diagnostics name compiler-resolved Node errors (class and message)
and explain parameters the frontend compiles as T | undefined because a
caller passes a possibly missing value (for example xs[i]!), naming that
call.
- Synthetic dynamic-class helpers (%dyn.*) carry the location of the code
that first needed them; they are no longer bound to annotations there.
- Int32 hints only parenthesize where needed; the NoThrow hint no longer
suggests try/catch, which does not discharge the contract.
- Diagnostics snapshots and TypeScript preflight/order baselines for the new
fixtures.
- Docs: /docs/contracts and a limitations entry.
The runtime answers like libuv 1.51's uv_available_parallelism, which
Node's os.availableParallelism() returns: on Linux the CPUs in the
process's affinity mask, lowered to a smaller cgroup (v2 cpu.max or v1
CFS) CPU quota; on Darwin hw.activecpu, hw.logicalcpu or hw.ncpu; on
Windows GetSystemInfo's processor count; at least 1. WASI answers 1, as
the dynamic island does.
Parallel programs (tsc-ts --checkers) need it to size their thread pools.
Corpus 4598 pins the value against the host's Node.
The new docs page (/docs/threads) explains @scriptc/threads: a runnable
example that publishes a million-order ledger and sends it to four
workers, verified under Node.js 24 and as a scriptc executable; what
publish accepts and refuses, and that a refused publish leaves the graph
unchanged; the frozen-object TypeErrors of the write guard; a comparison
with Node's structured clone (constant-time sends, preserved classes and
identity, immortal objects) and the three rules that make a program
behave the same under both; the automatic sharing of deeply frozen
untyped data; and the cost model. The limitations page gains a Published
graphs section (immortality, class and identity differences, write-check
evaluation order, private fields) and links the new page from the
worker-threads section.
This is the first page added since the migration, so the route-test
fixture now accepts pages without a legacy URL, and the agent guide's
checklist for new pages names the fixture.
- Preserve callback identity, receiver binding, and class references across unions and collections.
- Track record field presence independently of undefined values and improve native runtime behavior.
- Expand differential coverage and streamline CI bootstrap and compiler rebuild checks.
- Add native worker execution with isolated module state, structured messages, and lifecycle controls.
- Support shared buffers and integer atomics with coordinated runtime ownership and cancellation.
- Extend compiler, runtime-pack, differential, and compatibility coverage for native concurrency.
* Add Node 24 filesystem link support
* Use executable extensions in Windows link fixtures
* Remove Windows links without walking their targets
* Match Windows symlink inference and Buffer validation
* Match Node Windows symlink paths and fallback state
* Preserve Windows errors when following filesystem links
* feat: support Node 24 filesystem timestamp operations
* test: record frontend baselines for timestamp fixtures
* test: link timestamp validation into the runtime smoke test