Commit Graph
695 Commits
Author SHA1 Message Date
Chris Tate 3abf43affd Use the events module and EventEmitter as untyped constructor values (#1544) 2026-10-20 21:12:06 -05:00
Chris Tate eb8a148605 Merge main 2026-10-20 21:01:40 -05:00
Chris Tate 115a763df8 Check that the limitations partials keep one sentence per line (#1571) 2026-10-20 20:59:02 -05:00
Chris Tate 06e202a126 Leave the per-chapter status counts out of the compatibility files
The ledger and the public artifact held a block of status counts for
every chapter. Nothing reads them (the docs page uses a chapter's slug
and title), and every classification change rewrote its chapter's block,
so concurrent compatibility changes conflicted there. The rows they were
counted from are unchanged.
2026-10-20 20:46:25 -05:00
Chris Tate 08c7930958 Support crypto.createECDH and ECDH.convertKey (#1589) 2026-10-20 20:18:22 -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
Malte Ubl c76892dc74 Revert "Continue a failed checked cast with its value in a dynamic tail (#1561)"
This reverts commit 6bb2711c4b, reversing
changes made to cd833e68a4.
2026-10-20 16:42:01 -07:00
Chris Tate 74633db92f Merge main 2026-10-20 18:21:35 -05:00
Chris Tate 6bb2711c4b Continue a failed checked cast with its value in a dynamic tail (#1561) 2026-10-20 18:15:01 -05:00
Chris Tate 25a11d9864 Check that the limitations partials keep one sentence per line
The Limitations page partials keep one sentence per line so edits to
different sentences merge, but AGENTS.md's general Markdown rule asks
for paragraphs on one line, and changes that followed it conflicted with
the split text. AGENTS.md now names the partials as the exception, and
limitations-partials.mjs gains a check, run by pnpm lint, that fails on a
partial line holding two sentences, and a fix mode that splits such lines.
The one partial that held several sentences per line is split; Markdown
joins the lines, so the page renders the same.
2026-10-20 18:08:33 -05:00
Chris Tate a1ef7950d0 Delete the docs compatibility metadata file again
#1360 moved the content hash and row count into next.config.mjs and
deleted node-v24-compatibility-meta.json, but a later merge kept a
branch's copy. Nothing reads it, and its hash line conflicts on every
compatibility change. The local compatibility check now fails while the
file exists, so a merge can't bring it back unnoticed.
2026-10-20 17:53:33 -05:00
Malte UblandClaude Opus 5.5 1ef31a1b74 Continue a failed checked cast with its value in a dynamic tail
`JSON.parse(text) as T`, `const x: T = anyValue` and `await res.json()
as T` threw `TypeError: expected X at $.path, got Y` when the value did
not fit `T`. Node never checks an assertion and continues with the value
it has, so the build-container listener rejected an order Node accepts
and a JWT with a string `exp` became a 500.

A failed cast now keeps its value when it initializes a `const`/`let`
binding declared in a function or block and only the code after the cast
reads the binding. That code (the statements after the cast in each
enclosing statement list, up to the declaration) lowers twice: the
static copy, unchanged, runs while the value fits; a dynamic copy, in
which the binding and everything derived from it is typed `any`, runs
after a failure, so missing members read undefined, wrong-typed members
keep their values, extra members stay visible in source order, and
objects keep their identity. The cast sets the flag that selects the
copy: the fused JSON.parse helper's slow path and the plain check call
scr_dyn_check_recover, which takes back the TypeError and parks the
value for checkedCast.fallbackTaken/fallbackTake.

A failed value that flows into a typed slot outside the region is
checked there, as any `any` value is: it continues when it fits and
throws at that use when it does not. A statement of the dynamic copy
with no `any` lowering becomes a runtime fence that throws only when a
failed value reaches it. Module-level bindings, regions with hoisted
declarations or super() calls, union targets and targets holding class instances, and
--tier=static-only (and library mode) keep the throwing cast.

`a?.b.c` on an `any` value now short-circuits only on `a`, so `.c`
throws when `a.b` is undefined, as in Node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:25:33 -07:00
Malte UblandClaude Opus 5.5 fec779abbb Use the events module and EventEmitter as untyped constructor values
In JavaScript, `ReleaseEmitter = EventEmitter` over `const EventEmitter =
require("events")` was refused with SC1090 ("a runtime-provided class value
as an untyped value"), and `class Channel extends require("events")` failed
on the require call as a value. Bundled npm code does both, for example a
small semaphore that aliases EventEmitter and constructs its release channel
through the alias.

- The events module binding and the EventEmitter or stream class itself
  turn untyped as the runtime's untyped constructor that constructor
  functions already use (scr_dyn_builtin_class.c). `new` through it builds
  an emitter object with Node's listener API, and `===` against the class
  compares identity.
- `x instanceof EventEmitter` on an untyped value also recognizes a boxed
  compiled emitter (an instance of a program class extending EventEmitter),
  which the prototype test alone answered false for. The same holds through
  an untyped binding narrowed to the class.
- `class X extends require("events")` extends the runtime emitter, as
  through a require binding.
- A typed array of the class built from such values (`[EventEmitter]`) is
  refused with SC1090 rather than failing its class check at run time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 12:41:53 -07:00
Chris Tate a0894cc488 Give constructor functions native stream state over the stream classes (#1533) 2026-10-20 13:21:25 -05:00
Chris Tate 3751afa51f Merge main 2026-10-20 13:02:01 -05:00
Chris Tate 73a595692f Let NodeJS stream interface slots hold JavaScript stream objects (#1524) 2026-10-20 12:32:16 -05:00
Chris Tate f284f94827 Merge main 2026-10-20 12:31:50 -05:00
Chris Tate ae3642d1bb Merge main 2026-10-20 12:08:37 -05:00
Chris Tate 76227c86c8 Merge main 2026-10-20 12:07:23 -05:00
Chris Tate eea3bc5447 Specialize variadic generic wrappers to the wrapped function's signature (#1413) 2026-10-20 11:52:34 -05:00
Malte UblandClaude Opus 5.5 73e40f4196 Merge main
pipe() into an untyped destination now comes from main's pipeIntoDyn
(stream.unboxDyn); programs with constructor-function streams unbox
through scr_dyn_builtin_stream.c, which also takes those streams, so the
separate dyn.builtinStreamPipe entry point is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:49:43 -07:00
Malte UblandClaude Opus 5.5 507610b90d Give constructor functions native stream state over the stream classes
Bundled npm code (from2, bl, tar-stream, yazl, multistream) builds its
streams as ES5 constructor functions: util.inherits(Ctor, Readable) and
Readable.call(this, opts), with _read/_write/_transform on the
prototype. Readable.call(this) threw SC2020.

A new runtime unit, scr_dyn_builtin_stream.c (feature
dynBuiltinStream), gives the untyped stream constructors their stream
half. Base.call(this, opts) creates a runtime stream over the receiver
and keeps it in a hidden slot; the runtime calls the receiver's
underscore methods through its property lookup; the stream prototypes
carry Node's methods and accessors over the hidden stream; and
EventEmitter's methods register listeners with the runtime stream's
emitter, so runtime events and pipes reach JavaScript listeners with the
receiver as this. _readableState/_writableState are live views.

Stream class values now come from dyn.builtinStreamClass, so only
programs that use them link the stream half. Typed code sees these
objects as their runtime streams: checked casts to the stream classes
take them, readable.pipe() into an untyped destination pipes into them,
and runtime streams crossing into JavaScript answer the constructor
object.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:46:05 -07:00
Chris Tate a43f0a71a6 Merge main 2026-10-20 11:36:33 -05:00
Chris Tate 8823556a84 Let constructor functions inherit from EventEmitter and the stream classes (#1512) 2026-10-20 11:32:22 -05:00
Chris Tate 99af5c878b Merge main and cover a block-local arguments alias that shadows an outer one
- Merge origin/main (e9fb01603); the import lines at the top of
  lowerer.ts conflicted and both are kept.
- Corpus 6385 gains a wrapper whose block-local `args` alias shadows an
  outer one in the same function; each call forwards its own arguments.
2026-10-20 11:30:11 -05:00
Chris Tate e9fb01603f Compile NodeJS.ReadableStream and NodeJS.WritableStream as general streams when a program mixes stream producers (#1518) 2026-10-20 11:24:09 -05:00
Chris Tate 324f173f65 Merge main 2026-10-20 11:23:45 -05:00
Chris Tate 25780d9231 Merge main 2026-10-20 11:03:09 -05:00
Chris Tate 8c40f92019 Merge main 2026-10-20 11:00:03 -05:00
Chris Tate 8eb5ad28e5 Keep WebAssembly references and memory storage alive while they are in use; merge main
Externrefs a guest holds are borrowed pointers. An import's result was
kept only until the outermost call returned, which was before the export
call converted its results to JavaScript, so a result created by an
import was freed before conversion. A table or global slot released the
reference it replaced at once, although the guest may still hold it in a
local after reading the slot. The kept references are now released after
the outermost caller has converted its results (scr_wasm_leave), and a
table or global store during a call keeps the reference it replaces until
then.

Checked memories (explicit bounds checks: sanitized builds, Windows)
grew with realloc, which can move the storage that memory.buffer and its
views alias. They now reserve the address space for their largest size
(mmap on POSIX hosts, VirtualAlloc on Windows) and commit pages as they
grow, so the base never moves. Hosts without address-space reservation
grow in place only until a buffer has been handed out; after that,
growth that would move the storage fails.

Tests: webassembly-externref-lifetimes.mjs (import results through an
export, table and global references replaced by the guest and by
JavaScript), webassembly-memory-growth.test.ts (views written after
growth from JavaScript and from the guest), and translate.test.ts cases
for memargs naming memory 0 explicitly and for local.tee operand types,
which b3bcbaaf7 made consistent with validation. Under SCRIPTC_SAN=1 the
two runtime tests report heap-use-after-free without these changes.

Merges main; internal/compatibility/generated/node-v24-backlog.json is
regenerated with pnpm node-compat.
2026-10-20 10:58:34 -05:00
Malte UblandClaude Opus 5.5 e865594089 Accept NodeJS stream interfaces in the fallback events.once and document its boundary
The fallback declaration of events.once takes NodeJS.ReadableStream and
NodeJS.WritableStream emitters like @types/node does. The diagnostics
fixture now pins the forms that stay refused (options that are not an
object literal, a computed name, a stream's 'data' event), and the
limitations page states the supported events.once forms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:47:59 -07:00
Chris Tate 21c6505709 Match tuple rests and positional any[] parameters in function patterns, and merge main
- matchInferSignature reads a fixed-tuple rest as its positions, so
  (...args: [string, number]) needs two arguments, and a positional
  any[] pattern parameter matches only when the function's parameter
  there accepts an array, as TypeScript's assignability does
  (corpus 6398).
- Merge origin/main (200fe8d22); node-v24-backlog.json regenerated.
2026-10-20 10:37:43 -05:00
Chris Tate 89f8dbe9e0 Merge main 2026-10-20 10:23:43 -05:00
Chris Tate e0b131c0f9 Merge main into opt/variadic-generic-wrappers 2026-10-20 10:19:08 -05:00
Chris Tate da476df676 Merge main 2026-10-20 10:11:51 -05:00
Malte Ubl aaf1e83ad8 Merge remote-tracking branch 'origin/opt/npm-polyfill-shims' into opt/npm-fs-extra-shim 2026-10-20 08:08:36 -07:00
Chris Tate c4ce357a9e Merge main and answer false for fixed-parameter function patterns that need more arguments
- Merge origin/main (e1c27176a).
- matchInferSignature answers false when a function needs more arguments
  than a fixed-parameter pattern passes, as TypeScript's assignability
  does (corpus 6398).
- Record corpus costs for the programs this change adds.
2026-10-20 09:24:29 -05:00
Malte UblandClaude Opus 5.5 2081aaa721 Compile readable-stream 3.x as Node's stream module too
readable-stream 3.x is a copy of Node 10's streams. Like 2.x and 4.x it
now compiles as node:stream: readable.js as stream.Readable carrying the
stream classes, Stream, finished and pipeline, and lib/_stream_*.js as the
matching builtin classes. Unlike them, this is not the package's own
READABLE_STREAM=disable mode, which throws on Node 24 (it Object.assigns
every stream export onto stream.Readable, which inherits the getter-only
`promises` accessor). The limitations and dependencies pages and the
compatibility notes say so.

The corpus program readable-stream-3 runs the vendored 3.6.2 under Node and
keeps to behavior its streams share with the builtin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:22:27 -07:00
Chris Tate 575f6491f4 Fix silent wrong output: object identity, Object.prototype values, Date parsing, stored builtins (#1336) 2026-10-20 09:18:37 -05:00
Chris Tate 56de47defc Check programs with tsc-ts by default (#1353) 2026-10-20 09:12:30 -05:00
Chris Tate 7d555c4cf3 Merge main 2026-10-20 09:04:02 -05:00
Chris Tate 55f4eaca5b Merge main 2026-10-20 09:02:52 -05:00
Chris Tate 7cd7b483bf Merge main 2026-10-20 09:02:06 -05:00
Chris Tate 9e54b4a198 Merge main 2026-10-20 09:00:02 -05:00
Chris Tate acf8b28f40 Merge main 2026-10-20 08:57:09 -05:00
Malte UblandClaude Opus 5.5 dfd59e18ee Let NodeJS stream interface slots hold JavaScript stream objects
Under the general stream representation, NodeJS.ReadableStream and
NodeJS.WritableStream compile as the runtime Readable and Writable
classes, so a JavaScript stream object (a constructor-function stream, a
plain object with on/pipe, a stream from bundled npm code) passed through
a TypeScript function typed with them took the checked unwrap and threw.

A program that moves an untyped value into a runtime stream class slot,
or passes an untyped pipe() destination or pipeline stage, now lowers
once more with checked-dynamic stream slots: the two interfaces (and
intersections over them) map to dyn. A native stream rides its typed
capsule and keeps its identity; any other value is the JavaScript object
itself. Member calls dispatch per value: stream.dynNative tests for a
boxed native stream, which takes the ordinary class-method lowering;
other values call their own member through dynInvoke. pipe() into a
JavaScript destination follows Node's Readable.prototype.pipe listener
protocol (stream.pipeDyn). for await and pipeline stages keep the
not-supported error for values that are not native streams.

The runtime code lives in scr_stream_dyn.c behind a new streamDyn
feature, so programs without these libCalls link the same objects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 06:49:37 -07:00
Chris Tate ce5e4294ad Merge main 2026-10-20 08:49:25 -05:00
Malte UblandClaude Opus 5.5 b9aaaa9d8c Answer server.address() with the socket path for Unix-socket servers
Node answers a Unix-socket server's address() with its path. Programs
that call listen() with a string argument now get a Unix-aware
address(): typed `string | AddressInfo | null` (the @types/node
declaration), it answers the path; typed as the AddressInfo record alone,
which cannot hold the path, it throws for such a server, as does the
composed address().port read. Every other program keeps the record-only
lowering, so their output is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 04:45:43 -07:00
Malte UblandClaude Opus 5.5 447e9bf000 Compile Transform option callbacks and loosely typed child-process listeners
@types/node types the transform/flush completion callback's data as any
and a child stream 'data' chunk as any, and ChildProcess accepts
(code: number, signal: string) exit and close listeners through its
catch-all overload. None of these compiled: the any-typed completion
callback crashed the LLVM emitter, and the child listeners were refused.

The completion callback's data parameter is typed Buffer | string |
undefined while the option callback lowers. Child stream 'data' listeners
with an unknown or any chunk box it as a checked-dynamic value, taking
strings when a setEncoding statement on the same stream precedes the
listener and Buffers when the function never calls setEncoding on it;
other placements are refused. Exit and close listener parameters declared
number or string bind as checked-dynamic values, so the body sees the
null Node passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 04:16:06 -07:00
Malte UblandClaude Opus 5.5 95b2f81716 Pipe into untyped destinations by unwrapping boxed native streams
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 03:24:08 -07:00