Commit Graph
450 Commits
Author SHA1 Message Date
Chris Tate 24eb054395 Compile the hot-shots StatsD client over UDP (#1568) 2026-10-20 21:29:48 -05:00
Chris Tate bde7afa980 Compile undici from a built-in implementation (#1425) 2026-10-20 21:14:37 -05:00
Chris Tate d59d8ff6f2 Merge main and count declaration writes to parameters 2026-10-20 21:05:19 -05:00
Chris Tate eb8a148605 Merge main 2026-10-20 21:01:40 -05:00
Chris Tate 08c7930958 Support crypto.createECDH and ECDH.convertKey (#1589) 2026-10-20 20:18:22 -05:00
Chris Tate b04166a8f0 Read runtime keys of package enum objects as checked-dynamic values
The enum rewrite turns a package's numeric enum into one object holding
its names and its reverse mapping, so the object's fields have different
types. A reverse read with a runtime key, such as
DiagLogLevel[DiagLogLevel.WARN] in @opentelemetry/api, then failed with
SC1090 ("the declared fields have no one common type").

A keyed read of such a record already answers a checked-dynamic value in
JavaScript files. It now does the same where the checker types the read
'any'. The new npm case tsc-enum-reverse-reads matches Node, as does the
opentelemetry-api case again.
2026-10-20 20:04:06 -05:00
Chris Tate 1f4f7d822f Merge main 2026-10-20 19:27:58 -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 f3da708774 Compile polyfill packages that are Node builtins as the builtins (#1458) 2026-10-20 18:28:42 -05:00
Chris Tate 7f777f36a3 Carry runtime-decided dns.lookup answers dynamically, dial Node-typed net lookups, and keep tsc enum exports undefined until assigned (#1528) 2026-10-20 18:25:22 -05:00
Chris Tate 74633db92f Merge main 2026-10-20 18:21:35 -05:00
Chris Tate f45a37f307 Merge main 2026-10-20 18:05:28 -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
Chris Tate f446620ae5 Read absent process.versions entries as undefined under @types/node (#1550) 2026-10-20 17:46:00 -05: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 5765d89227 Check the frontend's types against tsc-ts/api
The frontend calls tokenStartOfNode, getTextOfNode, getSourceFileOfNode and
forEachChild instead of AstNode's position and traversal methods. Node lists
answer hasTrailingComma(), and a declaration's modifiers are a modifier list
with their flags.

Symbol, Type, Signature, IndexInfo, TypePredicate, Program, TypeChecker and
Diagnostic have tsc-ts/api's members and types. Compiler code reads symbol
names with symbolName(symbol).

tsc-ts goes to 0.0.5. api-conformance.ts asserts that AstNode, AstNodeList,
SourceFile and each node interface are assignable to tsc-ts/api's interface of
the same name, and names the members where the wire format differs.
2026-10-20 13:41:39 -05:00
Chris Tate 3751afa51f Merge main 2026-10-20 13:02:01 -05:00
Malte UblandClaude Opus 5.5 a12827cc35 Read absent process.versions entries as undefined under @types/node
@types/node declares http_parser, v8, uv, zlib, ares and modules as plain
strings, but the runtime's versions object holds only node and openssl. The
dyn read was narrowed to the declared string with a checked extraction, so
comparisons with undefined folded to false and other uses threw. Such reads
now keep the undefined arm, like the optional stream properties, and
unannotated bindings initialized from them store the same union.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:48:12 -07:00
Chris Tate f284f94827 Merge main 2026-10-20 12:31:50 -05:00
Chris Tate 834a2bfc29 Merge main 2026-10-20 12:31:03 -05:00
Chris Tate fdd1c9ee00 Lower fetch members typed by @types/node, and run the poll phase once per loop iteration (#1435) 2026-10-20 11:49:51 -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 68dac76fdc Treat setEncoding's return value as the stream it was called on
A method call declared to return `this`, such as setEncoding, resolves to
its receiver's access path, so a 'data' listener on the stream that
`const out = child.stdout.setEncoding("utf8")` returns receives strings.
A setEncoding call that a preceding statement always evaluates (its
expression, a variable initializer, or the receiver of a method chain in
one of those) counts as preceding the listener. Only `new` and the
child_process factories (spawn, fork, exec, execFile) count as creating a
separate stream; any other call result may be a stream another binding
already holds.
2026-10-20 11:11:59 -05:00
Malte UblandClaude Opus 5.5 bc6a2fc767 Merge main
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:06:59 -07:00
Chris Tate 8c40f92019 Merge main 2026-10-20 11:00:03 -05:00
Chris Tate 33354cc481 Abort the request of a redirect that fetch follows or rejects
A redirect fetch followed or rejected was marked to drain: its body was
read and dropped until the server ended it, and the abort listener was
already removed. A body that never ends kept the connection busy after
cancellation and stalled a pool of one connection. Following or
rejecting a redirect now aborts its request, so the connection closes.
undici 7 leaves that connection open with its body paused, which stalls
the same pool; the follow-up request here gets a new connection.
2026-10-20 10:50:19 -05:00
Chris Tate 8aca6d653d Abort the request of a redirect that fetch follows or rejects
A redirect fetch followed or rejected was marked to drain: its body was
read and dropped until the server ended it, and the abort listener was
already removed. A body that never ends kept the connection busy after
cancellation and stalled a pool of one connection. Following or
rejecting a redirect now aborts its request, so the connection closes.
undici 7 leaves that connection open with its body paused, which stalls
the same pool; the follow-up request here gets a new connection.
2026-10-20 10:48:36 -05:00
Malte UblandClaude Opus 5.5 d883c84752 Add corpus programs for events.once with a signal, over streams, and in races
6490 covers events.once with an AbortSignal: abort, an aborted signal, an
undefined signal, abort-listener order, 'removeListener' events, a
throwing 'newListener' listener and the settlement turns. 6491 covers
stream receivers (file streams, Readable.from, a destroyed PassThrough, a
Writable) and a NodeJS.ReadableStream part raced against its destination.
6492 covers races over events.once results with entries that only reject
and entries of different value types. 6493 covers stream subclasses whose
completion callbacks are typed `Function`. 6494 covers events.once over
checked-dynamic stream slots. The node-types fixture runs the race shapes
under @types/node, where events.once returns Promise<any[]>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:48:00 -07:00
Chris Tate b5e7c23b93 Merge main 2026-10-20 10:38:47 -05: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
Malte UblandClaude Opus 5.5 f669c46f0d Carry runtime-decided dns.lookup answers dynamically, dial Node-typed net lookups, and keep tsc enum exports undefined until assigned
- dns.lookup with options known only at run time (a checked-dynamic
  value, or one cast to an overload's option type) may answer a string or,
  with `all: true`, an address list, whatever the overload the checker
  picked says: an inline callback now binds its parameters as
  checked-dynamic values. Array.isArray tests a checker-narrowed dyn read's
  dyn value instead of folding on the extracted type, so it never answers
  false for an address list the declared type omits.
- net.connect({ lookup }) accepts a lookup of Node's own type
  (net.LookupFunction: options plus a callback taking an address string
  or list), called as Node's autoSelectFamily dial does ({ hints, all:
  true }); the fallback declarations spell net.LookupFunction that way.
  dns.lookup accepts Node's hints flags (ADDRCONFIG, V4MAPPED, ALL) and
  passes them to getaddrinfo.
- A CommonJS export typed as the empty object literal (tsc's enum output
  `exports.E || (exports.E = {})` after `exports.E = void 0`) rides
  checked-dynamic storage, so the preamble's undefined no longer traps at
  module load: @opentelemetry/api loads and its no-op metrics and trace
  APIs run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:58:15 -07:00
Chris Tate cb99a06fe5 Shadow the export alias only in the scope that declares it again
The export-alias rewrite skipped a whole function when a let or const
anywhere inside it declared the alias's name, so the function's other
references to the alias kept the alias name after its declaration was
removed. A function now shadows the alias only through its parameters,
its own name, its vars and the declarations directly in its body; a
block, case block, catch clause or for loop shadows it through its own
declarations, and the walk skips just that scope.
2026-10-20 09:35:14 -05:00
Chris Tate 90ff0af5b7 Merge main 2026-10-20 09:33:27 -05: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
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 da4f131651 Merge main 2026-10-20 08:56:12 -05:00
Malte UblandClaude Opus 5.5 465abda816 Compile the remaining safe-fetch shapes: Promise<never> race entries, typed Array(n).fill, narrowed header entries, lookup option unions and CommonJS export aliases
- Promise.race admits a Promise<never> entry (the deadline idiom) under
  any result type: it can only reject, so its fulfillment adapter traps.
  A Promise<never> executor's one-parameter resolve validates against the
  void inner.
- Array(n).fill(v) and new Array(n).fill(v), which the checker types as
  any[], take v's type.
- Object.entries/values over an index-signature record cast to a narrower
  value type check each value into the element type instead of refusing.
- dns.LookupAllOptions and the lookup-function option union that holds it
  (LookupOneOptions | LookupAllOptions | number | undefined) ride
  checked-dynamic storage, and dns.lookup passes a cast of a
  checked-dynamic options value through unchanged.
- npm packages: a CommonJS module that names its export object through a
  variable (`var ip = exports; ip.isPrivate = ...`, the ip package) is
  respelled through `exports`, and tsc output that adds a default-export
  object (`exports.default = { metrics: metrics_api_1.metrics }`, the
  @opentelemetry/api index) keeps its named exports linked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 06:36:48 -07: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 18034065d6 Compile the packages a module loaded through import() requires
A workspace package loaded on demand had its npm dependency selected, but
the selection never scanned that dependency's own JavaScript: it is
outside the startup module order, so a compiled CommonJS dist requiring a
sibling package was refused with "the module is not supported yet". The
scan of the import() graph now follows opted-in package JavaScript through
its literal require() and import edges.

The lowering appended those modules by their import declarations only, so
a CommonJS file's requires never joined the compiled graph and their
bindings stayed fenced. Preflight's resolved module edges, require edges
included, now reach the walks that append import(), fork() and Worker
modules, with lazy requires ordered after their module and inline require
cycles answered as at startup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 03:22:43 -07:00
Malte UblandClaude Opus 5.5 40b80116e4 Merge origin/main into opt/http-socket-path
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 03:22:28 -07:00
Malte UblandClaude Opus 5.5 cb26c95f61 Read http.request options at run time, speak HTTP over Unix sockets, and fill the boot path's net and fetch gaps
http.request, https.request and get now accept options the compiler
cannot see as an object literal: a RequestOptions variable, a literal
that spreads one, or a literal that sets socketPath. The runtime reads
the record in the ClientRequest constructor's order with Node's errors;
documented options it does not implement throw the runtime fence when
they carry a value. https adds rejectUnauthorized, ca and servername.

socketPath dials a Unix domain socket in the net unit; the agent keys
its sockets by the path as Node's getName does, and the Host header
defaults to localhost. server.listen(path[, cb]) binds a Unix socket and
removes the socket file when the server closes; a numeric string is
still a port. Errors name the path ("connect ENOENT /path", "listen
EADDRINUSE: address already in use /path"). Windows reports ENOTSUP.

A TypeScript object literal with no contextual type that spreads a
checked-dynamic value maps to the checked dynamic, so
`const options = { ...location, path, timeout }` compiles.

A socket's 'lookup' event reaches its listeners with (err, address,
family, host) for each address a host name resolves to, or once with
the lookup error, before 'connect'. Only programs that listen for
'lookup' install the lookup records; elsewhere the hook sites are a NULL
check.

server.close((err) => ...) runs the callback with undefined at 'close',
or with ERR_SERVER_NOT_RUNNING when the server was not listening; a
server that never listened now emits 'close'. IncomingMessage 'data'
listeners may take string chunks after setEncoding, and res.end()
accepts a string-or-undefined chunk.

fetch's BodyInit and HeadersInit unions, as RequestInit-derived option
types spell them under @types/node, map to the checked dynamic, and a
URLSearchParams body is sent form-encoded, as by Node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 02:57:13 -07:00
Chris Tate 12221ad7f8 Merge opt/npm-polyfill-shims and apply modes and inode checks in the fs-extra shim
- writeFile and outputFile with byte data and a mode open the file with
  that mode, and writeJsonSync and outputJsonSync pass the mode.
- copySync and moveSync compare source and destination inodes and walk
  the destination's parents, as copy and move do.
- The resolver parity sweep skips the project-import comparison for
  shimmed packages.
- The JSON reader writes the byte order mark as an escape.
2026-10-20 04:52:44 -05:00
Malte UblandClaude Opus 5.5 e4f72c65f5 Merge opt/native-undici (main 783870dec) into opt/native-undici-followups
Replaces the single-parent "Merge main" squash (6ab9a5423) with a two-parent merge of the same tree.

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