173 Commits
Author SHA1 Message Date
Malte UblandClaude Opus 5.5 f14997776b Box TextEncoder and TextDecoder records as checked-dynamic handles
A codec stored in untyped storage (hono's StreamingApi keeps
`this.encoder = new TextEncoder()` in a JavaScript class field) had no
dynamic representation and threw SC1101 at run time. The codec records
now cross 'unknown' slots as handles of two new tags that hold the record
itself, so identity and a decoder's streaming state survive the round
trip, and checked casts unbox the same record.

The handles answer encode, encodeInto and decode (with options objects),
the encoding, fatal and ignoreBOM properties, method values with Node's
ERR_INVALID_THIS, instanceof, String() tags and JSON's {}. The unit
scr_text_codec_dyn.c links only into programs that convert a codec to or
from an untyped value (the textCodecDyn runtime feature, found with the
dgram carrier walk, now shared).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:33:06 -07:00
Chris Tate 1221104388 Merge main and fix CI 2026-10-23 07:50:09 -05:00
Chris Tate 19e0fe8bcd Merge main and read cipher options through getters and prototypes 2026-10-23 05:33:14 -05:00
Chris Tate 7dfc96728d Merge main 2026-10-23 01:19:49 -05:00
Chris Tate 5c5d0f5a0f Merge main 2026-10-23 00:42:41 -05:00
Chris Tate 6e71385a1a Type user code from npm package declarations at a checked, identity-preserving boundary (#1942) 2026-10-23 00:33:02 -05:00
Chris Tate 0314d9db3e Dispatch checked-dynamic method calls on method ids 2026-10-22 23:52:25 -05:00
Chris Tate da289bb593 Support writev on Transform and PassThrough, and runtime stream option values 2026-10-22 23:13:49 -05:00
Chris Tate fc31dd5060 Enumerate each record in the key order its object literal wrote 2026-10-22 22:56:12 -05:00
Malte UblandClaude Opus 5.5 14966de563 Move adoption into its own runtime unit behind the declAdopt feature
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 19:35:40 -07:00
Chris Tate 53c43dd140 Merge main 2026-10-22 18:44:10 -05:00
Chris Tate 81891d55f7 Fix boxed record field hooks and moving key writes, and merge main 2026-10-22 18:19:14 -05:00
Chris Tate dc2b238df7 Revert "Dispatch checked-dynamic method calls on method ids (#1851)" 2026-10-22 18:02:51 -05:00
Chris Tate 5372c69459 Pass { signal } to stream operator callbacks and Duplex.from bodies 2026-10-22 17:50:29 -05:00
Chris Tate 846552b0e2 Support crypto.getCipherInfo, AES-CCM and the AES key wrap ciphers
getCipherInfo(nameOrNid[, options]) runs in a new runtime unit,
scr_cipher_info.c, over a table that scripts/gen-cipher-info.mjs generates
from Node 24.22's getCipherInfo. The table covers every cipher OpenSSL
names, including the ones without a native implementation. Lookups match
names case-insensitively and accept OpenSSL's nids. The unit applies
cipher.js's argument checks and GetCipherInfo's keyLength and ivLength
rules, and returns the info object in Node's key order. CipherInfo maps
to a checked-dynamic value, so TypeScript and JavaScript code receive
Node's object. Reading the nid Node leaves out for the SIV and SM4 GCM,
CCM and XTS ciphers, where the declared type gives number, throws a
TypeError.

createCipheriv and createDecipheriv support aes-128/192/256-ccm (and the
id-aesN-ccm names) over OpenSSL's ccm128 steps. They follow Node's tag and
IV lengths, the plaintextLength requirement, the message-length caps and
the one-update rule, and report a failed authentication from final().

They also support the RFC 3394 and RFC 5649 key wrap ciphers (aes-N-wrap,
aesN-wrap, id-aesN-wrap, the -pad forms and the -inv ciphers) over
wrap128.c's routines, with Node's lengths, integrity failures and
one-update rule.

The new names follow the existing ones in the cipher table, so the lookup
cost of the existing ciphers is unchanged.
2026-10-22 17:18:54 -05:00
Chris Tate 5c29845909 Support Readable.fromWeb over web ReadableStreams 2026-10-22 15:23:28 -05:00
Chris Tate f4365b7eea Cache each constant method name's id in a slot
A checked-dynamic method call looked its name up in the method table on
every call: a strlen, a hash and a byte comparison of the name.

The compiler now gives each method-name constant an i32 slot that starts
at -1 and passes it with the call (scr_dyn_invoke_prepared_id, and the
Buffer method entries, which forward it). The first call stores the
name's id in the slot, and later calls read it. Ids stay the runtime's
own, so the slot holds whatever this runtime's table says. Names are
still matched by content on the first call, and the slot is written with
a relaxed atomic store, since every thread writes the same id.

The runtime ABI is now 28.
2026-10-22 15:02:41 -05:00
Chris Tate d8d75dfa18 Support Duplex.from over streams, pairs, promises and async functions 2026-10-22 13:32:25 -05:00
Chris Tate 317ec98fa5 Close async generators on early for await exits and iterate untyped native streams 2026-10-22 12:31:21 -05:00
Chris Tate a6a1eb2b95 Support Duplex.from, compose stages, readable.compose and pipeline function destinations 2026-10-22 10:57:53 -05:00
Chris Tate 9aa3b15174 Support construct, writev, decodeStrings and defaultEncoding on streams 2026-10-22 09:44:27 -05:00
Chris Tate f87a04fa06 Build typed 'message' listener parameters from the message
A 'message' listener with a typed parameter received each message as a
checked-dynamic value: the port decoded the message into dyn objects, the
listener's thunk matched the value against each union arm, read every
field again to build the record, and the dyn objects were then released.
For bench/channel-messages that was about a third of the delivery time.

- A closure registered with on, once, addListener, prependListener or
  prependOnceListener for 'message' gets a typed message entry when its
  parameter is a number, boolean, string, a record of those without union
  fields, or a boxed union of those arms with null or undefined. The
  entry builds the parameter from the message's nodes and calls the
  closure.
- The entry handles a message only when it has the parameter's exact
  layout: the union arm the checked conversion picks, and a record's
  declared keys in declaration order with no others. Any other message
  runs through the thunk on the decoded value, as before, so undeclared
  keys, other orders and mismatches behave as they did.
- Ports, workers and parentPort deliver a message through the entries
  when no value in it is reached twice and it holds no ports or native
  handles. Listeners without an entry share one decoded value, made when
  the first of them runs.
- The message readers are runtime entry points, so the runtime ABI is now
  27.

Corpus 7130 and 7131 check typed listeners on MessageChannel ports, a
worker and parentPort against Node: exact layouts, extra keys, shared
values, nested records, untyped listeners beside typed ones, once
listeners and a transferred port.
2026-10-22 07:08:26 -05:00
Chris Tate 75bcf9dfa7 Merge main 2026-10-22 06:55:45 -05:00
Chris Tate daac2a4a15 Support objectMode streams with any value as a chunk (#1785) 2026-10-22 05:55:45 -05:00
Chris Tate 67247dd26b Support objectMode streams with any value as a chunk
Readable, Writable, Duplex, Transform and PassThrough take the
objectMode option, and a Duplex, Transform or PassThrough the
readableObjectMode and writableObjectMode options, as true or false
literals in an options object literal or in an options value. An
object-mode side holds any value that converts to a checked-dynamic
value: push, unshift, write, end, pipe, pipeline, for await, 'data'
listeners, Readable.from and the transform callback carry values in
TypeScript and JavaScript, and constructor-function streams and options
held in variables do the same. The object-mode high-water mark counts
values and defaults to 16. A readable buffer that mixes strings, Buffers
and other values holds them all, and push(undefined) and other values on
a byte-mode stream report ERR_INVALID_ARG_TYPE through 'error', as in
Node.

In typed code a write or transform callback, or a _write or _transform
method, may declare its chunk with any such type, which converts when
the callback runs. Writes pass the encoding argument to _write and
_transform as Node does: undefined when absent, null when a callback
took its place, otherwise the value unchanged. A parameter declared
string | null | undefined receives that value and one declared string
receives "" for undefined and null. write(chunk, encoding) on a
byte-mode stream encodes a string chunk with any known encoding and
throws ERR_UNKNOWN_ENCODING for an unknown one. Readable.from takes
typed Maps and Sets of any such value, and arrays that mix strings and
Buffers.

for await over a readable-only stream that will emit 'close' now ends
after 'close', as Node's eos does. Buffered writes that complete inside
clearBuffer run their callbacks in order, and 'finish' waits for a
deferred afterWrite that carries a callback, as Node's pendingcb does,
unless a _final callback schedules it.

The 'data' listener adapters take three slots and write and transform
callbacks read their chunk and encoding through runtime accessors, so
RUNTIME_ABI_VERSION is now 26.
2026-10-22 04:21:55 -05:00
Chris Tate 6e753cd5c8 Merge main 2026-10-22 04:08:52 -05:00
Chris Tate b5fb4115e1 Merge main 2026-10-22 03:33:29 -05:00
Chris Tate 7d20212dd4 Merge main 2026-10-22 03:24:23 -05:00
Chris Tate 1773ffbef3 WebCrypto: the crypto global, node:crypto's webcrypto, and secret-key SubtleCrypto 2026-10-22 02:52:01 -05:00
Chris Tateandsaboursepideh 1a240fbf10 Support asymmetric keys, signatures and Ed25519 in node:crypto and WebCrypto
Co-authored-by: saboursepideh <25549001+saboursepideh@users.noreply.github.com>
2026-10-22 02:49:33 -05:00
Chris Tate d426960f45 Make Cipheriv and Decipheriv Transforms and accept function stages anywhere in pipeline()
Cipheriv and Decipheriv values are Transforms, as in Node: they can be
written and ended, piped into, used as pipeline() and stream/promises
pipeline stages, composed, read, iterated with for await, read by
stream/consumers, passed to finished(), and listened to, and their stream
properties read as in Node. Each chunk goes through the cipher's
update(), and the end pushes final() or reports its error through
'error'; writing after final() throws out of write(). The stream unit
builds a cipher's Transform on its first stream use from operations the
cipher's handle provides (ScrDynHandleOps.transform), so programs that
use ciphers without streams link as before. The cipher is a
collector-headered object behind a traced handle: its Transform's steps
hold it, and the pair is reclaimed as a cycle. Through untyped values, in
a program that uses streams, a cipher's stream properties and its on,
once, off, pipe, unpipe, read, pause, resume, setEncoding, write, end,
destroy, cork and uncork members run on its Transform; other stream
members throw a coded SC2020 error.

A Transform holds a write's callback while its readable side is at the
high-water mark and runs it at the next read, and runs it on a tick once
the readable side has ended, as Transform._write does. write() on a
PassThrough, a Transform, a Hash or a cipher used to return true however
much the readable side buffered. zlib streams applied the rule already
and keep their timing.

pipeline() accepts function stages anywhere among its streams, so runs of
async generator stages can sit on both sides of a stream. A stage can be
named by a function declaration, or a const bound to a function
expression, that nothing reassigns; its body lowers again at the
pipeline with its source typed by the pipeline. The source can also be
an array, a string, a synchronous generator object, or a synchronous
generator function without parameters: an async generator steps the
source's iterator and yields each element, and the next stage receives
each element on the same tick as with Node's for await over the source.
The runtime's function-stage entry points take a bitmask of the function
positions and one (next, read, return) helper triple for each generator
pumped into a stream, so RUNTIME_ABI_VERSION is now 25. In JavaScript,
the chunks a stage receives from the previous stage's generator read as
the strings or Buffers it yields, so their string and Buffer methods
compile.

Corpus 7055-7059 cover cipher streams in TypeScript and JavaScript, their
errors, close order and backpressure, the pipeline stages and sources
with their tick order, and Transform backpressure.
2026-10-22 01:55:38 -05:00
Chris Tate 63001cbc13 Await a suspending stackless callee without its promise 2026-10-21 23:55:37 -05:00
Chris Tate 283a504fe0 Support crypto.createDiffieHellman and getDiffieHellman
crypto.createDiffieHellman, crypto.getDiffieHellman and
crypto.createDiffieHellmanGroup return native DiffieHellman and
DiffieHellmanGroup handles backed by mbedTLS bignums. generateKeys,
computeSecret, getPrime, getGenerator, getPublicKey, getPrivateKey,
setPublicKey, setPrivateKey and verifyError follow Node 24.22:

- the modp1, modp2, modp5 and modp14 through modp18 groups, with the
  private key widths of Node's OpenSSL 3 path (200 to 400 bits for
  modp5 and up, [2, p - 2] for modp1 and modp2);
- explicit primes and generators in every argument form and encoding,
  with keys of bits(p) - 2 bits, or below min(2^N, q) when the
  parameters equal an OpenSSL named group (RFC 3526, RFC 7919,
  RFC 5114);
- generated safe primes with OpenSSL's congruences for the generator;
- verifyError's DH_check bits, computed when it is first read;
- Node's argument, generator, modulus, key range, state and encoding
  errors, including the OpenSSL errors' library and reason properties.

Safe-prime generation sieves candidates with the odd primes below a
bound that grows with the prime's length and tests them with
Miller-Rabin rounds over a variable-time Montgomery exponentiation that
only reads public values; key and secret exponentiations stay on
mbedTLS's constant-time path. Primes longer than 8192 bits, property
reads other than verifyError, property writes, Object.prototype methods,
and calls whose output encoding is typed any or matches no @types/node
overload are refused.

The runtime unit scr_dh.c links, with the mbedTLS archive, only into
programs that use DiffieHellman. wasm32-wasi builds refuse it. The ECDH
unit's argument and encoding helpers move to scr_crypto_args.h, which
both units include.
2026-10-21 21:55:47 -05:00
Chris Tate d8265b2209 Link scr_bytes_dyn.c into libraries 2026-10-21 12:35:58 -05:00
Chris Tate f2fd1c85a2 Run Buffer methods on Buffers held as checked-dynamic values 2026-10-21 08:50:54 -05:00
Chris Tate 00840aaca6 Merge main 2026-10-21 00:08:02 -05:00
Chris Tate a1c55207fc Merge main 2026-10-20 23:21:29 -05:00
Chris Tate 012fdb3fb0 Merge main 2026-10-20 21:52:19 -05:00
Chris Tate d59d8ff6f2 Merge main and count declaration writes to parameters 2026-10-20 21:05:19 -05:00
Chris Tate 53171c282d Read and write dynamic-tier properties through shapes and inline caches (#1396) 2026-10-20 20:52:12 -05:00
Malte UblandClaude Opus 5.5 da13375a8b Keep properties JavaScript adds to a child process, and await it as a thenable
execa 5 mixes then/catch/finally into a real ChildProcess with
Reflect.defineProperty, replaces kill and adds cancel by assignment, and
awaits the child.

- A new optional runtime unit, scr_dyn_handle_props.c, keeps those
  properties in a side table keyed by the native child. Wrapper ops for
  the child tag look there first for reads, member calls and writes.
  defineProperty and getOwnPropertyDescriptor use it, and await adopts a
  child with a callable then. Class methods read as values call the
  class's own method.
- In JavaScript files, writes onto typed children, reads and calls of
  added names, method values for bind/call/apply, and members no typed
  lowering claims go through the child's checked-dynamic box.
- Only programs whose JavaScript adds properties to children link the
  unit and install the table; everything else compiles as before.
- A setTimeout delay that may be a boolean converts with ToNumber, and
  `if (t.unref)` over a timer handle folds to true (execa's lib/kill.js).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 18:28:00 -07:00
Chris Tate eac75404d5 Merge main 2026-10-20 19:19:07 -05:00
Chris Tate 2582e46e76 Support crypto.createECDH and ECDH.convertKey
crypto.createECDH returns a native ECDH handle backed by mbedTLS for
prime192v1, secp224r1, prime256v1, secp384r1, secp521r1, secp192k1,
secp224k1, secp256k1, brainpoolP256r1, brainpoolP384r1 and
brainpoolP512r1. generateKeys, computeSecret, getPublicKey,
getPrivateKey, setPrivateKey, setPublicKey and ECDH.convertKey follow
Node 24: compressed, uncompressed and hybrid points, input and output
encodings, the private key range, key pair validation, and Node's error
codes and messages.

Curve names follow OpenSSL's short-name lookup: names of other curves
from crypto.getCurves() are refused at compile time when literal and
throw a coded SC2020 error when computed, other OpenSSL short names
throw ERR_CRYPTO_OPERATION_FAILED, and unknown names throw
ERR_CRYPTO_INVALID_CURVE. Calls whose arguments no @types/node overload
accepts, and computeSecret(view, encoding), are refused at compile time.

The runtime unit scr_ecdh.c links, with the mbedTLS archive, only into
programs that use ECDH. wasm32-wasi builds refuse it.
2026-10-20 19:17:05 -05:00
Chris Tate 5b20bf1e77 Merge main 2026-10-20 18:25:49 -05:00
Chris Tate 40ed0e3aff Merge main 2026-10-20 18:16:00 -05:00
Malte UblandClaude Opus 5.5 2f50141c0c Compile the hot-shots StatsD client over UDP
hot-shots, a StatsD client compiled from its JavaScript, failed when a
program constructed a client. Each gap on its UDP path is closed
generically:

- Sloppy-mode functions with named parameters may read `arguments`
  where the aliasing of their parameters cannot show: only
  `arguments.length`, or element reads without parameter or element
  writes.
- An `any` slot admits any boxable function value, including functions
  with optional parameters (`C.prototype.m = function (...)` through an
  untyped receiver).
- In a JavaScript file TypeScript does not check, a prototype method
  takes its documented parameters as checked-dynamic values, as
  constructors already did.
- JavaScript dgram sends run completion callbacks, buffer lists,
  connected sends and the six-argument offset/length form.
- A dgram socket crosses into the checked-dynamic tree as a handle
  (SCR_DYNH_DGRAM_SOCKET) whose methods are function values, with
  untyped listeners that survive 'close'. The handle lives in its own
  runtime unit (scr_dgram_dyn.c, the dgramDyn feature), linked only
  when a program converts a socket to or from an untyped value.
- `String.prototype.concat` on strings, and `parseInt` over a possibly
  missing or untyped value in JavaScript.

Corpus programs 6590-6596 and the hot-shots-udp npm
case (hot-shots 8.5.0 vendored) match Node in both lanes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:56:59 -07:00
Malte UblandClaude Opus 5.5 e060eeae25 Iterate untyped values with for await, and delegate with yield* in async generators
- A JavaScript generator whose inferred return is `any` (it delegates to
  itself) is a generator with checked-dynamic channels.
- for await over a checked-dynamic value: a compiled async generator, the
  value's Symbol.asyncIterator result, or its synchronous iterator with
  awaited values; break and throws close it through an awaited return().
  A value that is not iterable throws V8's TypeError.
- yield* in async generators delegates through the same protocol and
  completes with the delegate's return value.

The runtime part is a new unit, scr_dyn_for_await.c, linked only by
programs that use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:17:52 -07:00
Chris Tate 445b5a2ced Merge main 2026-10-20 17:01:18 -05:00
Malte UblandClaude Opus 5.5 be9c18f0b3 Bind builtin static functions and read Buffer.alloc, fs.realpathSync and String methods as values
- bind/call/apply on builtin function values held as checked-dynamic
  functions (String.fromCharCode, JSON.stringify and the forms below).
- Function values for Buffer.byteLength (Node's runtime encoding ladder),
  Buffer.compare, Buffer.alloc (size check, then fill), JSON.parse,
  fs.realpathSync and fs.realpathSync.native (Node's options handling).
- A JavaScript string method read as a value answers String.prototype's
  function (smol-toml's `!!(''.isWellFormed)` probe).

The runtime entries live in a new unit, scr_builtin_values.c, linked only
by programs that read these values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 13:50:09 -07:00
Malte UblandClaude Opus 5.5 b723155820 Run buffer-crc32's and yazl's capability probes as Node does
- A JavaScript binding written with a value whose representation differs
  from its initializer's (buffer-crc32's Int32Array table) stores a
  checked-dynamic value.
- A top-level JavaScript function declaration its module reassigns
  (yazl's self-redefining bufferFrom) lives in a mutable module global,
  assigned when the module starts; reads, calls and writes use it.
- Buffer.from with a non-literal encoding follows Node's fromString rules
  at run time, and copies arrays crossing by reference; array and byte
  sources ignore the extra argument.
- `new Buffer(...)` in dependency sources, where Node never warns, is
  Node's construction.
- Fixed-width read/write methods on Buffers held as checked-dynamic
  values dispatch through a separate runtime unit (scr_bytes_dyn.c),
  linked only by programs that call them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 13:26:02 -07:00