Skip to content

Node v24.13.0 nsolid v6.2.0 release#409

Merged
santigimeno merged 147 commits intonode-v24.x-nsolid-v6.xfrom
node-v24.13.0-nsolid-v6.2.0-release
Jan 16, 2026
Merged

Node v24.13.0 nsolid v6.2.0 release#409
santigimeno merged 147 commits intonode-v24.x-nsolid-v6.xfrom
node-v24.13.0-nsolid-v6.2.0-release

Conversation

@santigimeno
Copy link
Copy Markdown
Member

@santigimeno santigimeno commented Jan 14, 2026

Summary by CodeRabbit

  • New Features

    • Type stripping marked stable (flag renamed to --no-strip-types)
    • localStorage/sessionStorage promoted to stable
    • HTTP/2 extended CONNECT (WebSocket over H2) support
    • New N-API helper to create objects with properties
    • Dev Container support & documentation
    • New RoundRobinPool dispatcher and request deduplication interceptor
  • Improvements

    • HTTP server: optimize handling for empty requests
    • Cache interceptor: stronger revalidation and 304 reuse with streaming
    • Diagnostics: additional HTTP/2 client stream events
    • TLS: more robust ALPN/PSK error handling
    • Module compile cache: portable mode and related UX enhancements

✏️ Tip: You can customize this high-level summary in your review settings.

aduh95 and others added 30 commits November 11, 2025 23:25
Original commit message:

    Fix scratch registers passed to mtvsrdd

    `ra` cannot be r0 as it will be interpreted as Operand(0)

    Change-Id: Idce58191f9d3578dc91dc4aa3872a0bf2939d8b3
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6936113
    Commit-Queue: Milad Farazmand <mfarazma@ibm.com>
    Reviewed-by: Junliang Yan <junyan1@ibm.com>
    Cr-Commit-Position: refs/heads/main@{#102388}

Refs: v8/v8@2abc613
PR-URL: nodejs/node#60177
Refs: nodejs/undici#4530
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
PR-URL: nodejs/node#60125
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
PR-URL: nodejs/node#60150
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
PR-URL: nodejs/node#60175
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
There can be a race from eagerly shutting down the servers and
severing two pipes at the same time but for the purpose of this test,
we only care about whether the requests are initiated from the client
as expected, not how the upstream/proxy servers behave. Ignore EPIPE
errors from them.

PR-URL: nodejs/node#60269
Refs: nodejs/node#59741
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
PR-URL: nodejs/node#60142
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
`performance.eventLoopUtilization` and `performance.timerify` are not
part of the Web API. Expose these two functions directly on the
`perf_hooks` module.

PR-URL: nodejs/node#60370
Fixes: nodejs/node#60368
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs/node#60391
Refs: nodejs/node#49605
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Jake Yuesong Li <jake.yuesong@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
The test has been flaky for years and new platforms keep popping
up. As it squeezes too many independent test cases into one file,
split them into individual files to avoid masking regressions
and help only mark the real flaky ones as flaky. This might also
help with the flakiness itself by avoiding updating a shared tmpdir
being watched by differet tests and avoiding running all these
time-consuming tests in one file, which can cause a timeout
on slow machines.

PR-URL: nodejs/node#60391
Refs: nodejs/node#49605
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Jake Yuesong Li <jake.yuesong@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
PR-URL: nodejs/node#60190
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
PR-URL: nodejs/node#60366
Refs: nodejs/nodejs.org#8231
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Claudio Wunder <cwunder@gnome.org>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Fixes: nodejs/node#56666
PR-URL: nodejs/node#56829
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
PR-URL: nodejs/node#60387
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
PR-URL: nodejs/node#60388
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Kohei Ueno <kohei.ueno119@gmail.com>
PR-URL: nodejs/node#60411
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
PR-URL: nodejs/node#60412
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Node.js only checks trust settings of additional certificates
from the system store.
It does not, however, support revocation/distrust of existing
certificates.

PR-URL: nodejs/node#60340
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
PR-URL: nodejs/node#60444
Refs: nodejs/undici#4644
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This addresses late review comments for the recently
landed cfbfc1b05080 and aligns the new code with the
pre-existing V8 fast call counters.

Refs: nodejs/node#60434 (review)
PR-URL: nodejs/node#60447
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Avoid unnecessary nextTick.

PR-URL: nodejs/node#60454
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
PR-URL: nodejs/node#60345
Fixes: nodejs/node#60311
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com>
PR-URL: nodejs/node#59394
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Zeyu "Alex" Yang <himself65@outlook.com>
Reviewed-By: Jordan Harband <ljharb@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
PR-URL: nodejs/node#60465
Reviewed-By: Richard Lau <richard.lau@ibm.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: nodejs/node#60474
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Previously, formatExtraProperties applied ctx.stylize to the entire
'[key]: value' string. This caused the colon and space to be styled,
making the output inconsistent with normal object properties.

Now, only the key itself is stylized, and the colon and space remain
unstyled, aligning with the formatting of regular properties.

Refs: nodejs/node#60131
PR-URL: nodejs/node#60479
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Jordan Harband <ljharb@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Otherwise when the expected prompt does not show up in the
session and the debugger tests time out, there is not enough
information to figure out exactly which line in the test
is causing the timeout.

PR-URL: nodejs/node#60457
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
The existing description is outdated, and exposes too many details
that are subject to change.

- There is no point conceptualizing "two module loaders", in reality
  the boundary is blurred since the two invoke each other to support
  require(esm) and import(cjs). The distinction lies not in
  what kind of module is being requested/which loader is used, but
  only in how the the module request is initiated (via `require()`
  or `import()`). The inner working of the loaders are subject
  to change and not suitable to be documented.
- It should not mention monkey patching in the documentation, as
  publicly supported universal hooks are already provided through
  `module.registerHooks()`, and so there's no need to single out
  any of them in terms of loader hooks support either.
- Remove the description about whether they are asynchronous or
  synchronous, which is also implementation detail subject to change.
- Add missing descriptions about how .ts, .mts and .cts are treated,
  and `.node` is also supported in import now.
- There is no need to specially mention .node treatment in cli.md,
  link to the explanations about loading from `import` in packages.md
  instead.

PR-URL: nodejs/node#60346
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
ESM resolution and loading is now always synchronous from a
non-loader-hook thread. If no asynchrnous loader hooks are
registered, the resolution/loading is entirely synchronous.
If asynchronous loader hooks are registered, these would be
synchronous on the non-loader-hook thread, and asynchronous
on the loader hook thread.

This avoids several races caused by async/sync loading sharing
the same cache. In particular, asynchronous loader hooks
now works with `require(esm)` - previously it tends to break
due to races.

In addition, when an asynchronous loader hook
returns a promise that never settles, the main thread no longer
silently exits with exit code 13, leaving the code below
any module loading calls silently ignored without being executed.
Instead, it now throws ERR_ASYNC_LOADER_REQUEST_NEVER_SETTLED
which can be caught and handled by the main thread. If the module
request comes from `import()`, the never-settling promise is
now relayed to the result returned by `import()`.

Drive-by: when annotating the error about importing undetectable
named exports from CommonJS, it now no longer reload the source
code of the CommonJS module, and instead reuses format information
cached when the module was loaded for linking.

PR-URL: nodejs/node#60380
Fixes: nodejs/node#59666
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
PR-URL: nodejs/node#60481
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Richard Lau <richard.lau@ibm.com>
Erik Corry and others added 18 commits December 7, 2025 19:42
Original commit message:

    [regexp] Rename "greedy loops" to "fixed length".

    Some greedy quantifiers are code-generated in a more efficient
    way, but far from all greedy quantifiers are generated
    in this way.  This change renames the specially optimized loops
    from "greedy loops" to "fixed length loops", which should be
    clearer.

    Going forward, we can probably reuse much of the code for
    fixed length loops when code-generating simple possessive
    quantifiers.

    Change-Id: I13b9d14beac430e2d05d0feaf887fc0566bc4103
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6508846
    Reviewed-by: Patrick Thier <pthier@chromium.org>
    Commit-Queue: Erik Corry <erikcorry@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#100062}

Refs: v8/v8@df20105
PR-URL: nodejs/node#60732
Fixes: nodejs/node#60030
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Original commit message:

    [regexp] Remove DeferredAction class.

    We can just chain up the traces and use the regular
    ActionNodes that we already have to represent the
    deferred actions.  Also simplifies the ActionNodes
    a little.  No functional change intended.

    Reduce the size of the Trace from 128->120 bytes.

    This is a stack allocated struct so to avoid stack
    overflows after adding the next_ field I am reducing
    it back down to 120 bytes by rearranging and shrinking
    fields.

    Change-Id: I6dca9946e035e9b22798e160b8fadaeca61f4955
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6512931
    Reviewed-by: Patrick Thier <pthier@chromium.org>
    Commit-Queue: Erik Corry <erikcorry@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#100092}

Refs: v8/v8@0dd2318
PR-URL: nodejs/node#60732
Fixes: nodejs/node#60030
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Original commit message:

    [regexp] Clean up state for fixed length loop.

    Also reduces the on-stack Trace size by one word,
    adds some comments, renames some variables for
    more clarity.

    Change-Id: I9ec105cd9cebbaba65e9801c47dd0574cc81f967
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6512896
    Reviewed-by: Patrick Thier <pthier@chromium.org>
    Commit-Queue: Erik Corry <erikcorry@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#100117}

Refs: v8/v8@6bb32bd
PR-URL: nodejs/node#60732
Fixes: nodejs/node#60030
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Original commit message:

    [regexp] Fix modifiers for ChoiceNodes

    Each alternative might modify flags when their sub-graph is emitted.
    We need to restore flags to the value at the beginning of a ChoiceNode
    for each alternative.

    Drive-by: Move regexp-modifiers test out of harmony/

    Fixed: 447583670
    Change-Id: I9f41e51f34df7659461da0a4fcd28b7e157f52e1
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6995181
    Reviewed-by: Jakob Linke <jgruber@chromium.org>
    Commit-Queue: Patrick Thier <pthier@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#102838}

Refs: v8/v8@72b0e27
Fixes: nodejs/node#60030
PR-URL: nodejs/node#60732
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Notable changes:

http:
  * (SEMVER-MINOR) add optimizeEmptyRequests server option (Rafael Gonzaga) nodejs/node#59778
lib:
  * (SEMVER-MINOR) add options to util.deprecate (Rafael Gonzaga) nodejs/node#59982
module:
  * (SEMVER-MINOR) mark type stripping as stable (Marco Ippolito) nodejs/node#60600
node-api:
  * (SEMVER-MINOR) add napi_create_object_with_properties (Miguel Marcondes Filho) nodejs/node#59953
sqlite:
  * (SEMVER-MINOR) allow setting defensive flag (Bart Louwers) nodejs/node#60217
src:
  * (SEMVER-MINOR) add watch config namespace (Marco Ippolito) nodejs/node#60178
  * (SEMVER-MINOR) add an option to make compile cache portable (Aditi) nodejs/node#58797
src,permission:
  * (SEMVER-MINOR) add --allow-inspector ability (Rafael Gonzaga) nodejs/node#59711
v8:
  * (SEMVER-MINOR) add cpu profile (theanarkh) nodejs/node#59807

PR-URL: nodejs/node#61001
Refs: https://hackerone.com/reports/3390084
PR-URL: nodejs-private/node-private#748
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
CVE-ID: CVE-2025-55132
Refs: https://hackerone.com/reports/3417819
Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com>
PR-URL: nodejs-private/node-private#760
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
CVE-ID: CVE-2025-55130
When a stack overflow exception occurs during async_hooks callbacks
(which use TryCatchScope::kFatal), detect the specific "Maximum call
stack size exceeded" RangeError and re-throw it instead of immediately
calling FatalException. This allows user code to catch the exception
with try-catch blocks instead of requiring uncaughtException handlers.

The implementation adds IsStackOverflowError() helper to detect stack
overflow RangeErrors and re-throws them in TryCatchScope destructor
instead of calling FatalException.

This fixes the issue where async_hooks would cause stack overflow
exceptions to exit with code 7 (kExceptionInFatalExceptionHandler)
instead of being catchable.

Fixes: nodejs/node#37989
Ref: https://hackerone.com/reports/3456295
PR-URL: nodejs-private/node-private#773
Refs: https://hackerone.com/reports/3456295
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
CVE-ID: CVE-2025-59466
Wrap pskCallback and ALPNCallback invocations in try-catch blocks
to route exceptions through owner.destroy() instead of letting them
become uncaught exceptions. This prevents remote attackers from
crashing TLS servers or causing resource exhaustion.

Fixes: https://hackerone.com/reports/3473882
PR-URL: nodejs-private/node-private#796
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
CVE-ID: CVE-2026-21637
This prevents the server from crashing due to an unhandled rejection
when a TLSSocket connection is abruptly destroyed during initialization
and the user has not attached an error handler to the socket.
e.g:

```js
const server = http2.createSecureServer({ ... })
server.on('secureConnection', socket => {
  socket.on('error', err => {
    console.log(err)
  })
})
```

PR-URL: nodejs-private/node-private#797
Fixes: nodejs/node#44751
Refs: https://hackerone.com/bugs?subject=nodejs&report_id=3262404
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
CVE-ID: CVE-2025-59465
PR-URL: nodejs/node#61283
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Richard Lau <richard.lau@ibm.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
PR-URL: nodejs/node#60997
Reviewed-By: Richard Lau <richard.lau@ibm.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
This removes the zero-fill toggle mechanism that allowed JavaScript
to control ArrayBuffer initialization via shared memory. Instead,
unsafe buffer creation now uses a dedicated C++ API.

Refs: https://hackerone.com/reports/3405778
Co-Authored-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com>
PR-URL: nodejs-private/node-private#759
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
CVE-ID: CVE-2025-55131
This is a security release.

Notable changes:

lib:
  * (CVE-2025-59465) add TLSSocket default error handler (RafaelGSS) <nodejs-private/node-private#797>
  * (CVE-2025-55132) disable futimes when permission model is enabled (RafaelGSS) <nodejs-private/node-private#748>
lib,permission:
  * (CVE-2025-55130) require full read and write to symlink APIs (RafaelGSS) <nodejs-private/node-private#760>
src:
  * (CVE-2025-59466) rethrow stack overflow exceptions in async\_hooks (Matteo Collina) <nodejs-private/node-private#773>
src,lib:
  * (CVE-2025-55131) refactor unsafe buffer creation to remove zero-fill toggle (Сковорода Никита Андреевич) <nodejs-private/node-private#759>
tls:
  * (CVE-2026-21637) route callback exceptions through error handlers (Matteo Collina) <nodejs-private/node-private#796>

PR-URL: nodejs-private/node-private#800
2026-01-13 Node.js v24.13.0 'Krypton' (LTS) Release
Git-EVTag-v0-SHA512: f6fd214d8fef7bb59d5ca9692798b55f4ac592c11fbaf66e18cafb8dbbfb20ed8787324e69843402e11eb0b6a39f584d0497416ff14f2512b2ab3b6778d9b8ef
@santigimeno santigimeno requested a review from RafaelGSS January 14, 2026 15:06
@santigimeno santigimeno self-assigned this Jan 14, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 14, 2026

Walkthrough

Restructures devcontainer configuration, adds a base devcontainer, and updates CODEOWNERS and .gitignore. Updates numerous GitHub Actions versions and ignores. Bumps multiple dependencies (c-ares, nghttp2, undici, corepack, amaro, v8). Adds runtime feature detection and new undici features (dedupe, RoundRobinPool, DNS storage). Many V8 and Node core API/internal changes and docs edits.

Changes

Cohort / File(s) Summary
Devcontainer
.devcontainer.json, .devcontainer/base/devcontainer.json, .gitignore, .github/CODEOWNERS
Remove top-level devcontainer.json, add shared base devcontainer, update .gitignore to track base file, add CODEOWNERS entries for .devcontainer/* and the devcontainer doc.
GitHub Actions
.github/workflows/* (many files)
Bumped action versions (notably actions/setup-node v5→v6, upload-artifact v4→v5, codeql v3→v4), added path ignores for test/internet/**, added post-release.yml, removed update-release-links.yml.
Undici (network client)
deps/undici/src/lib/**, deps/undici/src/types/**, deps/undici/src/package.json, deps/undici/src/docs/**
Add runtimeFeatures detector, new interceptors (deduplicate), DNSStorage abstraction, RoundRobinPool dispatcher, H2C/useH2c support, diagnostics channels and symbols, encoding/infra utilities, many API/type additions and docs.
c-ares
deps/cares/**
Bumped to 1.34.6, add C++17 test path, MidnightBSD parity, Unicode/Windows registry fixes, new ares_set_query_enqueue_cb, numeric_service_to_port helper, HAVE_CXX17 flag and related Makefile/CMake updates.
nghttp2
deps/nghttp2/lib/**
Bumped to 1.67.1, add package config/CMake exports, per-map seed, rand callback and glitch rate limiter APIs, API/type changes for map init and option flags.
V8
deps/v8/**
Wide changes: perf logging renamed & enabled on Darwin, FreeSpace object/layout redesign, regexp Greedy→FixedLength refactor across backends, various compiler/runtime adjustments and tests.
Node core: HTTP / Streams / TLS / FS
lib/_http_server.js, lib/_http_incoming.js, lib/_tls_wrap.js, lib/fs.js, lib/buffer.js
Add optimizeEmptyRequests option and IncomingMessage._dumpAndCloseReadable, improved TLS ALPN/PSK error handling (try/catch + socket destroy), permission-model gating for fs operations, Buffer.concat fast-path.
Benchmarks & N-API
benchmark/**, benchmark/napi/create_object_with_properties/*
Add new benchmarks (console throughput, esm import-meta changes), benchmark setup hook, new N-API native benchmark binding for create_object_with_properties.
Docs / API changes
doc/api/**, doc/contributing/**, changelogs, manpages, schema
Numerous documentation updates: new/renamed CLI flags (--strip-types, --allow-inspector), new APIs documented (napi_create_object_with_properties, v8.startCpuProfile/SyncCPUProfileHandle, SQLite SQLTagStore), docs for devcontainer usage, and many stability/flag name updates.
Misc deps & tooling
deps/corepack/*, deps/amaro/*, Makefile, common.gypi, .github/dependabot.yml
Version bumps (corepack, amaro), Makefile lint tool update (ruff), common.gypi V8 embedder string update, dependabot open PR limits set to 10 for some groups.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Application Client
  participant Dedup as Deduplicate Interceptor
  participant Map as PendingRequests Map
  participant Primary as Primary Dispatch (network)
  participant Handler as DeduplicationHandler
  participant Waiting as Waiting Handler(s)
  participant Response as Network Response

  Client->>Dedup: dispatch(request)
  Dedup->>Map: compute dedupeKey
  alt key exists
    Map-->>Handler: add Waiting Handler
    Dedup->>Waiting: attach to existing handler
  else new key
    Dedup->>Handler: create primary handler, register in Map
    Dedup->>Primary: forward actual dispatch
  end
  Primary->>Handler: onResponseStart/status/headers
  Handler->>Handler: buffer chunks via onResponseData
  Primary->>Handler: onResponseEnd
  Handler->>Waiting: replay buffered response to waiting handlers
  Handler->>Map: remove dedupeKey
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • RafaelGSS

"I nibble through the changelog's maze,
Devcontainers snug in base arrays,
Undici hums with pools that spin,
V8's loops now fixed within.
A joyful hop — build, test, and play!" 🐇

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.24% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: a release of Node v24.13.0 with nsolid v6.2.0, which is the primary purpose of this PR based on the branch name and objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 61f223c and 5554e72.

📒 Files selected for processing (2)
  • agents/grpc/src/grpc_agent.cc
  • doc/changelogs/NSOLID_CHANGELOG_V6_NODE_V24.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • doc/changelogs/NSOLID_CHANGELOG_V6_NODE_V24.md
🧰 Additional context used
🧠 Learnings (21)
📓 Common learnings
Learnt from: santigimeno
Repo: nodesource/nsolid PR: 0
File: :0-0
Timestamp: 2025-10-27T13:06:17.506Z
Learning: In the nodesource/nsolid repository, when reviewing PRs that add or modify V8 patches (e.g., in deps/v8/patches/), focus review comments on the patch management infrastructure (configure.py, apply-patches.sh, README.md, etc.) and not on the V8 code changes contained within the .patch files themselves, as the patch content is out of scope for the patch management PR.
📚 Learning: 2025-12-03T14:35:32.707Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/util/GEMINI.md:0-0
Timestamp: 2025-12-03T14:35:32.707Z
Learning: Applies to deps/grpc/src/core/util/**/*.{cc,h,cpp} : Use time-related functions from `time.h` and `time.cc`

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:29:25.191Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/ext/filters/channel_idle/GEMINI.md:0-0
Timestamp: 2025-12-03T14:29:25.191Z
Learning: Applies to deps/grpc/src/core/ext/filters/channel_idle/**/*idle*filter*.{h,cc} : Implement client-side idle connection timeout using `LegacyClientIdleFilter` to close the transport if the channel has been idle (no active calls) for a configurable amount of time, controlled by the `GRPC_ARG_CLIENT_IDLE_TIMEOUT_MS` channel argument

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:35:32.707Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/util/GEMINI.md:0-0
Timestamp: 2025-12-03T14:35:32.707Z
Learning: Applies to deps/grpc/src/core/util/**/*.{cc,h,cpp} : Use synchronization primitives from `sync.h` and `sync.cc`

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:34:55.521Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/telemetry/GEMINI.md:0-0
Timestamp: 2025-12-03T14:34:55.521Z
Learning: Applies to deps/grpc/src/core/telemetry/**/telemetry/tcp_tracer.{h,cc} : Use the `TcpTracer` class to trace TCP-level events in tcp_tracer.h / tcp_tracer.cc

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:29:25.191Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/ext/filters/channel_idle/GEMINI.md:0-0
Timestamp: 2025-12-03T14:29:25.191Z
Learning: Applies to deps/grpc/src/core/ext/filters/channel_idle/**/*idle*filter*.{h,cc} : Implement server-side maximum connection age enforcement using `LegacyMaxAgeFilter` to send a `GOAWAY` frame when the connection reaches its maximum age and close the connection after a grace period, configured via `GRPC_ARG_MAX_CONNECTION_AGE_MS`, `GRPC_ARG_MAX_CONNECTION_IDLE_MS`, and `GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS` channel arguments

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:34:52.246Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/telemetry/GEMINI.md:0-0
Timestamp: 2025-12-03T14:34:52.246Z
Learning: Applies to deps/grpc/src/core/telemetry/**/tcp_tracer.{h,cc} : Implement TcpTracer class to trace TCP-level events in tcp_tracer.h/tcp_tracer.cc

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:35:32.707Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/util/GEMINI.md:0-0
Timestamp: 2025-12-03T14:35:32.707Z
Learning: Applies to deps/grpc/src/core/util/**/*.{cc,h,cpp} : Use crash utilities from `crash.h` and `crash.cc` for controlled process termination in gRPC core

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:35:32.707Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/util/GEMINI.md:0-0
Timestamp: 2025-12-03T14:35:32.707Z
Learning: Applies to deps/grpc/src/core/util/**/*.{cc,h,cpp} : Use `RefCounted` class from `ref_counted.h` as a base class for reference-counted objects

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:34:55.521Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/telemetry/GEMINI.md:0-0
Timestamp: 2025-12-03T14:34:55.521Z
Learning: Applies to deps/grpc/src/core/telemetry/**/telemetry/call_tracer.{h,cc} : Use the `CallTracer` class to trace the lifecycle of a gRPC call in call_tracer.h / call_tracer.cc

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:35:32.707Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/util/GEMINI.md:0-0
Timestamp: 2025-12-03T14:35:32.707Z
Learning: Applies to deps/grpc/src/core/util/**/*.{cc,h,cpp} : Use `ref_counted_ptr` smart pointer from `ref_counted_ptr.h` for managing `RefCounted` objects

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:34:55.521Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/telemetry/GEMINI.md:0-0
Timestamp: 2025-12-03T14:34:55.521Z
Learning: Applies to deps/grpc/src/core/telemetry/**/telemetry/metrics.{h,cc} : Use the `Metrics` class to collect and report metrics in metrics.h / metrics.cc

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:34:47.986Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/telemetry/GEMINI.md:0-0
Timestamp: 2025-12-03T14:34:47.986Z
Learning: Applies to deps/grpc/src/core/telemetry/**/metrics.{h,cc} : The `Metrics` class should be used to collect and report metrics

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:34:52.246Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/telemetry/GEMINI.md:0-0
Timestamp: 2025-12-03T14:34:52.246Z
Learning: Applies to deps/grpc/src/core/telemetry/**/metrics.{h,cc} : Implement Metrics class to collect and report metrics in metrics.h/metrics.cc

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:30:16.146Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/ext/filters/load_reporting/GEMINI.md:0-0
Timestamp: 2025-12-03T14:30:16.146Z
Learning: Applies to deps/grpc/src/core/ext/filters/load_reporting/**/registered_opencensus_objects.h : Define OpenCensus measures and tags used by the server load reporting filter in the registered_opencensus_objects.h file

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:29:16.068Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/ext/filters/backend_metrics/GEMINI.md:0-0
Timestamp: 2025-12-03T14:29:16.068Z
Learning: Applies to deps/grpc/src/core/ext/filters/backend_metrics/**/backend_metric_provider.h : Define the `BackendMetricProvider` interface to be responsible for providing backend metric data to the filter.

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:29:16.068Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/ext/filters/backend_metrics/GEMINI.md:0-0
Timestamp: 2025-12-03T14:29:16.068Z
Learning: Applies to deps/grpc/src/core/ext/filters/backend_metrics/**/backend_metric_filter.{h,cc} : In `BackendMetricFilter` class, retrieve backend metrics from a `BackendMetricProvider`, serialize them using the `xds.data.orca.v3.OrcaLoadReport` protobuf message, and attach the result to the server's trailing metadata. Activate via `GRPC_ARG_SERVER_CALL_METRIC_RECORDING` channel argument.

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:29:05.695Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/credentials/transport/GEMINI.md:0-0
Timestamp: 2025-12-03T14:29:05.695Z
Learning: Applies to deps/grpc/src/core/credentials/transport/**/tls_credentials.{h,cc} : Use TLS (Transport Layer Security) credentials to configure TLS security for the Chttp2 transport

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:29:08.569Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/credentials/transport/GEMINI.md:0-0
Timestamp: 2025-12-03T14:29:08.569Z
Learning: Applies to deps/grpc/src/core/credentials/transport/**/{tls_credentials.h,tls_credentials.cc} : Implement credentials for TLS transport security in `tls_credentials.h` / `tls_credentials.cc`

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:29:05.695Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/credentials/transport/GEMINI.md:0-0
Timestamp: 2025-12-03T14:29:05.695Z
Learning: Applies to deps/grpc/src/core/credentials/transport/**/insecure_credentials.{h,cc} : Use insecure credentials implementation when no security is required for the transport

Applied to files:

  • agents/grpc/src/grpc_agent.cc
📚 Learning: 2025-12-03T14:29:05.695Z
Learnt from: CR
Repo: nodesource/nsolid PR: 0
File: deps/grpc/src/core/credentials/transport/GEMINI.md:0-0
Timestamp: 2025-12-03T14:29:05.695Z
Learning: Applies to deps/grpc/src/core/credentials/transport/**/alts_credentials.{h,cc} : Use ALTS (Application Layer Transport Security) credentials to configure ALTS security for the transport

Applied to files:

  • agents/grpc/src/grpc_agent.cc
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: coverage-windows
  • GitHub Check: test-macOS
  • GitHub Check: build-tarball
  • GitHub Check: lint-js-and-md
  • GitHub Check: coverage-linux
  • GitHub Check: coverage-linux-without-intl
  • GitHub Check: test-linux (ubuntu-24.04-arm)
  • GitHub Check: test-linux (ubuntu-24.04)
🔇 Additional comments (4)
agents/grpc/src/grpc_agent.cc (4)

25-27: LGTM!

Good refactoring to move chrono type aliases to the top level, consistent with the existing declarations for system_clock and time_point on lines 28-29.


81-82: LGTM!

Centralizing the gRPC timeout as a named constant improves maintainability and ensures consistent timeout behavior across all exporters.


1076-1077: LGTM – credential creation pattern is correct.

The pattern of explicitly creating credentials via MakeCredentials() and then setting use_ssl_credentials = false ensures the OtlpGrpcClientFactory::Create() uses the pre-configured credentials rather than attempting to create new ones. This avoids redundant credential creation and allows TLS keylog support.


1082-1122: LGTM – consistent timeout and credential propagation across exporters.

All three exporters (trace, metrics, log) consistently receive:

  1. The centralized DEFAULT_GRPC_TIMEOUT value
  2. The pre-created credentials (when not in insecure mode)

This ensures uniform timeout and security behavior across all gRPC export paths.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (13)
doc/api/child_process.md (1)

1484-1503: Remove duplicate close event handling.

This example contains both the original event-based handler (lines 1493-1499) and the new await once() pattern (lines 1500-1502). Both handlers would execute in the same code, causing the close message to be logged twice. This is inconsistent with the earlier examples which cleanly replaced the event handler.

Either remove the old event handler to match the pattern used in the earlier examples, or clearly separate these as distinct alternative approaches.

📝 Suggested fix
 ls.on('close', (code) => {
   console.log(`child process close all stdio with code ${code}`);
 });
 
 ls.on('exit', (code) => {
   console.log(`child process exited with code ${code}`);
 });
-
-const [code] = await once(ls, 'close');
-console.log(`child process close all stdio with code ${code}`);

Or, if both approaches should be demonstrated, they should be in separate code blocks with explanatory text distinguishing them.

deps/undici/src/lib/mock/snapshot-utils.js (1)

43-45: Fallback does not actually hash the value—it only encodes.

The fallback path Buffer.from(value).toString('base64url') performs base64url encoding without hashing. The crypto.hash API is only available in Node.js 19.1.0+; older versions fall back to the encoding-only path.

This creates a semantic mismatch: the JSDoc states the function returns "the base64url encoded hash," but the fallback implementation contradicts this. The practical implications are:

  • Output length differs between the two paths (fixed 43 chars for SHA-256 vs. variable for base64url)
  • If the crypto.hash availability differs between environments, generated snapshot IDs won't be stable

Since this is upstream undici code, this fallback is likely intentional for broad Node.js version compatibility. However, the JSDoc should clarify the fallback behavior rather than implying all code paths perform hashing.

deps/undici/src/docs/docs/api/Client.md (1)

33-38: Documentation inconsistency: Notes section contradicts the new useH2c option.

Line 33 documents the new useH2c option that "Enforces h2c for non-https connections", but line 37 in the notes section still states "It only works under TLS connections. h2c is not supported." This note should be updated to reflect the new h2c support when useH2c is enabled.

doc/api/http.md (1)

3569-3684: Fix pr-url and soften "never emit" wording for optimizeEmptyRequests.

The pr-url should point to this PR (#409), not upstream nodejs/node PR #59778—the lint-pr-url check validates that pr-url matches the current pull request URL.

Also, "never emit any stream events" overstates the guarantee. Since the stream is already-ended when initialized, new listeners won't fire, but the phrasing could be softened to say "will not emit stream events to listeners added after initialization" or similar.

deps/cares/src/lib/ares_init.c (1)

485-507: Lock (*dest) while copying callbacks to prevent event thread from reading partially-initialized pointers.

The event thread for (*dest) starts in ares_init_options() before the callbacks are copied at lines 488–501. Since the event thread reads notify_pending_write_cb and query_enqueue_cb without synchronization (see ares_process.c:1253 and ares_process.c:1390), wrap the callback assignments with ares_channel_lock(*dest) and ares_channel_unlock(*dest) to ensure thread safety.

deps/nghttp2/lib/nghttp2_session.c (2)

432-614: map_seed fallback being 0 may negate hash/DoS hardening when rand_callback is unset.
If nghttp2_map_init()’s seed is intended to reduce collision attacks, consider using a non-deterministic fallback when callbacks->rand_callback is NULL (or at least initialize map_seed before invoking the callback to avoid reliance on “must fill all bytes” behavior).

Proposed adjustment (minimal)
-  if (callbacks->rand_callback) {
-    callbacks->rand_callback((uint8_t *)&map_seed, sizeof(map_seed));
-  } else {
-    map_seed = 0;
-  }
+  map_seed = 0;
+  if (callbacks->rand_callback) {
+    callbacks->rand_callback((uint8_t *)&map_seed, sizeof(map_seed));
+  } else {
+    /* Fallback: avoid deterministic seed where possible */
+    map_seed = (uint32_t)nghttp2_time_now_sec();
+  }

5471-5528: Rate limiter is enabled by default (not opt-in); verify if default rates should be relaxed.

The glitch rate limiter is always initialized (not opt-in) with a burst of 1000 and a rate of 33 tokens/second. The NGHTTP2_OPT_GLITCH_RATE_LIMIT option allows overriding these defaults, not disabling the limiter entirely. This means valid-but-rare patterns (PRIORITY frames, empty DATA without END_STREAM, unknown extension frames) will trigger rate limiting on every session by default.

At the default rate of 33 events/second, clients legitimately sending PRIORITY frames or extension frames in rapid succession could exceed the limit and receive an unexpected GOAWAY (ENHANCE_YOUR_CALM). If this is a new feature, older clients with these patterns may encounter unexpected disconnections.

Consider: either relax the default rates (e.g., rate=0 to disable by default), or document this as a behavioral change requiring opt-out configuration.

Also applies to: 5602–5648, 5813–5832, 5908–5960, 6067–6083, 6615–6631

deps/v8/src/regexp/regexp-compiler.cc (3)

129-141: Comment tweak: “simple greedy loops” vs “fixed length loops” phrasing is slightly confusing
Line 129 says “Simple greedy loops…” and Line 130 says “these fixed length loops”. Consider rewording to make it clear you’re describing the optimization category (fixed-length loop optimization) rather than renaming the loop itself.


297-318: Make GetStoredPosition more robust against caller misuse
DCHECK_EQ(0, *cp_offset) (Line 305) requires callers to pre-init the out-param. It’s easy to violate and doesn’t buy much. Prefer setting *cp_offset = 0 at function entry and dropping the DCHECK (or DCHECK that cp_offset != nullptr).

Proposed diff
 bool Trace::GetStoredPosition(int reg, int* cp_offset) const {
-  DCHECK_EQ(0, *cp_offset);
+  DCHECK_NOT_NULL(cp_offset);
+  *cp_offset = 0;
   for (auto trace : *this) {
     if (trace->has_action() && trace->action()->Mentions(reg)) {
       if (trace->action_->action_type() == ActionNode::CLEAR_POSITION ||
           trace->action_->action_type() == ActionNode::RESTORE_POSITION) {
         *cp_offset = trace->next_->cp_offset();
         return true;
       } else {
         return false;
       }
     }
   }
   return false;
 }

2628-2679: Potential int overflow in fixed-length loop length accumulation
length += node_length; (Line 2666) can overflow signed int before the final bounds check (Lines 2674-2676). If it wraps, it can accidentally pass the min/max CP offset check and misclassify a too-large alternative as valid.

Proposed diff (checked add)
 int ChoiceNode::FixedLengthLoopLengthForAlternative(
     GuardedAlternative* alternative) {
   int length = 0;
   RegExpNode* node = alternative->node();
   int recursion_depth = 0;
   while (node != this) {
     if (recursion_depth++ > RegExpCompiler::kMaxRecursion) {
       return kNodeIsTooComplexForFixedLengthLoops;
     }
     int node_length = node->FixedLengthLoopLength();
     if (node_length == kNodeIsTooComplexForFixedLengthLoops) {
       return kNodeIsTooComplexForFixedLengthLoops;
     }
-    length += node_length;
+    if (V8_UNLIKELY(base::bits::SignedAddOverflow32(length, node_length,
+                                                    &length))) {
+      return kNodeIsTooComplexForFixedLengthLoops;
+    }
     node = node->AsSeqRegExpNode()->on_success();
   }
   if (read_backward()) {
     length = -length;
   }
   if (length < RegExpMacroAssembler::kMinCPOffset ||
       length > RegExpMacroAssembler::kMaxCPOffset) {
     return kNodeIsTooComplexForFixedLengthLoops;
   }
   return length;
 }
deps/v8/src/regexp/regexp-compiler.h (1)

243-353: Trace copy ctor likely missing quick_check_performed_ copy
Trace(const Trace& other) copies most state but does not initialize quick_check_performed_, so it defaults to characters_ == 0. That drops quick-check context on every Trace new_trace(*trace) and can change codegen decisions/optimizations.

Proposed diff
 Trace(const Trace& other) V8_NOEXCEPT
       : cp_offset_(other.cp_offset_),
         flush_budget_(other.flush_budget_),
         at_start_(other.at_start_),
         has_any_actions_(other.has_any_actions_),
         action_(nullptr),
         backtrack_(other.backtrack_),
         fixed_length_loop_state_(other.fixed_length_loop_state_),
         characters_preloaded_(other.characters_preloaded_),
         bound_checked_up_to_(other.bound_checked_up_to_),
+        quick_check_performed_(other.quick_check_performed_),
         next_(&other) {}
deps/v8/src/regexp/regexp-nodes.h (2)

329-420: Add direct include for base::IsInRange() and guard register access methods against misuse.

  • Mentions() uses base::IsInRange() which is defined in src/base/bounds.h, but that header is not directly included in regexp-nodes.h. Add direct include to avoid relying on transitive includes.
  • register_to() lacks the DCHECK(IsSimpleAction()) guard that register_from() has, creating asymmetry and risking accidental calls on non-simple actions. Add matching DCHECK.
  • Constructor should validate from <= to when to != -1 to prevent creating inverted ranges that would break Mentions() and related logic. Add defensive DCHECKs.
Proposed diff
--- a/deps/v8/src/regexp/regexp-nodes.h
+++ b/deps/v8/src/regexp/regexp-nodes.h
@@ -1,6 +1,7 @@
 `#include` "src/codegen/label.h"
+#include "src/base/bounds.h"
 `#include` "src/regexp/regexp-macro-assembler.h"
 `#include` "src/zone/zone.h"
 
   int register_from() const {
     DCHECK(IsSimpleAction());
     return data_.u_simple.register_from;
   }
 
-  int register_to() const { return data_.u_simple.register_to; }
+  int register_to() const {
+    DCHECK(IsSimpleAction());
+    return data_.u_simple.register_to;
+  }
 
   ActionNode(ActionType action_type, RegExpNode* on_success, int from,
              int to = -1, int value = 0)
       : SeqRegExpNode(on_success), action_type_(action_type) {
+    DCHECK_GE(from, 0);
+    DCHECK(to == -1 || to >= from);
     data_.u_simple.register_from = from;
     data_.u_simple.register_to = to == -1 ? from : to;
     data_.u_simple.value = value;
     DCHECK(IsSimpleAction());
   }

688-716: Flags are not consistently reset before all alternatives in EmitFixedLengthLoop and the early-return path.

The code at line 3222-3224 explicitly acknowledges that "flags might be modified when emitting an alternative" and need to be reset, but this is inconsistently applied:

  1. Early return (line 3195): When choice_count == 1 with no guards, the alternative's Emit is called without preserving flags at all.
  2. EmitFixedLengthLoop (line 3282): The first alternative's Emit is called without compiler->set_flags(flags) beforehand, unlike EmitChoices which sets flags before each alternative.

While EmitChoices properly calls compiler->set_flags(flags) at the start of each iteration before calling Emit, and out-of-line continuations also preserve flags, these two paths bypass the flag reset mechanism. Ensure all code paths that emit alternatives reset flags to the captured state first.

🤖 Fix all issues with AI agents
In `@benchmark/esm/import-meta.js`:
- Around line 25-52: In main(), change how fixtureDir is resolved: replace
path.resolve(__filename, '../../fixtures') with path.resolve(__dirname,
'../fixtures') (or use __dirname + '/.. /fixtures') so fixtureDir points to
benchmark/fixtures and fixtureFile/fixtureFileURL use that correct dir; also
handle import errors from load(...) by appending a .catch(err => { throw err; })
(or otherwise rethrow/log and process.exit) after the .then(...) to ensure
promise rejections propagate instead of silently failing; reference the main
function, variables fixtureDir, fixtureFileURL, and the load(...) call when
applying the changes.

In `@deps/cares/src/lib/ares_init.c`:
- Around line 607-617: The setter ares_set_query_enqueue_cb currently updates
channel->query_enqueue_cb and channel->query_enqueue_cb_data without holding the
channel lock; make it thread-safe by acquiring the channel lock used elsewhere
in this file before assigning those fields and releasing it afterward (follow
the same lock/unlock calls used by other setters in this file), while keeping
the early return when channel == NULL.

In `@deps/cares/src/lib/ares_sysconfig_win.c`:
- Around line 115-118: The early return when WideCharToMultiByte returns 0 leaks
the buffer pointed to by val; before returning ARES_FALSE you must free val
using the same allocator used at its allocation (e.g., free(val) or
ares_free(val) depending on how val was allocated), and then return ARES_FALSE;
ensure any other early-return paths in the function also free val to avoid
similar leaks.

In `@deps/undici/src/lib/interceptor/dns.js`:
- Around line 24-26: Update the DNSStorage.set signature to accept the third
options parameter (e.g., set(hostname, records, options)) so it matches the
TypeScript contract and callers that pass { ttl }. Modify the implementation of
DNSStorage.set to include the options parameter (even if unused) and forward or
ignore it safely, and update any internal references to call sites like the call
at line where set is invoked with { ttl: minTTL } to ensure no parameter is
dropped; keep the existing behavior of storing hostname/records in this.#records
while matching the declared function signature in interceptors.d.ts.

In `@doc/api/packages.md`:
- Around line 1164-1179: Update the two broken Markdown link definitions so they
point to the actual anchor IDs: change the WebAssembly modules reference from
esm.md#wasm-modules to esm.md#esm_experimental_wasm_modules and change
customization hooks from module.md#customization-hooks to
module.md#module_customization_hooks; leave the error-code links as-is (their
case-insensitive anchors work) and ensure you update the entries in the same
link-definition block that contains symbols like [`"exports"`], [`"imports"`],
and [entry points].

In `@doc/api/worker_threads.md`:
- Around line 1833-1834: Restore the full description for the worker.performance
property by replacing the truncated sentence with a complete sentence such as:
"An object that can be used to query performance information from a worker
instance. Similar to perf_hooks.performance." Ensure the reference link for
`perf_hooks.performance` (the `[perf_hooks.performance][]` anchor) is re-added
at the end of the document if it was removed so the inline reference resolves
correctly; update the `worker.performance` documentation block to include the
restored text and the reference link.

In `@lib/fs.js`:
- Around line 1278-1286: The fsync function sets req.oncomplete =
makeCallback(callback) but calls the raw callback on the permission-denied path;
change the error path to invoke the wrapped callback (i.e., use req.oncomplete
or call makeCallback(callback) result) so the callback is always the wrapped
version—update the permission check in fsync to call req.oncomplete(new
ERR_ACCESS_DENIED(...)) or assign and call the wrapped callback instead of
calling the original callback directly (refer to fsync, FSReqCallback,
makeCallback, permission.isEnabled, ERR_ACCESS_DENIED, binding.fsync).
- Around line 1246-1255: The permission-denied path uses the raw callback
instead of the wrapped one; set req.oncomplete = makeCallback(callback) first
(already done) and invoke that wrapped callback with the error instead of
calling callback directly — i.e., replace callback(new ERR_ACCESS_DENIED(...))
with req.oncomplete(new ERR_ACCESS_DENIED('fdatasync API is disabled when
Permission Model is enabled.')); keep the early return.
🟡 Minor comments (22)
deps/undici/src/lib/dispatcher/dispatcher-base.js-19-20 (1)

19-20: JSDoc type annotation has a syntax error.

The generic type is missing its closing angle bracket: Array<Function|null} should be Array<Function|null>} or more likely Array<Function>|null} to match the semantics used on line 25.

Since this is vendored undici code, consider reporting this upstream if not already fixed.

Suggested fix
-  /** `@type` {Array<Function|null} */
+  /** `@type` {Array<Function>|null} */
   [kOnDestroyed] = null;
deps/undici/src/docs/docs/api/WebSocket.md-48-48 (1)

48-48: Missing WebSocket import in the example.

The code example imports only Agent but uses WebSocket on line 52 without importing it. This will cause a ReferenceError when users try to run the example.

📝 Proposed fix
-import { Agent } from 'undici'
+import { WebSocket, Agent } from 'undici'
doc/api/v8.md-1403-1419 (1)

1403-1419: Fix grammar in method descriptions.

The method descriptions use present participle ("Stopping") instead of present tense. This is inconsistent with Node.js documentation conventions where API method descriptions typically use present tense.

📝 Proposed fix
-Stopping collecting the profile and return the profile data.
+Stops collecting the profile and returns the profile data.
-Stopping collecting the profile and the profile will be discarded.
+Stops collecting the profile and discards the profile data.
doc/api/v8.md-1516-1531 (1)

1516-1531: Fix grammar and add using syntax example.

Line 1524 has a grammar issue similar to the class methods. Additionally, while the documentation claims support for using syntax (line 1525), the example only demonstrates manual resource management with stop(). Since Symbol.dispose is implemented, an example showing the using syntax would be valuable.

📝 Proposed fixes

Fix the grammar:

-Starting a CPU profile then return a `SyncCPUProfileHandle` object.
+Starts a CPU profile and returns a `SyncCPUProfileHandle` object.

Add an additional example demonstrating the using syntax:

// Using the 'using' syntax for automatic disposal
using handle = v8.startCpuProfile();
// Profile collection stops automatically when 'handle' goes out of scope
doc/api/sqlite.md-989-997 (1)

989-997: Fix the description inconsistency.

The heading indicates size() is a method (note the parentheses), but the description text calls it "a read-only property." This is inconsistent.

📝 Proposed fix
 ### `sqlTagStore.size()`
 
 <!-- YAML
 added: v24.9.0
 -->
 
 * Returns: {integer} The number of prepared statements currently in the cache.
 
-A read-only property that returns the number of prepared statements currently in the cache.
+Returns the number of prepared statements currently in the cache.
doc/api/cli.md-4093-4093 (1)

4093-4093: Verify the link fragment.

The link reference [environment_variables]: #environment-variables_1`` may have an incorrect fragment. The static analysis tool flagged this as a potentially invalid link fragment.

The section at line 3273 is ## Environment variables, which would typically create the anchor #environment-variables (with a hyphen, not underscore). Please verify that the _1 suffix is needed and that the anchor actually uses an underscore.

Based on static analysis hints.

deps/undici/src/README.md-194-210 (1)

194-210: Missing import for setGlobalDispatcher.

The example uses setGlobalDispatcher(client) but doesn't import it. Users copying this example will encounter a ReferenceError.

📝 Proposed fix
-import { fetch, Agent, interceptors, cacheStores } from 'undici';
+import { fetch, Agent, interceptors, cacheStores, setGlobalDispatcher } from 'undici';
deps/cares/RELEASE-NOTES.md-27-27 (1)

27-27: Fix PR reference mismatch.

The link text shows #996 but the URL points to pull/997. This inconsistency should be corrected.

📝 Proposed fix
-  [PR `#996`](https://github.com/c-ares/c-ares/pull/997)
+  [PR `#997`](https://github.com/c-ares/c-ares/pull/997)
deps/cares/RELEASE-NOTES.md-24-24 (1)

24-24: Fix capitalization.

"Windows" should be capitalized as it refers to the Microsoft operating system. As per static analysis hints, this is a proper noun.

📝 Proposed fix
-* Fix clang build on windows.
+* Fix clang build on Windows.
deps/cares/RELEASE-NOTES.md-6-7 (1)

6-7: Wrap bare URL in angle brackets for markdown compliance.

The CVE number and GitHub Security Advisory reference are correct. However, the bare URL on line 7 should be wrapped in angle brackets to comply with markdown linting rules:

Markdown fix
-* CVE-2025-62408. A use-after-free bug has been uncovered in read_answers() that
-  was introduced in v1.32.3. Please see https://github.com/c-ares/c-ares/security/advisories/GHSA-jq53-42q6-pqr5
+* CVE-2025-62408. A use-after-free bug has been uncovered in read_answers() that
+  was introduced in v1.32.3. Please see <https://github.com/c-ares/c-ares/security/advisories/GHSA-jq53-42q6-pqr5>
deps/undici/src/lib/handler/cache-handler.js-199-203 (1)

199-203: Address potential async store handling in 304 Not Modified path.

While the current built-in store implementations (MemoryCacheStore and SqliteCacheStore) return synchronously, the cache interceptor's design (cache.js lines 426-428) explicitly accounts for stores that return Promises via typeof result.then === 'function' checks. The 304 path at line 199 calls this.#store.get() without handling this case, making it incompatible with async store implementations. For consistency and future extensibility, this should either handle the Promise case or document that custom stores must be synchronous.

deps/undici/src/lib/web/fetch/formdata-parser.js-537-555 (1)

537-555: Typo in comment: // + should be // =

The comment on line 553 says // + but 0x3d is the ASCII code for = (equals sign), not + (plus sign, which is 0x2b).

📝 Proposed fix
-    char === 0x3d    // +
+    char === 0x3d    // =
deps/undici/src/lib/interceptor/deduplicate.js-14-23 (1)

14-23: Validation of opts occurs after destructuring.

The typeof opts !== 'object' check on line 21 happens after destructuring opts on lines 15-19. If opts is a non-object primitive (e.g., a string or number), the destructuring will succeed but yield unexpected undefined values rather than throwing the intended TypeError.

Consider reordering validation before destructuring:

🛠️ Suggested fix
 module.exports = (opts = {}) => {
+  if (typeof opts !== 'object' || opts === null) {
+    throw new TypeError(`expected type of opts to be an Object, got ${opts === null ? 'null' : typeof opts}`)
+  }
+
   const {
     methods = ['GET'],
     skipHeaderNames = [],
     excludeHeaderNames = []
   } = opts
 
-  if (typeof opts !== 'object' || opts === null) {
-    throw new TypeError(`expected type of opts to be an Object, got ${opts === null ? 'null' : typeof opts}`)
-  }
deps/undici/src/types/round-robin-pool.d.ts-14-15 (1)

14-15: Minor typo in JSDoc comment.

The comment references pool.destroyed() but the method is pool.destroy(). The property itself (destroyed) is correctly a boolean.

📝 Suggested fix
-  /** `true` after `pool.destroyed()` has been called or `pool.close()` has been called and the pool shutdown has completed. */
+  /** `true` after `pool.destroy()` has been called or `pool.close()` has been called and the pool shutdown has completed. */
deps/undici/undici.js-2141-2141 (1)

2141-2141: Minor JSDoc typo.

The closing angle bracket is missing in the type annotation.

📝 Suggested fix
-      /** `@type` {Array<Function|null} */
+      /** `@type` {Array<Function>|null} */
doc/changelogs/CHANGELOG_V24.md-68-82 (1)

68-82: Fix Markdown list formatting in 24.13.0 “Notable Changes” (currently nests subsystem labels into the previous bullet).
Lines 74/76/78/80 are indented, so they’ll render as part of the previous list item instead of as their own headings/grouping, which makes the section hard to read (and possibly lint-failing depending on rules).

Proposed formatting fix
 ### Notable Changes
 
-lib:
-
-* (CVE-2025-59465) add TLSSocket default error handler (RafaelGSS) <https://github.com/nodejs-private/node-private/pull/797>
-* (CVE-2025-55132) disable futimes when permission model is enabled (RafaelGSS) <https://github.com/nodejs-private/node-private/pull/748>
-  lib,permission:
-* (CVE-2025-55130) require full read and write to symlink APIs (RafaelGSS) <https://github.com/nodejs-private/node-private/pull/760>
-  src:
-* (CVE-2025-59466) rethrow stack overflow exceptions in async\_hooks (Matteo Collina) <https://github.com/nodejs-private/node-private/pull/773>
-  src,lib:
-* (CVE-2025-55131) refactor unsafe buffer creation to remove zero-fill toggle (Сковорода Никита Андреевич) <https://github.com/nodejs-private/node-private/pull/759>
-  tls:
-* (CVE-2026-21637) route callback exceptions through error handlers (Matteo Collina) <https://github.com/nodejs-private/node-private/pull/796>
+* (CVE-2025-59465) **lib**: add TLSSocket default error handler (RafaelGSS) <https://github.com/nodejs-private/node-private/pull/797>
+* (CVE-2025-55132) **lib**: disable futimes when permission model is enabled (RafaelGSS) <https://github.com/nodejs-private/node-private/pull/748>
+* (CVE-2025-55130) **lib,permission**: require full read and write to symlink APIs (RafaelGSS) <https://github.com/nodejs-private/node-private/pull/760>
+* (CVE-2025-59466) **src**: rethrow stack overflow exceptions in async\_hooks (Matteo Collina) <https://github.com/nodejs-private/node-private/pull/773>
+* (CVE-2025-55131) **src,lib**: refactor unsafe buffer creation to remove zero-fill toggle (Сковорода Никita Андреевич) <https://github.com/nodejs-private/node-private/pull/759>
+* (CVE-2026-21637) **tls**: route callback exceptions through error handlers (Matteo Collina) <https://github.com/nodejs-private/node-private/pull/796>
doc/node.1-729-735 (1)

729-735: Minor grammar fix in NODE_COMPILE_CACHE_PORTABLE description.
“location … remain consistent” → “location … remains consistent”.

Proposed fix
- will be hit as long as the location of the modules relative to the cache directory remain
+ will be hit as long as the location of the modules relative to the cache directory remains
doc/api/n-api.md-2640-2675 (1)

2640-2675: Use C terminology (NULL) and a c fence for consistency with Node-API documentation.

The code fence should be c instead of cpp (the similar napi_create_object function above uses c, and the Node-API documentation predominantly uses c, appearing 214 times vs. only 6 times for ```cpp).

Additionally, the parameter description should use NULL instead of nullptrnullptr is C++ terminology, whereas the Node-API is a C API and consistently uses NULL in documentation. The phrase "or a nullptr that will be converted to null" should be "or NULL (which will be treated as null)".

The version metadata (added: v24.12.0) could not be definitively verified with available repository history.

doc/node-config-schema.json-732-760 (1)

732-760: Fix minItems placement for array schemas (currently not enforced).
minItems should be at the array schema level, not nested under items. This affects multiple array properties generated by the schema builder including watch-path.

Example fix
             {
               "items": {
-                "type": "string",
-                "minItems": 1
+                "type": "string"
               },
+              "minItems": 1,
               "type": "array"
             }

Regarding watch appearing in both nodeOptions and as a top-level namespace: this is intentional. The nodeOptions.watch boolean is for backward compatibility (from CLI environment options), while the top-level watch object is a separate namespace for detailed watch configuration (watch-path, watch-kill-signal, etc.).

doc/contributing/using-devcontainer.md-16-16 (1)

16-16: Fix typo: "popuplar" → "popular".

Proposed fix
-Among them, [Visual Studio Code (VS Code)](https://code.visualstudio.com/) is a very popuplar option.
+Among them, [Visual Studio Code (VS Code)](https://code.visualstudio.com/) is a very popular option.
doc/contributing/using-devcontainer.md-5-5 (1)

5-5: Fix typo: "pre-genreated" → "pre-generated".

Proposed fix
-development container that comes with pre-installed build dependencies and pre-genreated build cache.
+development container that comes with pre-installed build dependencies and pre-generated build cache.
deps/nghttp2/lib/includes/nghttp2/nghttp2.h-2042-2055 (1)

2042-2055: Fix typo and grammar in docs: "which includes upper cased latter" → "which include upper case letter".

Appears at lines 2042-2055 and 2080-2092.

Proposed doc fix
- * Also header fields which includes upper cased latter are also
+ * Also header fields which include upper case letter are also
  * treated as error without passing them to this callback.
🧹 Nitpick comments (34)
deps/undici/src/eslint.config.js (1)

19-20: LGTM! Good additions for enforcing Node.js best practices.

Both rules are sensible additions:

  • n/prefer-node-protocol ensures clarity by requiring the node: prefix for built-in modules.
  • n/no-process-exit encourages proper error handling over abrupt termination.

Nitpick: Minor style inconsistency—line 19 uses ['error'] (array) while line 20 uses 'error' (string). Both are functionally equivalent, but using the same format would be slightly more consistent.

doc/api/errors.md (1)

706-712: Consider improving description clarity and verify version metadata.

The new error code entry is properly formatted, but the description could be more direct and clear:

Current: "An operation related to module loading is customized by an asynchronous loader hook that never settled the promise before the loader thread exits."

Suggested: "An asynchronous loader hook customizing module loading never settled its promise before the loader thread exited."

Additionally, verify whether YAML version metadata should be added. Some error codes in this file include version information (see lines 656-657 for ABORT_ERR, lines 840-842 for ERR_CPU_PROFILE_ALREADY_STARTED), while others don't. Since this is part of the v24.13.0 release, confirm whether the following metadata should be added:

<!-- YAML
added: v24.13.0
-->
deps/nghttp2/lib/nghttp2_map.c (1)

118-121: Minor: Redundant hash computation in debug output.

map_hash(map, bkt->key) is computed twice - once for idx and again in the fprintf. This is debug code (non-WIN32 only), so the performance impact is negligible.

♻️ Optional: Reuse computed idx
     idx = map_hash(map, bkt->key);
-    fprintf(stderr, "@%zu hash=%zu key=%d base=%zu distance=%u\n", i,
-            map_hash(map, bkt->key), bkt->key, idx, bkt->psl);
+    fprintf(stderr, "@%zu hash=%zu key=%d base=%zu distance=%u\n", i,
+            idx, bkt->key, idx, bkt->psl);
deps/v8/src/logging/log.cc (1)

2306-2323: Minor: Static assert messages could be updated for accuracy.

The static_assert messages on lines 2317-2322 still reference "non-Linux platforms," but Darwin is now explicitly supported via the expanded guard. Consider updating to "non-Linux/Darwin platforms" for clarity.

📝 Suggested message update
 `#else`
   static_assert(
       !v8_flags.perf_prof.value(),
-      "--perf-prof should be statically disabled on non-Linux platforms");
+      "--perf-prof should be statically disabled on non-Linux/Darwin platforms");
   static_assert(
       !v8_flags.perf_basic_prof.value(),
-      "--perf-basic-prof should be statically disabled on non-Linux platforms");
+      "--perf-basic-prof should be statically disabled on non-Linux/Darwin platforms");
 `#endif`
glossary.md (1)

11-14: LGTM! Helpful additions to the glossary.

Both new entries are technically accurate and well-formatted. The Backport definition is particularly relevant for the Node.js LTS workflow.

Optional: Consider making the ASLR definition more specific

The current definition mentions "certain attacks" but could be more informative for readers:

-* **ASLR**: Address Space Layout Randomization. A security technique that randomizes memory addresses
-  to prevent certain attacks.
+* **ASLR**: Address Space Layout Randomization. A security technique that randomizes memory addresses
+  to prevent exploitation of memory corruption vulnerabilities.

This clarifies what type of attacks ASLR specifically mitigates, though the current definition is still correct.

deps/undici/src/docs/docs/best-practices/crawling.md (1)

11-33: Example format and code are clear and correct.

The user agent format example and JavaScript code are well-structured. The privacy guidance regarding role-based contacts is excellent.

Static analysis flagged two minor formatting issues that you may optionally address:

📝 Optional: Address linter hints

Line 13: Add a language identifier to the code fence for consistency:

-```
+```text
 AcmeCo Crawler - acme.co - contact@acme.co

**Line 17:** The bare URL warning for `crawler-team@company.com` is a false positive (it's an example email in prose, not a link), so you can safely ignore it or wrap it in backticks if preferred:

```diff
-Instead, use a role-based or organizational contact (e.g., crawler-team@company.com) to protect individual privacy while still enabling communication.
+Instead, use a role-based or organizational contact (e.g., `crawler-team@company.com`) to protect individual privacy while still enabling communication.
doc/api/util.md (2)

247-250: Improve clarity of the modifyPrototype option description.

The description "When false do not change the prototype of object while emitting the deprecation warning" could be more specific:

  1. Specify which object's prototype is being modified (e.g., "the returned wrapper function's prototype")
  2. Explain what prototype modification occurs by default when modifyPrototype is true
  3. Consider adding a usage example to demonstrate when and why users would set this to false

This will help users understand the practical implications of this option.

📝 Suggested documentation improvement

Consider revising to be more explicit:

 * `options` {Object}
-  * `modifyPrototype` {boolean} When false do not change the prototype of object
-    while emitting the deprecation warning.
+  * `modifyPrototype` {boolean} When `false`, the returned wrapper function's 
+    prototype will not be modified to match the deprecated function's prototype.
     **Default:** `true`.

And add an example after the existing examples (around line 297) demonstrating this option:

To deprecate a function without modifying its prototype:

\`\`\`mjs
import { deprecate } from 'node:util';

const oldFunc = () => { /* ... */ };
const newFunc = deprecate(oldFunc, 'Use newShinyFunc instead', 'DEP0XYZ', {
  modifyPrototype: false
});
\`\`\`

228-228: Add example demonstrating the options parameter and clarify how to use it when a deprecation code is not needed.

The documentation introduces the modifyPrototype option but provides no examples showing its usage. Since the function signature requires passing code before options, users wanting to use the option without a deprecation code must pass undefined for code, which should be clarified with an example:

import { deprecate } from 'node:util';

// Using options without a deprecation code
const fn = deprecate(myFunction, 'msg', undefined, { modifyPrototype: false });

// Or with a deprecation code
const fn = deprecate(myFunction, 'msg', 'DEP1234', { modifyPrototype: false });
lib/fs.js (1)

1803-1809: Consider wrapping callback before the permission check.

When callback is provided as the 4th argument (not inferred from type), it's used directly without being wrapped by makeCallback(). This follows the pre-existing behavior in this function, but for the new permission error path, it would be safer to ensure the callback is validated and runs in the proper context.

Suggested improvement
 function symlink(target, path, type, callback) {
   if (callback === undefined) {
     callback = makeCallback(type);
     type = undefined;
   } else {
     validateOneOf(type, 'type', ['dir', 'file', 'junction', null, undefined]);
+    callback = makeCallback(callback);
   }

   // Due to the nature of Node.js runtime, symlinks has different edge cases that can bypass
   // the permission model security guarantees. Thus, this API is disabled unless fs.read
   // and fs.write permission has been given.
   if (permission.isEnabled() && !permission.has('fs')) {
     callback(new ERR_ACCESS_DENIED('fs.symlink API requires full fs.read and fs.write permissions.'));
     return;
   }
deps/undici/src/lib/web/infra/index.js (1)

126-131: Consider using a clearer constant for the chunk size.

The expression (2 << 15) - 1 equals 65535, but the bit-shift notation is non-standard for this value. Typically (1 << 16) - 1 or simply 65535 would be more readable.

Suggested improvement
+const MAX_ARGS_LENGTH = 65535
+
 function isomorphicDecode (input) {
   const length = input.length
-  if ((2 << 15) - 1 > length) {
+  if (MAX_ARGS_LENGTH > length) {
     return String.fromCharCode.apply(null, input)
   }
   let result = ''
   let i = 0
-  let addition = (2 << 15) - 1
+  let addition = MAX_ARGS_LENGTH
   while (i < length) {
deps/undici/src/lib/web/fetch/formdata-parser.js (1)

274-276: Consider catching decodeURIComponent errors.

If the percent-encoded value in the extended attribute is malformed (e.g., %GG), decodeURIComponent will throw a URIError. This would propagate uncaught instead of being converted to a structured parsing error.

♻️ Proposed fix
     // Skip utf-8'' and decode the rest
-    value = decodeURIComponent(decoder.decode(headerValue.subarray(7)))
+    try {
+      value = decodeURIComponent(decoder.decode(headerValue.subarray(7)))
+    } catch {
+      throw parsingError('invalid percent-encoding in extended attribute')
+    }
deps/undici/src/lib/util/cache.js (1)

374-392: Header casing may cause deduplication key inconsistency.

Object.keys(cacheKey.headers).sort() performs a case-sensitive sort, so headers like "Accept" vs "accept" would produce different key orderings and values. Since makeCacheKey passes headers through without normalization, identical requests with differently-cased headers could generate different deduplication keys, causing missed deduplication opportunities.

Consider normalizing header keys to lowercase before sorting, or ensure all callers normalize headers before invoking this function.

♻️ Suggested fix
 function makeDeduplicationKey (cacheKey, excludeHeaders) {
   // Create a deterministic string key from the cache key
   // Include origin, method, path, and sorted headers
   let key = `${cacheKey.origin}:${cacheKey.method}:${cacheKey.path}`

   if (cacheKey.headers) {
-    const sortedHeaders = Object.keys(cacheKey.headers).sort()
+    const sortedHeaders = Object.keys(cacheKey.headers)
+      .map(h => h.toLowerCase())
+      .sort()
     for (const header of sortedHeaders) {
       // Skip excluded headers
-      if (excludeHeaders?.has(header.toLowerCase())) {
+      if (excludeHeaders?.has(header)) {
         continue
       }
-      const value = cacheKey.headers[header]
+      // Use case-insensitive header lookup
+      const originalKey = Object.keys(cacheKey.headers).find(k => k.toLowerCase() === header)
+      const value = cacheKey.headers[originalKey]
       key += `:${header}=${Array.isArray(value) ? value.join(',') : value}`
     }
   }

   return key
 }
deps/undici/src/lib/dispatcher/h2c-client.js (1)

18-19: Unused connect variable extracted from options.

The connect option is destructured but never used since the base Client class now handles connection building internally with useH2c: true. Consider omitting it from destructuring to avoid confusion:

-    const { connect, maxConcurrentStreams, pipelining, ...opts } =
-            clientOpts ?? {}
+    const { maxConcurrentStreams, pipelining, ...opts } =
+            clientOpts ?? {}

Alternatively, if connect should be passed to super, include it in opts.

deps/undici/src/lib/dispatcher/round-robin-pool.js (1)

78-84: TTL annotation overwrites existing properties on connect event.

Using Object.assign(target, { ttl: Date.now() }) works but could be clearer with direct property assignment:

-        Object.assign(target, { ttl: Date.now() })
+        target.ttl = Date.now()

This is a minor readability improvement.

deps/undici/src/lib/util/runtime-features.js (1)

35-38: Consider: Missing error handling for module loading.

detectRuntimeFeatureByExportedProperty calls lazyLoaders[moduleName]() directly without a try/catch. If the module is unavailable (unlikely for core modules like node:zlib and node:worker_threads), this would throw instead of returning false.

Since this is upstream undici code and these are Node.js core modules, this is likely acceptable, but worth noting for edge cases.

deps/undici/src/lib/handler/deduplication-handler.js (2)

147-161: Synthetic controller's aborted getter always returns false.

The waitingController object has get aborted() { return false } (line 151), so the check on lines 159-161 will never trigger. This appears intentional since the response is being replayed from a buffer (the original request already completed successfully), but the dead code could be confusing.

If this is intentional defensive coding for interface compliance, consider adding a brief comment. Otherwise, the abort checks can be removed.


179-181: Empty catch blocks are intentional but could benefit from a comment.

The empty catch blocks silently ignore errors from waiting handlers. This is correct behavior (one handler's failure shouldn't affect others), but the intent could be clearer.

📝 Suggested improvement
       } catch {
-        // Ignore errors from waiting handlers
+        // Ignore errors from waiting handlers - one handler's failure shouldn't affect others
       }

Also applies to: 206-208

deps/v8/src/objects/heap-object.h (1)

51-52: Nice utility API; consider documenting that this is the raw map-word slot.
A brief comment like “raw slot for map word (usable during GC / for barriers)” would help prevent accidental misuse.

Also applies to: 161-162

deps/v8/src/heap/free-list.cc (1)

35-48: PickNodeFromList() failure path now returns the canonical null sentinel.

Setting *node_size = 0 and returning Tagged<FreeSpace>() is consistent with callers that gate on is_null().

Possible consistency tweak

Consider using the same accessor family for sizing (size(kRelaxedLoad) vs Size()) in this method vs SearchForNodeInList() to reduce future layout surprises.

deps/v8/src/diagnostics/objects-debug.cc (1)

369-376: FreeSpace verifier is a good start; consider expanding invariants if not covered elsewhere.

If not already verified by Torque verifiers / other checks, it may be worth asserting basic sanity (e.g., non-negative size, alignment, and (if applicable) next structure).

deps/v8/src/heap/heap.cc (1)

6250-6258: Harden Heap::IsFreeSpaceValid() against null + size_t/int compare warnings

object is immediately dereferenced; adding a DCHECK_NOT_NULL(object) would make misuse fail fast in debug. Also consider normalizing types in the CHECK_LE to avoid size_t vs int/uint32_t comparison warnings (often -Werror in V8 builds).

Proposed tweak
 bool Heap::IsFreeSpaceValid(const FreeSpace* object) {
+  DCHECK_NOT_NULL(object);
   Heap* heap = HeapUtils::GetOwnerHeap(object);
   Tagged<Object> free_space_map =
       heap->isolate()->root(RootIndex::kFreeSpaceMap);
   CHECK(!heap->deserialization_complete() ||
         object->map_slot().contains_map_value(free_space_map.ptr()));
-  CHECK_LE(offsetof(FreeSpace, next_) + kTaggedSize,
-           object->size(kRelaxedLoad));
+  CHECK_LE(offsetof(FreeSpace, next_) + kTaggedSize,
+           static_cast<size_t>(object->size(kRelaxedLoad)));
   return true;
 }

Verification to run: ensure this matches upstream V8 API expectations for HeapUtils::GetOwnerHeap(...), FreeSpace::map_slot(), and the return type of FreeSpace::size(...) in this branch.

doc/contributing/writing-and-running-benchmarks.md (1)

598-600: Minor grammar: use "teardown" (one word) instead of "tear down".

"Teardown" as a noun is conventionally written as one word in technical contexts.

📝 Suggested fix
-    If tear down is necessary, register a listener for the `exit` event on
+    If teardown is necessary, register a listener for the `exit` event on
doc/api/http.md (1)

1188-1228: Example should consume the response via res.resume() (and ideally show 'error' handling).
The current “Do nothing” data handler works but trains a non-idiomatic pattern.

Proposed example tweak
   http.get('http://localhost:3000', { agent }, (res) => {
-    res.on('data', (data) => {
-      // Do nothing
-    });
+    res.resume(); // Consume data to free up memory
   });
 }, 5000); // Sending request on 5s interval so it's easy to hit idle timeout
deps/cares/src/lib/ares_getaddrinfo.c (1)

578-638: Nice deduplication; please confirm edge-case parsing behavior matches previous semantics.
numeric_service_to_port() centralizes validation well (errno, full-consume via *end == '\0', range check). The remaining question is whether inputs like "", " 80", or "+80" should be accepted/rejected (strtoul accepts leading whitespace and +).

Optional stricter parsing (only if desired)
 static ares_bool_t numeric_service_to_port(const char *service,
                                            unsigned short *port)
 {
   char *end;
   unsigned long val;

+  if (service == NULL || port == NULL || *service == '\0') {
+    return ARES_FALSE;
+  }
+
   errno = 0;
   val   = strtoul(service, &end, 10);

-  if (errno == 0 && *end == '\0' && val <= 65535) {
+  if (errno == 0 && end != service && *end == '\0' && val <= 65535UL) {
     *port = (unsigned short)val;
     return ARES_TRUE;
   }

If there are existing resolver/getaddrinfo tests in this repo, it’d be ideal to add/adjust one for the accepted numeric-service grammar (especially around whitespace and empty-string handling).

doc/api/module.md (1)

386-447: Fix a few grammar/wording nits to keep the docs crisp (and reduce ambiguity).
Notably: “a ECMAScript Module” → “an ECMAScript module”, “can not” → “cannot”.

Proposed doc tweak
- whenever Node.js compiles a CommonJS, a ECMAScript Module, or a TypeScript module, it will
+ whenever Node.js compiles a CommonJS module, an ECMAScript module, or a TypeScript module, it will
   use on-disk [V8 code cache][] persisted in the specified directory to speed up the compilation.
@@
-Compilation cache generated by one version of Node.js can not be reused by a different
+Compilation cache generated by one version of Node.js cannot be reused by a different
 version of Node.js. Cache generated by different versions of Node.js will be stored
.github/CODEOWNERS (1)

236-236: Use a recursive glob to cover nested devcontainer files.

The pattern /.devcontainer/* only matches files directly within .devcontainer/, but .devcontainer/base/devcontainer.json exists in a nested subdirectory and won't be covered by this pattern. Change to /.devcontainer/** to ensure the @nodejs/devcontainer team is pinged for all devcontainer-related changes, including nested files.

Suggested change
-/.devcontainer/* `@nodejs/devcontainer`
+/.devcontainer/** `@nodejs/devcontainer`
.devcontainer/base/devcontainer.json (1)

1-11: Consider pinning the devcontainer image version for reproducibility.

Using nodejs/devcontainer:nightly may cause inconsistent development environments as the image changes. Consider using a versioned tag or SHA digest if reproducible builds are important for the team.

The rest of the configuration looks appropriate - the volume mount for /out and the git restore-mtime post-create command are sensible choices for build caching and avoiding timestamp-based rebuilds.

doc/contributing/using-devcontainer.md (1)

50-50: Consider: "drop down" → "dropdown".

Proposed fix
-* Select the appropriate Dev Container configuration from the drop down. The base configuration in this
+* Select the appropriate Dev Container configuration from the dropdown. The base configuration in this
benchmark/fixtures/import-meta-dirname-and-filename.mjs (1)

1-1: Consider exporting the value directly to avoid extra per-iteration work in the benchmark.

Right now each default() call allocates a new array; if you want the benchmark to focus on import.meta.* access, prefer a constant export (and adjust the benchmark accordingly).

benchmark/esm/import-meta.js (1)

17-23: Avoid serial dynamic imports (optional), and consider pre-sizing the array.

This is setup work (not timed), but await import() in a loop makes the benchmark startup significantly slower for larger n.

Proposed tweak (parallelize imports)
 async function load(n, fixtureFileURL) {
-  const array = [];
-  for (let i = 0; i < n; i++) {
-    array[i] = await import(`${fixtureFileURL}?i=${i}`);
-  }
-  return array;
+  const imports = new Array(n);
+  for (let i = 0; i < n; i++) {
+    imports[i] = import(`${fixtureFileURL}?i=${i}`);
+  }
+  return Promise.all(imports);
 }
deps/nghttp2/lib/nghttp2_session.c (1)

3386-3398: Add a GOAWAY reason for glitch-limiter termination (debuggability).
Right now termination is NGHTTP2_ENHANCE_YOUR_CALM with no reason string, which makes it hard to attribute disconnects in the field.

Proposed change
-  return nghttp2_session_terminate_session(session, NGHTTP2_ENHANCE_YOUR_CALM);
+  return nghttp2_session_terminate_session_with_reason(
+    session, NGHTTP2_ENHANCE_YOUR_CALM, "glitch rate limit exceeded");
deps/v8/src/regexp/regexp-compiler.cc (2)

353-366: Guard against inverted register ranges when collecting affected registers
for (int i = action->register_from(); i <= to; i++) assumes register_to() >= register_from(). A defensive DCHECK_GE(to, action->register_from()) would make failures clearer if a new ActionNode type accidentally violates the invariant.


3205-3256: Flags reset strategy is good; consider restoring entry flags before returning
Capturing RegExpFlags flags = compiler->flags(); (Line 3226) and resetting per alternative (Lines 3241, 3359) is solid. One small safety improvement: restore compiler->set_flags(flags); just before returning from ChoiceNode::Emit, so outer emitters don’t observe a flags value modified by the last-emitted alternative.

deps/v8/src/regexp/regexp-compiler.h (1)

321-324: set_flush_budget should defensively clamp in release builds
DCHECK(to <= UINT16_MAX) won’t prevent truncation in non-debug builds. If callers can ever pass larger values, prefer to = std::min(to, int{UINT16_MAX});.

Comment on lines 25 to 52
function main({ n, valuesToRead }) {
const array = [];
for (let i = 0; i < n; ++i) {
array.push({ dirname: '', filename: '', i: 0 });
}
const fixtureDir = path.resolve(__filename, '../../fixtures');
const fixtureFile = path.join(fixtureDir, `import-meta-${valuesToRead}.mjs`);
const fixtureFileURL = pathToFileURL(fixtureFile);

bench.start();
load(array, n, valuesToRead).then((arr) => {
load(n, fixtureFileURL).then((array) => {
const results = new Array(n);
bench.start();
for (let i = 0; i < n; i++) {
results[i] = array[i].default();
}
bench.end(n);
if (valuesToRead.includes('dirname')) assert.strictEqual(arr[n - 1].dirname, fixtureDir);
if (valuesToRead.includes('filename')) assert.strictEqual(arr[n - 1].filename, path.join(fixtureDir, `import-meta-${valuesToRead}.mjs`));

switch (valuesToRead) {
case 'dirname-and-filename':
assert.deepStrictEqual(results[n - 1], [fixtureDir, fixtureFile]);
break;
case 'dirname':
assert.strictEqual(results[n - 1], fixtureDir);
break;
case 'filename':
assert.strictEqual(results[n - 1], fixtureFile);
break;
case 'url':
assert.strictEqual(results[n - 1], `${fixtureFileURL}?i=${n - 1}`);
break;
}
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and see the actual code context
cat -n benchmark/esm/import-meta.js | head -60

Repository: nodesource/nsolid

Length of output: 1813


🏁 Script executed:

# Check if __dirname is used elsewhere in ESM benchmarks
fd '\.mjs$|\.js$' benchmark/esm --type f -x grep -l "__dirname" {} +

Repository: nodesource/nsolid

Length of output: 340


🏁 Script executed:

# Check if fixtures directory structure matches the path resolution
find benchmark -type d -name 'fixtures' 2>/dev/null | head -20

Repository: nodesource/nsolid

Length of output: 79


🏁 Script executed:

# Look for other benchmarks using path.resolve with __filename
rg "path\.resolve\(__filename" benchmark/

Repository: nodesource/nsolid

Length of output: 154


🏁 Script executed:

# Check how load() is defined and if it handles errors in similar benchmarks
rg -A 5 "function load\(" benchmark/esm/import-meta.js

Repository: nodesource/nsolid

Length of output: 230


🏁 Script executed:

# Check if fixtures directory exists at repo root
find . -maxdepth 2 -type d -name 'fixtures' 2>/dev/null

Repository: nodesource/nsolid

Length of output: 97


🏁 Script executed:

# Check other benchmarks for .then() error handling patterns
rg "\.then\(" benchmark/ -A 2 | head -40

Repository: nodesource/nsolid

Length of output: 1907


🏁 Script executed:

# Verify the fixture files referenced actually exist
ls -la benchmark/fixtures/import-meta-*.mjs 2>/dev/null || echo "Fixture files not found at benchmark/fixtures/"

Repository: nodesource/nsolid

Length of output: 430


🏁 Script executed:

# Check if there's a root fixtures directory with these files
ls -la fixtures/import-meta-*.mjs 2>/dev/null || echo "No fixtures at repo root"

Repository: nodesource/nsolid

Length of output: 85


Use __dirname and add error handling to prevent silent benchmark failures.

  • Line 26: path.resolve(__filename, '../../fixtures') incorrectly resolves to the repo root instead of benchmark/fixtures/. Use __dirname with ../fixtures to reach the correct directory.
  • Line 30: Unhandled promise rejection on import failure. Add .catch((err) => { throw err; }) to propagate errors instead of silently failing.
Proposed fix
 function main({ n, valuesToRead }) {
-  const fixtureDir = path.resolve(__filename, '../../fixtures');
+  const fixtureDir = path.resolve(__dirname, '../fixtures');
   const fixtureFile = path.join(fixtureDir, `import-meta-${valuesToRead}.mjs`);
   const fixtureFileURL = pathToFileURL(fixtureFile);

-  load(n, fixtureFileURL).then((array) => {
+  load(n, fixtureFileURL).then((array) => {
     const results = new Array(n);
     bench.start();
     for (let i = 0; i < n; i++) {
       results[i] = array[i].default();
     }
     bench.end(n);

     switch (valuesToRead) {
       case 'dirname-and-filename':
         assert.deepStrictEqual(results[n - 1], [fixtureDir, fixtureFile]);
         break;
       case 'dirname':
         assert.strictEqual(results[n - 1], fixtureDir);
         break;
       case 'filename':
         assert.strictEqual(results[n - 1], fixtureFile);
         break;
       case 'url':
         assert.strictEqual(results[n - 1], `${fixtureFileURL}?i=${n - 1}`);
         break;
     }
-  });
+  }).catch((err) => { throw err; });
 }
🤖 Prompt for AI Agents
In `@benchmark/esm/import-meta.js` around lines 25 - 52, In main(), change how
fixtureDir is resolved: replace path.resolve(__filename, '../../fixtures') with
path.resolve(__dirname, '../fixtures') (or use __dirname + '/.. /fixtures') so
fixtureDir points to benchmark/fixtures and fixtureFile/fixtureFileURL use that
correct dir; also handle import errors from load(...) by appending a .catch(err
=> { throw err; }) (or otherwise rethrow/log and process.exit) after the
.then(...) to ensure promise rejections propagate instead of silently failing;
reference the main function, variables fixtureDir, fixtureFileURL, and the
load(...) call when applying the changes.

Comment on lines +29 to +45
static napi_value global_names[20];
static napi_value global_values[20];
static bool global_properties_initialized = false;

// Creating with many options because complains are when ~20 properties
static void InitializeTestProperties(napi_env env) {
if (global_properties_initialized) return;

for (int i = 0; i < 20; i++) {
std::string name = "foo" + std::to_string(i);
napi_create_string_utf8(
env, name.c_str(), NAPI_AUTO_LENGTH, &global_names[i]);
napi_create_string_utf8(
env, name.c_str(), NAPI_AUTO_LENGTH, &global_values[i]);
}
global_properties_initialized = true;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Global napi_value handles may become stale across benchmark iterations.

napi_value handles are scoped to the current callback invocation and may be garbage collected between calls. Storing them in globals means subsequent benchmark runs could use invalid handles, causing undefined behavior or crashes.

Consider one of these approaches:

  1. Use napi_create_reference to prevent GC of the values
  2. Re-initialize properties on each call (acceptable overhead for benchmarks since it's outside the timed section)
  3. Create a persistent reference that you retrieve on each call
🔧 Suggested fix using napi_ref for persistent storage
-static napi_value global_names[20];
-static napi_value global_values[20];
-static bool global_properties_initialized = false;
+static napi_ref global_names_refs[20];
+static napi_ref global_values_refs[20];
+static bool global_properties_initialized = false;

 // Creating with many options because complains are when ~20 properties
-static void InitializeTestProperties(napi_env env) {
+static void InitializeTestProperties(napi_env env,
+                                     napi_value* names,
+                                     napi_value* values) {
   if (global_properties_initialized) return;

   for (int i = 0; i < 20; i++) {
     std::string name = "foo" + std::to_string(i);
+    napi_value name_val, value_val;
     napi_create_string_utf8(
-        env, name.c_str(), NAPI_AUTO_LENGTH, &global_names[i]);
+        env, name.c_str(), NAPI_AUTO_LENGTH, &name_val);
     napi_create_string_utf8(
-        env, name.c_str(), NAPI_AUTO_LENGTH, &global_values[i]);
+        env, name.c_str(), NAPI_AUTO_LENGTH, &value_val);
+    napi_create_reference(env, name_val, 1, &global_names_refs[i]);
+    napi_create_reference(env, value_val, 1, &global_values_refs[i]);
   }
   global_properties_initialized = true;
+
+  // Retrieve values for this call
+  for (int i = 0; i < 20; i++) {
+    napi_get_reference_value(env, global_names_refs[i], &names[i]);
+    napi_get_reference_value(env, global_values_refs[i], &values[i]);
+  }
 }

Comment on lines +607 to +617
void ares_set_query_enqueue_cb(ares_channel_t *channel,
ares_query_enqueue_cb callback,
void *user_data)
{
if (channel == NULL) {
return;
}

channel->query_enqueue_cb = callback;
channel->query_enqueue_cb_data = user_data;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make ares_set_query_enqueue_cb thread-safe (missing channel lock).

Other setters in this file lock the channel; this one should too.

Proposed fix
 void ares_set_query_enqueue_cb(ares_channel_t       *channel,
                                ares_query_enqueue_cb callback,
                                void                 *user_data)
 {
   if (channel == NULL) {
     return;
   }

-  channel->query_enqueue_cb      = callback;
-  channel->query_enqueue_cb_data = user_data;
+  ares_channel_lock(channel);
+  channel->query_enqueue_cb      = callback;
+  channel->query_enqueue_cb_data = user_data;
+  ares_channel_unlock(channel);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void ares_set_query_enqueue_cb(ares_channel_t *channel,
ares_query_enqueue_cb callback,
void *user_data)
{
if (channel == NULL) {
return;
}
channel->query_enqueue_cb = callback;
channel->query_enqueue_cb_data = user_data;
}
void ares_set_query_enqueue_cb(ares_channel_t *channel,
ares_query_enqueue_cb callback,
void *user_data)
{
if (channel == NULL) {
return;
}
ares_channel_lock(channel);
channel->query_enqueue_cb = callback;
channel->query_enqueue_cb_data = user_data;
ares_channel_unlock(channel);
}
🤖 Prompt for AI Agents
In `@deps/cares/src/lib/ares_init.c` around lines 607 - 617, The setter
ares_set_query_enqueue_cb currently updates channel->query_enqueue_cb and
channel->query_enqueue_cb_data without holding the channel lock; make it
thread-safe by acquiring the channel lock used elsewhere in this file before
assigning those fields and releasing it afterward (follow the same lock/unlock
calls used by other setters in this file), while keeping the early return when
channel == NULL.

Comment on lines +115 to +118
len = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, NULL, NULL);
if (len == 0) {
return ARES_FALSE;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Memory leak: val is not freed when WideCharToMultiByte fails.

If WideCharToMultiByte returns 0 on line 115, the function returns ARES_FALSE without freeing the val buffer allocated on line 102.

🐛 Proposed fix
   /* Convert to UTF8 */
   len = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, NULL, NULL);
   if (len == 0) {
+    ares_free(val);
     return ARES_FALSE;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
len = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, NULL, NULL);
if (len == 0) {
return ARES_FALSE;
}
len = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, NULL, NULL);
if (len == 0) {
ares_free(val);
return ARES_FALSE;
}
🤖 Prompt for AI Agents
In `@deps/cares/src/lib/ares_sysconfig_win.c` around lines 115 - 118, The early
return when WideCharToMultiByte returns 0 leaks the buffer pointed to by val;
before returning ARES_FALSE you must free val using the same allocator used at
its allocation (e.g., free(val) or ares_free(val) depending on how val was
allocated), and then return ARES_FALSE; ensure any other early-return paths in
the function also free val to avoid similar leaks.

Comment on lines +24 to +26
set (hostname, records) {
this.#records.set(hostname, records)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Signature mismatch: set ignores the options parameter.

The DNSStorage.set method accepts only (hostname, records), but it's called at line 275 with a third { ttl: minTTL } argument. The TypeScript definition in interceptors.d.ts (line 26) expects set(origin, records, options: { ttl: number }).

This means the ttl option—intended for external storage implementations—is silently ignored by the built-in storage. Update the signature to accept the options parameter for consistency with the TypeScript contract.

🔧 Proposed fix
-  set (hostname, records) {
+  set (hostname, records, options) {
     this.#records.set(hostname, records)
   }

Even if the built-in storage doesn't use ttl, accepting the parameter ensures signature compatibility with external implementations and the TypeScript types.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
set (hostname, records) {
this.#records.set(hostname, records)
}
set (hostname, records, options) {
this.#records.set(hostname, records)
}
🤖 Prompt for AI Agents
In `@deps/undici/src/lib/interceptor/dns.js` around lines 24 - 26, Update the
DNSStorage.set signature to accept the third options parameter (e.g.,
set(hostname, records, options)) so it matches the TypeScript contract and
callers that pass { ttl }. Modify the implementation of DNSStorage.set to
include the options parameter (even if unused) and forward or ignore it safely,
and update any internal references to call sites like the call at line where set
is invoked with { ttl: minTTL } to ensure no parameter is dropped; keep the
existing behavior of storing hostname/records in this.#records while matching
the declared function signature in interceptors.d.ts.

Comment thread doc/api/packages.md
Comment on lines +1164 to 1179
[TypeScript]: typescript.md
[WebAssembly modules]: esm.md#wasm-modules
[WinterCG]: https://wintercg.org/
[`"exports"`]: #exports
[`"imports"`]: #imports
[`"main"`]: #main
[`"name"`]: #name
[`"type"`]: #type
[`--conditions` / `-C` flag]: #resolving-user-conditions
[`--experimental-addon-modules`]: cli.md#--experimental-addon-modules
[`--no-addons` flag]: cli.md#--no-addons
[`ERR_PACKAGE_PATH_NOT_EXPORTED`]: errors.md#err_package_path_not_exported
[`ERR_UNKNOWN_FILE_EXTENSION`]: errors.md#err_unknown_file_extension
[`package.json`]: #nodejs-packagejson-field-definitions
[customization hooks]: module.md#customization-hooks
[entry points]: #package-entry-points
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the referenced doc files exist and anchors are present somewhere in-file
set -euo pipefail

echo "=== Checking file existence ==="
for f in doc/api/typescript.md doc/api/esm.md doc/api/module.md doc/api/errors.md; do
  if test -f "$f"; then
    echo "$f exists"
  else
    echo "$f missing"
  fi
done

echo -e "\n=== Checking anchors ==="
echo "Checking wasm-modules in doc/api/esm.md:"
rg -n "wasm-modules" doc/api/esm.md || echo "  (not found)"

echo -e "\nChecking customization-hooks in doc/api/module.md:"
rg -n "customization.hooks|customization-hooks" doc/api/module.md || echo "  (not found)"

echo -e "\nChecking err_unknown_file_extension in doc/api/errors.md:"
rg -n "err_unknown_file_extension" doc/api/errors.md -i || echo "  (not found)"

echo -e "\nChecking err_package_path_not_exported in doc/api/errors.md:"
rg -n "err_package_path_not_exported" doc/api/errors.md -i || echo "  (not found)"

Repository: nodesource/nsolid

Length of output: 1207


🏁 Script executed:

#!/bin/bash
# Get context around the anchor references to verify they are properly defined

echo "=== Context around wasm-modules in esm.md (line 715) ==="
sed -n '710,720p' doc/api/esm.md

echo -e "\n=== Context around customization-hooks in module.md (line 1815) ==="
sed -n '1810,1825p' doc/api/module.md

echo -e "\n=== Check for wasm-modules anchor ID specifically ==="
rg -n 'id=".*wasm' doc/api/esm.md || echo "  (not found)"

echo -e "\n=== Check for customization-hooks anchor ID in module.md ==="
rg -n 'id=".*customization' doc/api/module.md || echo "  (not found)"

echo -e "\n=== Check reference link definitions in module.md ==="
rg -n '\[customization hooks\]' doc/api/module.md

Repository: nodesource/nsolid

Length of output: 1524


🏁 Script executed:

#!/bin/bash
# Check if HTML anchors are case-insensitive by examining both the anchor and link references

echo "=== Full context for ERR_UNKNOWN_FILE_EXTENSION anchor ==="
sed -n '3173,3180p' doc/api/errors.md

echo -e "\n=== Looking for the link reference format in packages.md ==="
rg -n "ERR_UNKNOWN_FILE_EXTENSION|err_unknown_file_extension" doc/api/packages.md

echo -e "\n=== Summary of anchor ID formats found ==="
echo "ESM file uses: esm_experimental_wasm_modules (line 707)"
echo "Module file uses: module_customization_hooks (line 581)"
echo "Expected by links: wasm-modules and customization-hooks"

Repository: nodesource/nsolid

Length of output: 779


Fix anchor references for WebAssembly modules and customization hooks links.

All referenced files exist, but two cross-reference anchors are broken:

  • [WebAssembly modules]: esm.md#wasm-modules targets #wasm-modules, but the actual anchor ID in esm.md (line 707) is esm_experimental_wasm_modules
  • [customization hooks]: module.md#customization-hooks targets #customization-hooks, but the actual anchor ID in module.md (line 581) is module_customization_hooks

Update the link definitions to reference the correct anchor IDs. The error code links use case-insensitive HTML anchors (ERR_UNKNOWN_FILE_EXTENSION vs err_unknown_file_extension) which function but are not exact matches.

🤖 Prompt for AI Agents
In `@doc/api/packages.md` around lines 1164 - 1179, Update the two broken Markdown
link definitions so they point to the actual anchor IDs: change the WebAssembly
modules reference from esm.md#wasm-modules to
esm.md#esm_experimental_wasm_modules and change customization hooks from
module.md#customization-hooks to module.md#module_customization_hooks; leave the
error-code links as-is (their case-insensitive anchors work) and ensure you
update the entries in the same link-definition block that contains symbols like
[`"exports"`], [`"imports"`], and [entry points].

Comment thread doc/api/worker_threads.md
Comment on lines 1833 to +1834
An object that can be used to query performance information from a worker
instance. Similar to [`perf_hooks.performance`][].
instance.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Restore the complete description for worker.performance.

The description for worker.performance has been truncated to just "instance." which is incomplete and uninformative. The original description provided useful context:

"An object that can be used to query performance information from a worker instance. Similar to perf_hooks.performance."

Please restore the complete description or provide an equivalent full description of this property.

📝 Suggested fix
 An object that can be used to query performance information from a worker
-instance.
+instance. Similar to [`perf_hooks.performance`][].

Note: You may also need to verify whether the reference link [perf_hooks.performance][] should be restored at the end of the file if it was removed.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
An object that can be used to query performance information from a worker
instance. Similar to [`perf_hooks.performance`][].
instance.
An object that can be used to query performance information from a worker
instance. Similar to [`perf_hooks.performance`][].
🤖 Prompt for AI Agents
In `@doc/api/worker_threads.md` around lines 1833 - 1834, Restore the full
description for the worker.performance property by replacing the truncated
sentence with a complete sentence such as: "An object that can be used to query
performance information from a worker instance. Similar to
perf_hooks.performance." Ensure the reference link for `perf_hooks.performance`
(the `[perf_hooks.performance][]` anchor) is re-added at the end of the document
if it was removed so the inline reference resolves correctly; update the
`worker.performance` documentation block to include the restored text and the
reference link.

Comment thread lib/fs.js
Comment on lines 1246 to 1255
function fdatasync(fd, callback) {
const req = new FSReqCallback();
req.oncomplete = makeCallback(callback);

if (permission.isEnabled()) {
callback(new ERR_ACCESS_DENIED('fdatasync API is disabled when Permission Model is enabled.'));
return;
}
binding.fdatasync(fd, req);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Bug: Permission check uses raw callback instead of the wrapped callback.

The callback is wrapped at line 1248 (req.oncomplete = makeCallback(callback)), but the permission denial error path at line 1251 uses the raw callback. This is inconsistent with other permission-gated APIs like fchmod, fchown, and futimes which wrap the callback first and then use it consistently.

makeCallback() validates the callback is a function and ensures it runs in the proper context. Using the raw callback bypasses these guarantees.

Proposed fix
 function fdatasync(fd, callback) {
+  callback = makeCallback(callback);
+
+  if (permission.isEnabled()) {
+    callback(new ERR_ACCESS_DENIED('fdatasync API is disabled when Permission Model is enabled.'));
+    return;
+  }
+
   const req = new FSReqCallback();
-  req.oncomplete = makeCallback(callback);
-
-  if (permission.isEnabled()) {
-    callback(new ERR_ACCESS_DENIED('fdatasync API is disabled when Permission Model is enabled.'));
-    return;
-  }
+  req.oncomplete = callback;
   binding.fdatasync(fd, req);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function fdatasync(fd, callback) {
const req = new FSReqCallback();
req.oncomplete = makeCallback(callback);
if (permission.isEnabled()) {
callback(new ERR_ACCESS_DENIED('fdatasync API is disabled when Permission Model is enabled.'));
return;
}
binding.fdatasync(fd, req);
}
function fdatasync(fd, callback) {
callback = makeCallback(callback);
if (permission.isEnabled()) {
callback(new ERR_ACCESS_DENIED('fdatasync API is disabled when Permission Model is enabled.'));
return;
}
const req = new FSReqCallback();
req.oncomplete = callback;
binding.fdatasync(fd, req);
}
🤖 Prompt for AI Agents
In `@lib/fs.js` around lines 1246 - 1255, The permission-denied path uses the raw
callback instead of the wrapped one; set req.oncomplete = makeCallback(callback)
first (already done) and invoke that wrapped callback with the error instead of
calling callback directly — i.e., replace callback(new ERR_ACCESS_DENIED(...))
with req.oncomplete(new ERR_ACCESS_DENIED('fdatasync API is disabled when
Permission Model is enabled.')); keep the early return.

Comment thread lib/fs.js
Comment on lines 1278 to 1286
function fsync(fd, callback) {
const req = new FSReqCallback();
req.oncomplete = makeCallback(callback);
if (permission.isEnabled()) {
callback(new ERR_ACCESS_DENIED('fsync API is disabled when Permission Model is enabled.'));
return;
}
binding.fsync(fd, req);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Bug: Same issue as fdatasync - permission check uses raw callback.

The callback is wrapped at line 1280 but the error path at line 1282 uses the raw callback.

Proposed fix
 function fsync(fd, callback) {
+  callback = makeCallback(callback);
+
+  if (permission.isEnabled()) {
+    callback(new ERR_ACCESS_DENIED('fsync API is disabled when Permission Model is enabled.'));
+    return;
+  }
+
   const req = new FSReqCallback();
-  req.oncomplete = makeCallback(callback);
-  if (permission.isEnabled()) {
-    callback(new ERR_ACCESS_DENIED('fsync API is disabled when Permission Model is enabled.'));
-    return;
-  }
+  req.oncomplete = callback;
   binding.fsync(fd, req);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function fsync(fd, callback) {
const req = new FSReqCallback();
req.oncomplete = makeCallback(callback);
if (permission.isEnabled()) {
callback(new ERR_ACCESS_DENIED('fsync API is disabled when Permission Model is enabled.'));
return;
}
binding.fsync(fd, req);
}
function fsync(fd, callback) {
callback = makeCallback(callback);
if (permission.isEnabled()) {
callback(new ERR_ACCESS_DENIED('fsync API is disabled when Permission Model is enabled.'));
return;
}
const req = new FSReqCallback();
req.oncomplete = callback;
binding.fsync(fd, req);
}
🤖 Prompt for AI Agents
In `@lib/fs.js` around lines 1278 - 1286, The fsync function sets req.oncomplete =
makeCallback(callback) but calls the raw callback on the permission-denied path;
change the error path to invoke the wrapped callback (i.e., use req.oncomplete
or call makeCallback(callback) result) so the callback is always the wrapped
version—update the permission check in fsync to call req.oncomplete(new
ERR_ACCESS_DENIED(...)) or assign and call the wrapped callback instead of
calling the original callback directly (refer to fsync, FSReqCallback,
makeCallback, permission.isEnabled, ERR_ACCESS_DENIED, binding.fsync).

Don't set `OtlpGrpcClientOptions.use_ssl_credentials` when also setting
`OtlpGrpcClientOptions.credentials`.
Specifically in `EnvInst::CustomCommandReqWeakCallback()` when trying to
access `EnvInst` associated with the `Isolate`. Observed when
load-testing the `test/addons/nsolid-custom-command` test.
@santigimeno santigimeno force-pushed the node-v24.13.0-nsolid-v6.2.0-release branch from 61f223c to 5554e72 Compare January 14, 2026 16:34
@santigimeno santigimeno merged commit 5554e72 into node-v24.x-nsolid-v6.x Jan 16, 2026
13 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.