Skip to content

worker: populate BroadcastChannel MessageEvent source#64334

Open
SudhansuBandha wants to merge 38 commits into
nodejs:mainfrom
SudhansuBandha:update-broadcast-channel-source
Open

worker: populate BroadcastChannel MessageEvent source#64334
SudhansuBandha wants to merge 38 commits into
nodejs:mainfrom
SudhansuBandha:update-broadcast-channel-source

Conversation

@SudhansuBandha

Copy link
Copy Markdown
Contributor

Populate the MessageEvent source property with the sender's worker thread ID for BroadcastChannel messages originating from worker threads.

Fixes: #59053

@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. worker Issues and PRs related to Worker support. labels Jul 7, 2026
Populate the MessageEvent source property with the sender's
worker thread ID for BroadcastChannel messages
originating from worker threads.

Fixes: nodejs#59053
Signed-off-by: Sudhansu Bandha <bandhasudhansu@gmail.com>
@SudhansuBandha SudhansuBandha force-pushed the update-broadcast-channel-source branch from 8a9de03 to 98aaa6a Compare July 7, 2026 02:37
@jdmarshall

jdmarshall commented Jul 7, 2026

Copy link
Copy Markdown

In the MDN documentation, https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/source

The source read-only property of the MessageEvent interface is a MessageEventSource (which can be a WindowProxy, MessagePort, or ServiceWorker object) representing the message emitter.

The threadId might be sufficient to work with the new API you folks were working on but I'm wondering if there's a technical limitation that makes diverging from the web api an absolute necessity? Ideally this would be the Worker Object, since one could immediately invoke postMessage() for any rendezvous coordination necessitated by the broadcast. With that in mind a MessagePort would also work if that's available, but I'm guessing that is not...

@jasnell jasnell left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a breaking change making this a semver-major. It will need doc updates as well. I think we should instead try to find a way of doing this so that it's not a breaking change

Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: nodejs#64134
Reviewed-By: James M Snell <jasnell@gmail.com>
@SudhansuBandha

Copy link
Copy Markdown
Contributor Author

Thanks for the review, @jasnell. I agree that changing MessageEvent.source makes this a semver-major change. Do you have any particular approach in mind for exposing the sender information while preserving the existing semantics of MessageEvent.source? I'd like to make sure I'm exploring all feasible directions that best align with Node's API design.

If you are only sending datagrams and so streams,
your datagrams could stall.
There were two reasons:
i. A SendPendingDataScope in SendDatagrams was
missing.
ii. SendPendingData did not attempt to send
datagrams, if there were no stream data.

Signed-off-by: Marten Richter <marten.richter@freenet.de>
PR-URL: nodejs#64303
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
@jdmarshall

jdmarshall commented Jul 7, 2026

Copy link
Copy Markdown

@jasnell Source currently resolves to null. Why would this a breaking change when there is nobody in the forest to hear the tree fall?

mcollina and others added 19 commits July 7, 2026 09:38
for await / reader.read() loops over byte streams were ~4x slower than
over default streams. Three per-chunk costs, none required by the spec:

- ArrayBufferViewGetBuffer/ByteLength/ByteOffset went through
  ReflectGet(view.constructor.prototype, ...), a reflective get that is
  ~3.5x slower than the original prototype getters from primordials and
  spoofable through a user-defined .constructor to boot.

- The buffered fast paths in ReadableStreamDefaultReader.read() and the
  async iterator only covered default controllers, so byte streams with
  queued data still allocated a read request and PromiseWithResolvers
  per chunk. Byte-queue dequeue is fully synchronous (it is the
  queue-filled arm of the byte controller's pull steps), so both fast
  paths now resolve directly from the byte queue.

- readableByteStreamControllerEnqueue re-ran the reader brand check and
  re-loaded the read request list four times per chunk across
  HasDefaultReader / ProcessReadRequestsUsingQueue / GetNumReadRequests
  / FulfillReadRequest; it now does a single pass. The async iterator
  also reuses its read request object across reads (at most one is ever
  in flight).

benchmark/webstreams interleaved same-day A/B, --runs 10:
readable-async-iterator bytes +16.3% (***), readable-read byob +9.1%
(***), all other rows neutral. Profiler harness: parked byte iteration
+14%, buffered byte iteration +37%, buffered byte read loop +18%,
default-stream rows at parity. WPT streams/compression/encoding
subtests identical to baseline.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: nodejs#64291
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: nodejs#64291
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
The depth of the stack depends not only on the stack size, but
also on the size of each stack frame, which in turn depends on
which tier the recursive function happens to be running at when
the overflow occurs. Under load the background tier-up can land
at a non-deterministic point in the recursion and flake the test.
Keep the recursive function in the interpreter with
%NeverOptimizeFunction() so the frame size - and thus the depth
- is deterministic.

Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com>
PR-URL: nodejs#64271
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
When a test  uses 'pipe' for the stdio but the child process crashes,
the stream will be null. In this case, don't try to stringify it and
instead log an empty string.

Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com>
PR-URL: nodejs#64273
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Signed-off-by: Guilherme Araújo <arauujogui@gmail.com>
PR-URL: nodejs#64219
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Signed-off-by: Efe Karasakal <hi@efe.dev>
PR-URL: nodejs#64158
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Cut several sources of per-stream/per-request overhead on the hot
path:

- Track 'priority'/'frameError' stream listeners by overriding the
  EventEmitter methods on Http2Stream instead of subscribing to
  'newListener'/'removeListener', which made every listener add and
  remove on every stream emit an extra tracking event.
- Replace the per-call SafeSet and sensitive-header mapping in
  buildNgHeaderString with a lazily allocated array and an
  empty-array fast path, and skip the HTTP token regex and
  connection-specific header checks for well-known single-value
  header names.
- Replace per-call closures with shared named handlers in
  onStreamClose, afterShutdown and Http2Stream._destroy.
- Skip the pendingStreams Set add/delete for streams that are
  created with their native handle already available (all server
  streams).
- Hoist the per-request onStreamTimeout closure factories in the
  compat layer to module-level handlers, and avoid a once() wrapper
  allocation per server stream.

h2load, 1 KiB response payload, -c 4 -m 100, mean of 6 alternating
runs: core API 60.2k -> 69.3k req/s (+15%), compat API 43.6k ->
46.2k req/s (+5.9%).

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: nodejs#64265
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Tim Perry <pimterry@gmail.com>
The compat layer always responded with waitForTrailers set, so every
response paid for a wantTrailers C++ -> JS callback, an empty
sendTrailers() submission scheduled through setImmediate(), and an
extra empty DATA frame on the wire, even though the vast majority of
responses never register any trailers.

When the headers are flushed as part of response.end() and no
trailers have been registered, there is no further opportunity to
add trailers, so waitForTrailers can be skipped altogether. Headers
flushed early (writeHead, write, flushHeaders) keep the previous
behavior so trailers can still be added while streaming.

Trailers added after response.end() are now silently dropped,
matching the HTTP/1 response.addTrailers() semantics.

Also reuse a shared options object for Http2ServerRequest instances
created without explicit options.

h2load, 1 KiB response payload, -c 4 -m 100, mean of 6 alternating
runs: compat API 43.1k -> 49.9k req/s (+15.7% cumulative vs main).

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: nodejs#64265
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Tim Perry <pimterry@gmail.com>
Every _write()/_writev() on an Http2Stream allocated four closures
and an anonymous nextTick callback to coordinate the write callback
with the end-of-stream check. Since the stream machinery dispatches
at most one write at a time, that coordination state can live on the
stream's kState object instead, with shared named functions for the
end check and completion logic.

When trailers are pending the writable side cannot be shut down
early anyway, so the end-of-stream check tick is now skipped
entirely for those writes.

Also pre-initialize the kState fields that used to be added
dynamically (shutdownWritableCalled, fd) so hot-path stores no
longer transition the object shape.

h2load, 1 KiB response payload, -c 4 -m 100, mean of 6 alternating
runs vs main: core API 61.0k -> 70.7k req/s (+15.9% cumulative),
compat API 43.7k -> 50.4k req/s (+15.3% cumulative).

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: nodejs#64265
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Tim Perry <pimterry@gmail.com>
When the compat layer flushes response headers before the response
is ended (writeHead(), write(), flushHeaders()), it must keep
waitForTrailers so that trailers can still be added while streaming.
As a result, every such response paid for a wantTrailers C++ -> JS
callback, an empty sendTrailers() with its setImmediate(), and a
trailers() call back into C++, even though most responses never
register any trailers.

Introduce STREAM_OPTION_AUTO_EMPTY_TRAILERS: when set and no
trailers have been handed to the native side by the time the final
DATA frame is sent, the stream is finished directly in C++ with the
same empty DATA frame carrying END_STREAM that the JS path would
have produced, without calling into JS at all. The compat layer
enables this mode whenever it responds with waitForTrailers and no
trailers registered yet; a later setTrailer() call flips the stream
back to JS-managed trailers through a new disableAutoTrailers()
binding, so streaming trailers keep working unchanged.

The wire format is identical in all cases.

h2load -c 4 -m 100, 1 KiB payload, mean of 8 alternating runs
against the previous commit: compat writeHead()+end() 47.8k -> 50.2k
req/s (+5.0%); multi-write streaming responses +1%.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: nodejs#64265
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Tim Perry <pimterry@gmail.com>
Two per-request scheduling eliminations:

- The end-of-stream check that lets the final DATA frame carry the
  END_STREAM flag was scheduled with process.nextTick() on every
  write. When the write is dispatched from inside end() - the common
  case of end(chunk) - the check can instead run synchronously once
  end() returns and the writable state has settled. An end()
  override marks the stream while the base method runs, and
  [kWriteGeneric] hands the check back to it instead of scheduling
  a tick. Writes not tied to end() keep the nextTick behavior.

- Every stream destruction scheduled a setImmediate() to ask the
  session to clean itself up, but Http2Session[kMaybeDestroy] is a
  no-op unless the session is closed and has no remaining streams.
  Gate the setImmediate() on that condition: session.close() runs
  its own check, and the native side notifies again through
  ongracefulclosecomplete once pending data is flushed.

The wire format is unchanged (verified byte-identical h2load
traffic), and the END_STREAM merge is preserved.

h2load -c 4 -m 100, 1 KiB payload, alternating runs vs the previous
commit: consistently around +1% (within run-to-run noise on any
single set, positive across 42 paired samples).

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: nodejs#64265
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Tim Perry <pimterry@gmail.com>
respond() copied the user-provided options object on every call just
so it could normalize and locally flip options.endStream, and
prepareResponseHeadersObject() then looked the :status and date
fields up again on the dictionary-mode null-prototype headers copy
it had just built. Use a local variable for endStream and pick up
:status/date while copying the headers instead.

No measurable throughput change on its own; this removes an object
clone and several dictionary-mode property lookups per response.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: nodejs#64265
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Tim Perry <pimterry@gmail.com>
Signed-off-by: Chengzhong Wu <cwu631@bloomberg.net>
PR-URL: nodejs#64220
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Adrian Estrada <edsadr@gmail.com>
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
Reviewed-By: Harshitha K P <harshitha014@gmail.com>
Signed-off-by: Moshe Atlov <moshe@atlow.co.il>
PR-URL: nodejs#64309
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Original commit message:

    [execution] Lookup interceptor for RestrictedGlobalProperty

    When the script context looks up if a global property is
    restricted, it should also query the global interceptor.

    To avoid calling the interceptor for every declaration
    unconditionally, an interceptor has to be defined with
    `PropertyHandlerFlags::kHasDontDeleteProperty`
    to intercept restricted global property queries.

    Refs: nodejs#63715
    Refs: nodejs#52634

    Change-Id: I623ff285c4e8773d8ee7f681cbad68ba24bd3f40
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7898818
    Reviewed-by: Leszek Swirski <leszeks@chromium.org>
    Reviewed-by: Igor Sheludko <ishell@chromium.org>
    Commit-Queue: Igor Sheludko <ishell@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#108280}

Refs: v8/v8@a05321e
Signed-off-by: Chengzhong Wu <cwu631@bloomberg.net>
PR-URL: nodejs#64202
Fixes: nodejs#63715
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Signed-off-by: Chengzhong Wu <cwu631@bloomberg.net>
PR-URL: nodejs#64202
Fixes: nodejs#63715
Refs: v8/v8@a05321e
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Increase the base timeout in test-http-server-consumed-timeout from
common.platformTimeout(200) to common.platformTimeout(1000).

The test is intentionally timing-sensitive and can fail on slower or
more contended CI hosts when timers fire later than expected. Using a
larger timeout reduces false positives without changing the behavior
being tested.

Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: openai:gpt-5.5
PR-URL: nodejs#64204
Refs: https://ci.nodejs.org/job/node-stress-single-test/764/
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
When an input provides Symbol.iterator, fromSync() should consume the
synchronous iterator instead of rejecting the input because it also
exposes an asynchronous or promise-like protocol.

Continue rejecting async-only iterables and promise/thenable-only
inputs, but allow sync iterables that also define Symbol.asyncIterator
or then().

Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: openai:gpt-5.5
PR-URL: nodejs#64294
Fixes: nodejs#64292
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
checkServerIdentity() stopped matching an IPv6 host against a matching
IP-Address SAN. The hostname is now run through domainToASCII() before
the net.isIP() gate, and domainToASCII('::1') === '' (an IPv6 literal is
not a domain), so net.isIP('') is 0, the IP-SAN branch is skipped, and
verification fails with "Cert does not contain a DNS name". IPv4 is
unaffected because dotted-decimal survives domainToASCII().

Match IP hosts against the original hostname instead of the IDNA-
normalized one. net.isIP() rejects non-ASCII input, so there is no IDNA
confusion to guard against for an IP literal; the normalized form is
still used for the DNS-name path.

Fixes: nodejs#64144
Signed-off-by: Pascal Garber <pascal@artandcode.studio>
PR-URL: nodejs#64145
Reviewed-By: Tim Perry <pimterry@gmail.com>
nodejs-github-bot and others added 14 commits July 8, 2026 09:57
PR-URL: nodejs#64315
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Notable changes:

buffer:
  * (SEMVER-MINOR) implement blob.textStream() (Matthew Aitken) nodejs#64036
esm:
  * (SEMVER-MINOR) add `--experimental-import-text` flag (Efe) nodejs#62300
perf_hooks:
  * (SEMVER-MINOR) sample delay per event loop iteration (Pablo Erhard) nodejs#62935
stream:
  * (SEMVER-MINOR) expose ReadableStreamTee (Matteo Collina) nodejs#64195
tls:
  * (SEMVER-MINOR) report negotiated TLS groups (Filip Skokan) nodejs#64119

PR-URL: nodejs#64329
Signed-off-by: Richard Lau <richard.lau@ibm.com>
Signed-off-by: Paolo Insogna <paolo@cowtech.it>
Assisted-By: OpenAI:GPT-5.5 <openai/gpt-5.5>
PR-URL: nodejs#64323
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
- Clarify permissions needed to be able to prepare a release
- Add CitGM to the "relevant jenkins jobs" section
- Clarify GPG key creation process and algorithms
- Also suggest that GPG keys can be published to ubuntu's keyservers
- Clarify that signed commits on release branches are required
- Add note about branch-diff using significant github API credits
- Explicit comment on each section which can be skipped with automation

Signed-off-by: Stewart X Addison <sxa@ibm.com>
PR-URL: nodejs#64198
Reviewed-By: Richard Lau <richard.lau@ibm.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
PR-URL: nodejs#64321
Signed-off-by: Stewart X Addison <sxa@ibm.com>
fromList() re-read state.length and each chunk's length several times
per call and re-loaded buffer[idx] around every copy, and read() loaded
state.length three times in its read(0) check; the engine cannot fold
these loads across the intervening copy and slice calls. Cache them in
locals instead. Ported from Bun's fork of the same functions
(src/js/internal/streams/readable.ts fromList/read), which carries
these hoists on top of the shared readable-stream lineage.

benchmark/compare.js against the unmodified baseline (60-run capture
plus an independent 30-run repeat, Welch t-test):
streams/readable-unevenread +0.65% (p=4.3e-4) / +0.59% (p=5.9e-3) and
streams/pipe.js +0.74% (p=2.0e-4) / +0.52% (p=8.8e-3), with no
significant regression across the captured streams benchmarks.

Refs: https://github.com/oven-sh/bun/blob/main/src/js/internal/streams/readable.ts
Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
Assisted-by: Grok (Grok Build)
PR-URL: nodejs#64312
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
The [[queue]] backing every default readable/writable controller was a
plain array of { value, size } wrappers consumed with
ArrayPrototypeShift, so each buffered chunk allocated a wrapper object
and each dequeue moved (or forced the engine to re-linearize) the
remaining elements; the byte controller queue paid the same shift cost
for its chunk descriptor records.

Replace the array with a power-of-two ring buffer. Default controller
queues store each entry as (value, size) in two consecutive slots, so
the per-chunk wrapper allocation disappears; the byte controller keeps
its descriptor records (they are mutated in place at the head) in
single slots. Controllers start from (and are reset to) a shared
immutable empty queue, so constructing a stream allocates no queue
storage until a chunk is actually buffered. Enqueues measured by the
internal default size algorithm (never observable by user code, always
returns 1, cannot throw) skip the algorithm call and its try/catch
entirely.

The layout mirrors what Bun/WebKit use for the same spec structure:
[[queue]] as a ring-buffer deque (WTF::Deque in Bun's
src/jsc/bindings/webcore/streams/StreamQueue.h), the pure-JS ring
buffer in Bun's src/js/internal/fifo.ts, and the trivial-size-algorithm
bypass in
src/jsc/bindings/webcore/streams/JSReadableStreamDefaultController.cpp.

benchmark/compare.js against the unmodified baseline (30-run capture
plus an independent 15-run repeat, Welch t-test, all p < 1e-5):
webstreams/pipe-to.js +12-17% across all sixteen high-water-mark
configurations, readable-read-buffered +20% (bufferSize=1) to +49%
(bufferSize=1000), readable-async-iterator +21%. No stable significant
regression across the rest of the webstreams suite: the creation.js and
readable-read.js deltas seen in the full-suite capture disappear in
isolated 60-run rechecks.

Refs: https://github.com/oven-sh/bun/blob/main/src/js/internal/fifo.ts
Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
Assisted-by: Grok (Grok Build)
PR-URL: nodejs#64312
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  - when the defer imported module contains top-level await
  - when the defer imported module is also eagerly imported

Refs: https://github.com/tc39/proposal-defer-import-eval
Signed-off-by: Maya Lekova <maya@igalia.com>
PR-URL: nodejs#64197
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
The http3 application had misinterpreted some of
nghttp3 callbacks regarding stopSending
and ResetStream.
Actually, these callbacks asks the application
to do the action and not informs about an event
from the peer.

The fixes lead to some failures of the automated
tests, uncovering some problems:

First headers, and pendingTrailers were reset,
when the internal object went away,
though the test wanted to read them.

Second, during a graceful session shutdown,
the implemented did not waited for all stream
to be removed, but only one.

Fixes: nodejs#63657

Signed-off-by: Marten Richter <marten.richter@freenet.de>
PR-URL: nodejs#64289
Fixes: nodejs#63657
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
PR-URL: nodejs#64199
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Richard Lau <richard.lau@ibm.com>
One small fix notably included:

- Check is_destroyed() after StreamCommit, since it calls JS callbacks
  which could destroy the session.

Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: nodejs#64127
Reviewed-By: James M Snell <jasnell@gmail.com>
PR-URL: nodejs#64330
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Richard Lau <richard.lau@ibm.com>
This separates the native crypto backend paths for OpenSSL >= 3,
BoringSSL, and legacy OpenSSL. The OpenSSL >= 3 path now builds with
`OPENSSL_API_COMPAT=30000` and `OPENSSL_NO_DEPRECATED`, moving normal
crypto/TLS code away from APIs that OpenSSL 3.0.0 marks deprecated.
BoringSSL remains on its own branch, and OpenSSL < 3 remains the legacy
fallback.

The exception is ENGINE support. ENGINE APIs are isolated into a
dedicated compatibility target so they can remain available while the
JS-facing engine APIs are runtime-deprecated in 27.x. That gives us a
clear removal point for 28.x, without letting ENGINE usage leak back
into the strict OpenSSL 3 path.

The split also makes the eventual OpenSSL 1.1.1 removal easier to reason
about. Once support for OpenSSL < 3 is dropped, the legacy branch can be
removed in a focused follow-up, possibly targeting 27.x, instead of
untangling mixed version guards throughout the crypto implementation.

No public crypto or TLS API behavior is intentionally changed.

Assisted-by: Codex:gpt-5
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
PR-URL: nodejs#64211
Refs: nodejs#56733
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Richard Lau <richard.lau@ibm.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Defer reading the next value from each source in merge() until the
merged consumer resumes after receiving the previous value.

Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: openai:gpt-5.5
PR-URL: nodejs#64293
Fixes: nodejs#63566
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
@SudhansuBandha

SudhansuBandha commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

node/deps/undici/undici.js

Lines 14727 to 14737 in 8fec65d

static createFastMessageEvent(type, init) {
const messageEvent = new _MessageEvent(kConstruct, type, init);
messageEvent.#eventInit = init;
messageEvent.#eventInit.data ??= null;
messageEvent.#eventInit.origin ??= "";
messageEvent.#eventInit.lastEventId ??= "";
messageEvent.#eventInit.source ??= null;
messageEvent.#eventInit.ports ??= [];
return messageEvent;
}
};

Will it be feasible to add a Node Specific extension on MessageEvent (ex.- event.sender). This would avoid a breaking change while still allowing Node to expose sender information through a separate property.
cc. @addaleax @mcollina @jasnell

Populate the MessageEvent source property with the sender's
worker thread ID for BroadcastChannel messages
originating from worker threads.

Fixes: nodejs#59053
Signed-off-by: Sudhansu Bandha <bandhasudhansu@gmail.com>
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.24%. Comparing base (e6a8d06) to head (c3d7dcd).
⚠️ Report is 307 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #64334      +/-   ##
==========================================
- Coverage   92.01%   90.24%   -1.77%     
==========================================
  Files         379      741     +362     
  Lines      166972   241344   +74372     
  Branches    25554    45477   +19923     
==========================================
+ Hits       153639   217807   +64168     
- Misses      13041    15088    +2047     
- Partials      292     8449    +8157     

see 548 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run. worker Issues and PRs related to Worker support.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BroadcastChannel doesn't fill in useful MessageEvent fields like source, or ports