You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Core: Disable component manifest by default - #34408, thanks @yannbf!
[!NOTE] Version >=0.5.0 of @​storybook/addon-mcp enables component manifests again. If you're upgrading Storybook from version >= 10.3.0 to >= 10.3.5 and are using the MCP addon, you should also upgrade @​storybook/addon-mcp to keep the docs toolset in the MCP server.
e8d657 fix: nvmrc precision logic, detect-indent for JSON, options.yes guard
Add NodeVersionPrecision type and precision field to parseNodeVersionString
so callers know if the input was major-only, major.minor, or full
Add mode:'nvmrc' option to isNodeVersionSupported: major-only "22" means
"latest 22.x" (supported), not 22.0.0 (which is not); major.minor "22.14"
checks at minor level rather than treating as 22.14.0
Use mode:'nvmrc' + precision in PreflightCheckCommand and node-version-check
nvmrc check paths so users with ".nvmrc: 22" are not incorrectly prompted
Replace naive indent detection in updateEnginesNode with detect-indent so
tab-indented JSON is preserved correctly (not converted to spaces)
Add options.yes === true to non-interactive guard alongside TTY/CI checks
Add nvmrc mode tests, precision assertions in parseNodeVersionString tests,
and tab/minified JSON indentation tests for updateEnginesNode
Core: Disable component manifest by default - #34408, thanks @yannbf!
[!NOTE] Version >=0.5.0 of @​storybook/addon-mcp enables component manifests again. If you're upgrading Storybook from version >= 10.3.0 to >= 10.3.5 and are using the MCP addon, you should also upgrade @​storybook/addon-mcp to keep the docs toolset in the MCP server.
e8d657 fix: nvmrc precision logic, detect-indent for JSON, options.yes guard
Add NodeVersionPrecision type and precision field to parseNodeVersionString
so callers know if the input was major-only, major.minor, or full
Add mode:'nvmrc' option to isNodeVersionSupported: major-only "22" means
"latest 22.x" (supported), not 22.0.0 (which is not); major.minor "22.14"
checks at minor level rather than treating as 22.14.0
Use mode:'nvmrc' + precision in PreflightCheckCommand and node-version-check
nvmrc check paths so users with ".nvmrc: 22" are not incorrectly prompted
Replace naive indent detection in updateEnginesNode with detect-indent so
tab-indented JSON is preserved correctly (not converted to spaces)
Add options.yes === true to non-interactive guard alongside TTY/CI checks
Add nvmrc mode tests, precision assertions in parseNodeVersionString tests,
and tab/minified JSON indentation tests for updateEnginesNode
d35774 bundler: fix stale HTML-import manifest etag across rebuilds (#29233)
What does this PR do?
The HTML chunk's manifest etag was its isolated_hash, which by
design hashes the output pieces between unique-key placeholders — i.e.
it excludes the slots where child-chunk paths are substituted. So when
only a referenced JS/CSS chunk changed, the served HTML body changed (it
embeds /chunk-<hash>.js) but its etag did not. Bun.serve would then
304 to a cached body that referenced chunks the new build no longer
served, leaving the page blank until a hard refresh.
Fix:
appendIsolatedHashesForImportedChunks now also recurses on .chunk/.scb output pieces. HTML chunks reference their JS/CSS via
pieces only (their cross_chunk_imports is empty), so without this
their transitive hash never folded in children. For JS chunks the visit
map makes the new recursion a no-op since those pieces are already
reached via cross_chunk_imports.
HTMLImportManifest emits each chunk's template.placeholder.hash
(the transitive hash) instead of isolated_hash.
JS/CSS chunk filenames are unchanged (verified by the existing snapshots
— only etag values moved).
Fixes #23009
How did you verify your code works?
New test html-import/etag-changes-with-referenced-chunks builds the
same HTML import twice with different JS content and asserts the HTML etag differs while the HTML path stays the same. Fails on main,
passes here.
RootMarkReason::MarkedJSValueRefArray enum value removed
BunV8HeapSnapshotBuilder.cpp switch case dropped.
InlineCacheHandler.h new transitive include of
InlineCacheCompiler.h
Added to PRIVATE_FRAMEWORK_HEADERS in JSC
CMakeLists.txt.
Compatibility Shim Added (oven-sh/WebKit only)
JSObject::globalObject() and Structure::globalObject() were
re-introduced under USE(BUN_JSC_ADDITIONS) as inline aliases of realmMayBeNull() / realm(). This avoids a 300+-call-site rename
across Bun's bindings and codegen templates in this PR; the alias
preserves the pre-rename nullable semantics. Migration to realm() can
be done incrementally.
Notable JSC Commits
Performance
da43fc766f60 — ArrayLengthStore IC for array.length = N
3ba3be2ff84e — IC for property keys undefined/true/false/null
7aea7dd35f02 — Fold string length in DFG/FTL
47263c1fcdf7 — toUpperCase intrinsic
3a21b7550526 — String#indexOf one-char fast path in DFG/FTL
6276c6b5f2b9 — Remove redundant mov in await/yield bytecode
7c75a8 deflake: fetch-proxy-tls-intern-race timeout on Linux release builds (#29212)
Summary
Fixes the 41/200 timeout flake of test/js/web/fetch/fetch-proxy-tls-intern-race.test.ts on Linux release
targets (🐧 25.04 x64-baseline, 🐧 3.23 aarch64, 🐧 13 x64-baseline).
Root cause: the test's CONNECT proxy only handled client.on("error"), not "close". The probe loop aborts each fetch
immediately, so the client→proxy socket usually closes with FIN (not
RST). The proxy→backend upstream socket was never destroyed in that
path. On release builds the setImmediate probe loop fires thousands of
times per second, so orphaned TLS connections accumulate on the backend Bun.serve until its accept queue / FD table saturates and the driver's
fetch stalls. The driver fetch had no abort signal, so await driverDone hung past the 30s test timeout.
Fix:
Proxy: destroy upstream on client "close" (and vice versa) so
aborted probes don't leak backend connections.
Fixture: start the hard cap as a setTimeout up front so it's
authoritative regardless of what the loops are blocked on; it flips stop and aborts the in-flight driver fetch.
Fixture: let the driver complete one request against an idle proxy
before the probe flood so the driverOk > 0 sanity check holds on
loaded CI. The warmup wait is bounded by the same hard-cap timer
(addresses the unbounded-loop review feedback on #28873).
Supersedes the fetch-proxy-tls-intern-race-fixture.ts portion of
#28873.
Test plan
20× sequential runs with release build (bun-pr 29163): all pass at
~5.4s
18× parallel runs (6 concurrent × 3 rounds) under load: all pass
After the parent shell dies, /proc shows the bun child was reparented
to init (kernel=1), but process.ppid is frozen at the dead parent
PID. This breaks the common orphan-detection pattern if (process.ppid === 1) process.exit(), which Node.js supports.
Cause
process.ppid was declared in BunProcess.cpp as:
ppid constructPpid PropertyCallback
PropertyCallback is a lazy property — it calls the constructor
once on first access and then caches the result on the process object.
So getppid() ran once at startup and never again, no matter how long
the process lived.
Fix
Switch ppid to a CustomAccessor getter that calls getppid() / uv_os_getppid() on every access. This matches Node.js, where process.ppid is a live getter backed by uv_os_getppid().
Writes to process.ppid replace the accessor with a plain value on the
process object via putDirect, so process.ppid = 5 also matches
Node's observable behavior (the write sticks).
Verification
test/regression/issue/29169.test.ts spawns setsid bash which forks a
backgrounded bun child, then kills the parent bash. The child reads both process.ppid and the real ppid from /proc/self/stat in a tight loop
and asserts that after reparenting, process.ppid matches the kernel's
view and is no longer the dead parent PID.
Before the fix: expect(reparented.js).toBe(reparented.kernel) → Expected: 1, Received: 5519 (the dead parent PID).
a0d9aa serve: consolidate file streaming into FileResponseStream; Range support; fix aborted-stream hang (#29202)
Started as a follow-up to #29185 fixing two StreamTransfer abort bugs,
then consolidated the four divergent file-response strategies into one
shared implementation and added Range support.
Fixes #20965
FileResponseStream
New src/bun.js/api/server/FileResponseStream.zig — owns
fd→AnyResponse body streaming. Shared by FileRoute (static routes:
entries) and RequestContext (file bodies returned from fetch
handlers).
BufferedReader path by default; kernel sendfile() only for ≥1MB
regular files on non-SSL POSIX
Idempotent finish(), abort-safe; detachResp() clears uWS callbacks
before end()/endSendFile() so the deferred eof_task can never
touch a reaped socket
fd closed in deinit() regardless of which path ran
Optional on_abort callback so RequestContext can route disconnects
through its real onAbort (preserving flags.aborted / additional_on_abort / req.signal)
SendfileContext shrinks to {offset, remain, total} — only what renderMetadata reads.
Range requests
New src/bun.js/api/server/RangeRequest.zig — parses Range: bytes=...
matching WebKit's parseRange semantics (case-insensitive unit,
whitespace-tolerant, suffix/open forms; multi-range falls through to
full body). Two-phase: parseRaw() captures the header without knowing
total size (so RequestContext can store it past the uWS request
buffer's lifetime), .resolve(total) validates against the stat'd size.
Both paths now honor incoming Range: for whole-file 200 responses →
206 + Content-Range / 416 + bytes */total. Range is ignored when the
route has a non-200 status or the blob is already .slice()d.
Bugs fixed
server.stop() hangs after any aborted file stream (#20965) — StreamTransfer.onAborted set has_ended_response before finish(),
so route.onResponseComplete() was skipped and pending_requests was
never decremented.
UAF when onReaderDone fires after abort — finish()
unconditionally deref'd; second entry took refcount to 0 and the queued defer this.deref() hit freed memory.
fd leak on aborted sendfile from a fetch handler — RequestContext.onAbort never closed sendfile.fd; deinit() didn't
either. Now owned by FileResponseStream.deinit.
SSL/Windows file responses buffered the entire file — the doReadFileInternal fallback. Now streams.
shouldCloseConnection() always false on 416/empty paths — was
called after detachResponse() nulled this.resp.
Error handler returning a file-backed Response was dropped — has_sendfile_ctx was latched before open/stat validation.
Duplicate Content-Length on file responses — renderMetadata
wrote one, then uWS end() added another; now marked.
bytes=-N on a zero-length file returned 416 — RFC 9110 §14.1.3
says positive suffix-length is satisfiable; now serves the (empty)
representation.
Tests
test/regression/issue/20965.test.ts — 5MB FileRoute, raw-TCP abort
after first chunk, assert server.stop() resolves (fails on main with HUNG)
bun-serve-file.test.ts — Range tests (describe.each over FileRoute
and fetch-handler paths):
closed/open/suffix/past-EOF/clamped/multi-range/case-insensitive
serve.test.ts 189 pass × 8 runs no ASAN; bun-serve-file 56 / static 34 / routes 40 / ssl 16; zig:check-all clean on all 12
targets.
b18f26 WebSocket client: support ws+unix:// and wss+unix:// (#29203)
What does this PR do?
Adds Unix domain socket support to the WebSocket client via the ws+unix:// and wss+unix:// URL schemes.
// Plainconstws=newWebSocket("ws+unix:///tmp/app.sock");// With a request path (split on first ':', same as the npm `ws` package)constws=newWebSocket("ws+unix:///tmp/app.sock:/api/stream?x=1");// TLS over a unix socketconstws=newWebSocket("wss+unix:///tmp/app.sock",{tls: {rejectUnauthorized: false},});
Host header defaults to localhost, matching Node's http.request({ socketPath }) and ws.
Proxies are ignored for unix URLs (the socket is local).
wss+unix:// selects the TLS socket context and runs the normal
handshake over the domain socket.
How did you verify your code works?
New test file test/js/web/websocket/websocket-unix.test.ts covers:
echo over Bun.serve({ unix })
:path + query string parsing and Host header value
binary frames
connect failure when the socket file does not exist
SyntaxError on missing socket path
wss+unix:// against Bun.serve({ unix, tls })
round-trip from a spawned subprocess
7 pass
0 fail
Existing websocket-client.test.ts and websocket-custom-headers.test.ts continue to pass.
Implementation
WebSocket.cpp: recognise ws+unix: / wss+unix:, split pathname on
the first : into socket path + request path, default host to localhost, skip proxy, pass the socket path through to Zig.
WebSocketUpgradeClient.zig: new unix_socket_path arg; when set,
dial via Socket.connectUnixAnon on the existing per-SSL us_socket_context instead of the TCP connectPtr path. All downstream
state (upgrade, adopt, deflate, custom SSL ctx) is unchanged.
headers.h: add the parameter to both Bun__WebSocketHTTP{,S}Client__connect externs.
c39ed1 fix(serve): close fd on 304 / HEAD / bodiless paths in FileRoute (#29185)
What
Bun.serve static file routes (static: { "/path": new Response(Bun.file(...)) }) leaked one file descriptor per 304 Not
Modified and per HEAD response. Under CDN-style traffic this exhausted
the OS fd limit within minutes.
FileRoute.on() (src/bun.js/api/server/FileRoute.zig) opens the
backing file before selecting a status code, and only transfers fd
ownership to StreamTransfer on the streaming path. Four early-return
paths between the open and the transfer skipped the close entirely:
Only the !can_serve_file branch correctly called bun.Async.Closer.close(fd, …). The 304 and HEAD paths are the dominant
leak cases because they fire on every conditional request.
Fix
Close the fd on each early-return path in FileRoute.on(), matching the
existing !can_serve_file pattern.
6b9ee6 Implement X25519 deriveBits in SubtleCrypto (#29152)
4b1d88 CI: fix unchecked exception in test failure previews
0ffd1b perf: add butterfly fast path to JSArrayIterator (#29104)
Summary
Adds a fast path to JSArrayIterator that reads elements directly from
the JSArray butterfly when the array has Int32 or Contiguous storage
and a sane prototype chain, instead of calling JSObject::getIndex()
per element.
This generalizes the approach proposed in #26294 by putting the fast
path inside JSArrayIterator.next() itself, so every existing call site
benefits without code duplication.
Changes
src/bun.js/bindings/bindings.cpp
Bun__JSArray__getContiguousVector() — returns butterfly->contiguous().data() when isJSArray && (Int32|Contiguous) && canDoFastIndexedAccess().
Bun__JSArray__contiguousVectorIsStillValid() — cheap revalidation of
indexing type, butterfly identity, and publicLength.
src/bun.js/bindings/JSArrayIterator.zig — init() attempts the
fast path; next() revalidates the butterfly before each direct read
and falls back to getIndex if the array was mutated. Holes (encoded 0) become js_undefined.
Safety
The revalidation mirrors JSC's fastArrayJoin
(ArrayPrototypeInlines.h), which checks thisObject->butterfly() == &butterfly && originalLength == butterfly.publicLength() after each
potentially side-effecting element conversion and bails to the generic
path if the butterfly was reallocated or transitioned. This makes the
iterator safe even when callers run user JS between next() calls (e.g. expect().toContainEqual() triggering a getter that mutates the
iterated array).
Benchmarks (Apple M4 Max, release, median of 4 alternating runs)
benchmark
baseline
optimized
speedup
expect(arr).toContain(last) [1000 ints]
11493 ns
8031 ns
1.43x
expect(x).toBeOneOf(arr) [1000 ints]
13736 ns
10643 ns
1.29x
new Blob([100 strings + 100 buffers])
9703 ns
8301 ns
1.17x
new Blob([1000 strings])
56817 ns
49630 ns
1.14x
Tests
13 cases in test/js/web/fetch/blob-array-fast-path.test.ts covering
contiguous/Int32/sparse/frozen/derived arrays, holes, Array.prototype
indexed-getter fallback, mixed types, non-ASCII, and array mutation
during iteration via element side-effect.
232473 fix(css): preserve leading @layer statements when bundling (#28915)
What
Closes #28914.
The CSS bundler's leading-rule filter in prepareCssAstsForChunk was
unconditionally stripping every leading .layer_statement rule, which
deleted the top-level @​layer ordering declarations that Tailwind CSS
(and anyone using cascade layers) depends on.
Repro
/* entry.css */
@​layer theme,base,components,utilities;
@​layer base {
body { color: red; }
}
$ bun build ./entry.css/* entry.css */@​layer base { body { color: red; }}
The @​layer theme, base, components, utilities; line is gone. Without
it the cascade order is whatever happens to be emitted first, which is
exactly the Tailwind breakage reported in #28914.
Cause
Regression from #27131 (e7cf4b77ba), which added .layer_statement to
the leading-rule filter in src/bundler/linker_context/prepareCssAstsForChunk.zig:
if (rule.*==.importorrule.*==.ignoredorrule.*==.layer_statement) {} else {
// slice off [0..ruleidx]
}
That fix wanted the filter to skip past leading @​layer statements
so it could reach and strip the interleaved @​import rules underneath
them (the target of #20546). But the filter mechanism is "drop
everything up to the first non-match", so skipping past @​layer also
dropped it. For files with no @​import layer(...) (Tailwind's shape),
nothing else re-emits those layer names and the ordering information is
lost.
Fix
Rewrite the filter as an in-place compaction:
Drop leading .import and .ignored rules.
Keep .layer_statement rules, compacting them forward.
Stop at the first rule of any other kind, then shift the tail to close
the gap.
This keeps the #20546 behavior (interleaved @​import rules are still
stripped) while preserving the layer ordering declarations that Tailwind
needs.
Verification
New regression test: test/regression/issue/28914.test.ts (4 cases —
Tailwind-style statement + block, bare statement, statement + unlayered
rule, multiple individual statements). All pass on the patched build,
all fail on system bun.
Existing test/regression/issue/20546.test.ts still passes (2/2).
Full CSS bundler suite test/bundler/esbuild/css.test.ts passes
(53/53).
Broader CSS parser suite test/js/bun/css/css.test.ts passes
(1028/1028).
5c885f Fix neon CPU feature detection on macOS arm64 (#29153)
Summary
aarch64_cpu_features() queried hw.optional.AdvSIMD, which does not
exist on macOS. The documented key is hw.optional.arm.AdvSIMD (legacy
alias hw.optional.neon).
Effect: the neon bit in bun_cpu_features() was never set on Apple
Silicon. The other macOS aarch64 keys (hw.optional.floatingpoint, hw.optional.arm.FEAT_AES, hw.optional.armv8_crc32, hw.optional.arm.FEAT_LSE) are correct.
$ sysctl hw.optional.AdvSIMDsysctl: unknown oid 'hw.optional.AdvSIMD'
$ sysctl hw.optional.arm.AdvSIMDhw.optional.arm.AdvSIMD: 1
Adds MKADDRESSBOOK to Bun's HTTP method allowlist. Before this change, Bun.serve would silently drop requests with method MKADDRESSBOOK and fetch() would rewrite them to GET.
MKADDRESSBOOK is a CardDAV extension method (analogous to MKCALENDAR
for CalDAV) used by Apple's Calendar & Contacts server and other CardDAV
implementations to create an address book collection.
Root cause
The method name was missing from five duplicated allowlists:
src/http/Method.zig — the Zig enum + ComptimeStringMap used by Bun.serve / fetch()
src/bun.js/bindings/BunCommonStrings.cpp — HTTPMethod enum (must
stay in sync with Method.zig) + toJS switch
src/bun.js/bindings/BunCommonStrings.h — lazy interned JS string
list
src/js/internal/http.ts — the METHODS array exported as http.METHODS
packages/bun-uws/src/HttpContext.h — supportedHttpMethods used
when registering a * (catch-all) route handler. If the method isn't in
this list, uWS never dispatches to the Zig handler, which is why raw TCP MKADDRESSBOOK requests were dropped before ever reaching Method.which().
Fix
Adds MKADDRESSBOOK in the alphabetically-correct slot in all five
lists and shifts the numeric discriminants in Method.zig and BunCommonStrings.cpp by one (they must stay in lockstep).
Verification
Regression test at test/regression/issue/28954.test.ts covers three
things:
Raw TCP MKADDRESSBOOK / HTTP/1.1 reaches the Bun.serve handler
(this exercises the uWS route dispatch path separately from fetch's
client-side method validation)
http.METHODS contains MKADDRESSBOOK
Without the fix all three tests fail; with the fix all three pass.
Note: node:http uses llhttp (vendored under src/bun.js/bindings/node/http/llhttp/) which has its own method
allowlist. Extending llhttp requires regenerating the parser and is out
of scope for this issue — Bun.serve and fetch() are the primary
paths.
The zig step itself reports success. Reproduced by
oven-sh/bun-development-docker-image's Daily Docker Build on every run
since Apr 9
(example).
Cause
#29092 enabled the parallel-sema compiler with sharded LLVM codegen on
Linux local builds. Sharded codegen on Linux goes through oven-sh/zig's
self-hosted ELF -r merge to combine the per-shard .o files into bun-zig.o. #29092's compiler bump fixed a hang in that merge, but the
merge output is still incomplete — getEmittedBin() installs a bun-zig.o missing the symbols. The subsequent bumps to 7d3c0c9b / 445fc0cb haven't fixed it either.
macOS uses the Mach-O merge path, which works (verified locally — single
315MB .o with llvm_codegen_threads=16).
Fix
Gate the parallel compiler back to darwin-only until the ELF merge in
oven-sh/zig is fixed. Linux local builds revert to the stable compiler
(same as CI). No change for darwin or CI.
tls.connect({host, port}) without an explicit servername option was
skipping hostname verification entirely and reporting authorized: true
for any certificate that passed chain-of-trust. An on-path attacker
presenting any CA-signed cert (e.g. a free Let's Encrypt cert for attacker.com) could MITM connections made by libraries like pg, ioredis, mysql2, and nodemailer that call tls.connect without
setting servername.
Root cause
TLSSocket.prototype[buntls] (src/js/node/tls.ts) returned the host
fallback under the key serverName (camelCase), but the consumer in
src/js/node/net.ts read tls.servername (lowercase) — so self.servername stayed undefined and the guard && self.servername
at the handshake callback skipped checkServerIdentity, falling through
to authorized = true. The lowercase key only existed (via the ...this[ksecureContext] spread) when the user passed servername
explicitly.
The native layer provided no backstop: SSL_set1_host is declared but
never called; only SNI is set.
Fix
Emit a single lowercase servername after the secureContext spread,
computed as this.servername || ctx?.servername || host || "localhost".
The native SSLConfig.fromJS already accepts lowercase via altNames: ["servername"] in SSLConfig.bindv2.ts, so SNI continues to work. This
also fixes a secondary issue where native SNI was reading the camelCase
key (= host) instead of the user's explicit servername option.
Tests
New: test/js/node/tls/node-tls-connect-hostname-verification.test.ts —
written with node:test + node:assert so it runs identically under
Node.js and Bun. Verified to pass in Node v25.2.1, fail on bun 1.3.11
(authorized: true, checkServerIdentity never called), and pass with
this fix.
Updated existing tests that were silently relying on the bug:
node-tls-cert.test.ts — the shared checkServerIdentity override
asserted hostname === "localhost" while the connect helper used host: "127.0.0.1"; the assertion was dead code before and is now corrected.
Cipher tests now pass the override since their cert is for agent10.example.com.
node-tls-cert-extra-ca.fixture.ts — adds a no-op checkServerIdentity (fixture tests CA loading, not hostname).
node-tls-connect.test.ts — 4 assertions on the internal [symbolConnectOptions].serverName updated to .servername.
Verification
node --experimental-strip-types --test test/js/node/tls/node-tls-connect-hostname-verification.test.ts # 3 pass
USE_SYSTEM_BUN=1 bun test test/js/node/tls/node-tls-connect-hostname-verification.test.ts # 3 fail (bug repro)
bun bd test test/js/node/tls/node-tls-{connect-hostname-verification,connect,cert}.test.ts # 52 pass / 0 fail
bun bd test test/js/node/tls/node-tls-{server,context}.test.ts # 28 pass / 0 fail
Unrelated pre-existing gap
While probing, noticed server-side SNICallback does not receive the
client's SNI value in Bun (same on 1.3.11). Not touched by this PR.
ad909a Fix segfault in StringDecoder.write() when result exceeds String::MaxLength (#29111)
panic(main thread): Segmentation fault at address 0x5
Cause
Bun__encoding__toString can throw (e.g. ERR_STRING_TOO_LONG when the
decoded length exceeds JSC's String::MaxLength of 2³¹-1) and return
encoded-0. JSStringDecoder::text() / fillLast() / write()
propagate that as an empty JSValue via RELEASE_AND_RETURN, and the
caller then did:
.toString() runs before the exception check. On an empty JSValue, isCell() is true, asCell() is nullptr, and asCell()->type()
reads JSCell::m_type at offset 5 → segfault at address 0x5.
Fix
Store the JSValue, RETURN_IF_EXCEPTION, then.toString(). Same
pattern applied to all affected sites in write() and end().
Now throws ERR_STRING_TOO_LONG like Node.js instead of crashing.
Verification
bun bd test test/js/node/string_decoder/string-decoder.test.js → 84
pass / 0 fail
USE_SYSTEM_BUN=1 bun test ... -t "larger than String::MaxLength" →
fails (subprocess segfaults)
BUN_JSC_validateExceptionChecks=1 clean on all encoding paths
Node parallel tests test-string-decoder{,-end,-fuzz}.js all pass
After queue.push(this) publishes the job, the main thread can be woken
by a ConcurrentTask enqueued by a different worker, call RuntimeTranspilerStore.runFromJSThread() → queue.popBatch() (which
drains all pushed jobs, including this one) → runFromJSThread() → store.put(this). HiveArray.put() writes value.* = undefined across
the slot, so by the time this worker executes the second line and
reloads this.vm, it reads 0xAA poison and vm.eventLoop()
dereferences a non-canonical pointer.
In practice this only crashes on Windows x64 release builds: those are
ReleaseSafe, so = undefined actually writes 0xAA (ReleaseFast is a
no-op), and the generated code reloads this.vm after the xchg in queue.push rather than CSE'ing it. The window between the two
instructions is a handful of cycles, so it only fires when the worker is
preempted right after the push on an oversubscribed machine.
Crash reports show up as Segmentation fault at address 0xFFFFFFFFFFFFFFFF with frames VirtualMachine.zig:eventLoop / arena_allocator.zig:deinit / atomic.zig:fetchSub (the innermost
inline at each PC; the outermost frames are dispatchToMainThread / TranspilerJob.run / ThreadPool.Thread.run).
Fix: snapshot vm into a local before queue.push(this) and never
touch this after publishing.
775a36 fix(usockets): snapshot loop before context unref in us_connecting_socket_free (#29064)
us_internal_socket_context_unlink_connecting_socket() calls
us_socket_context_unref(), which can drop the last reference and queue
the context for free. The two lines that follow then dereference
c->context->loop. Snapshot the loop pointer before unlink runs.
Matches the existing snapshot idiom in start_connections
(context.c:596-597).
Part of defensive hardening for the v1.3.11 crash signature (segfault at
0x0 inside us_loop_run_bun_tick at loop.c:238, the inlined
us_internal_socket_after_resolve / DNS drain path). No deterministic
repro; ASAN stress test (WebSocket + cancel + spawnSync, 50 iters) runs
clean on the debug build. Existing socket / node:net / DNS / proxy tests
pass (proxy redirect timeouts are pre-existing on main).
Companion PR: ref/unref the context across
us_internal_socket_after_resolve.
4c9061 build: bump ZIG_COMMIT_PARALLEL to 445fc0cbba (#29097)
f0c014 build: pass --locked to cargo for vendored Rust deps (#29095)
Pass --locked to cargo build in emitCargo() so transitive Rust
crate versions can't silently re-resolve against crates.io.
Bumps LOLHTML_COMMIT one commit forward (e3aa547→77127cd) because
the old pin's c-api/Cargo.lock was stale (upstream forgot to
regenerate it for 2.7.2). The new pin is the upstream lockfile fix; only c-api/Cargo.lock differs between the two — same lol-html 2.7.2 source.
8e65e4 fix(websocket): double-free on ws.close() during proxy TLS handshake (#29101)
Core: Disable component manifest by default - #34408, thanks @yannbf!
[!NOTE] Version >=0.5.0 of @​storybook/addon-mcp enables component manifests again. If you're upgrading Storybook from version >= 10.3.0 to >= 10.3.5 and are using the MCP addon, you should also upgrade @​storybook/addon-mcp to keep the docs toolset in the MCP server.
e8d657 fix: nvmrc precision logic, detect-indent for JSON, options.yes guard
Add NodeVersionPrecision type and precision field to parseNodeVersionString
so callers know if the input was major-only, major.minor, or full
Add mode:'nvmrc' option to isNodeVersionSupported: major-only "22" means
"latest 22.x" (supported), not 22.0.0 (which is not); major.minor "22.14"
checks at minor level rather than treating as 22.14.0
Use mode:'nvmrc' + precision in PreflightCheckCommand and node-version-check
nvmrc check paths so users with ".nvmrc: 22" are not incorrectly prompted
Replace naive indent detection in updateEnginesNode with detect-indent so
tab-indented JSON is preserved correctly (not converted to spaces)
Add options.yes === true to non-interactive guard alongside TTY/CI checks
Add nvmrc mode tests, precision assertions in parseNodeVersionString tests,
and tab/minified JSON indentation tests for updateEnginesNode
Core: Disable component manifest by default - #34408, thanks @yannbf!
[!NOTE] Version >=0.5.0 of @​storybook/addon-mcp enables component manifests again. If you're upgrading Storybook from version >= 10.3.0 to >= 10.3.5 and are using the MCP addon, you should also upgrade @​storybook/addon-mcp to keep the docs toolset in the MCP server.
e8d657 fix: nvmrc precision logic, detect-indent for JSON, options.yes guard
Add NodeVersionPrecision type and precision field to parseNodeVersionString
so callers know if the input was major-only, major.minor, or full
Add mode:'nvmrc' option to isNodeVersionSupported: major-only "22" means
"latest 22.x" (supported), not 22.0.0 (which is not); major.minor "22.14"
checks at minor level rather than treating as 22.14.0
Use mode:'nvmrc' + precision in PreflightCheckCommand and node-version-check
nvmrc check paths so users with ".nvmrc: 22" are not incorrectly prompted
Replace naive indent detection in updateEnginesNode with detect-indent so
tab-indented JSON is preserved correctly (not converted to spaces)
Add options.yes === true to non-interactive guard alongside TTY/CI checks
Add nvmrc mode tests, precision assertions in parseNodeVersionString tests,
and tab/minified JSON indentation tests for updateEnginesNode
Core: Disable component manifest by default - #34408, thanks @yannbf!
[!NOTE] Version >=0.5.0 of @​storybook/addon-mcp enables component manifests again. If you're upgrading Storybook from version >= 10.3.0 to >= 10.3.5 and are using the MCP addon, you should also upgrade @​storybook/addon-mcp to keep the docs toolset in the MCP server.
e8d657 fix: nvmrc precision logic, detect-indent for JSON, options.yes guard
Add NodeVersionPrecision type and precision field to parseNodeVersionString
so callers know if the input was major-only, major.minor, or full
Add mode:'nvmrc' option to isNodeVersionSupported: major-only "22" means
"latest 22.x" (supported), not 22.0.0 (which is not); major.minor "22.14"
checks at minor level rather than treating as 22.14.0
Use mode:'nvmrc' + precision in PreflightCheckCommand and node-version-check
nvmrc check paths so users with ".nvmrc: 22" are not incorrectly prompted
Replace naive indent detection in updateEnginesNode with detect-indent so
tab-indented JSON is preserved correctly (not converted to spaces)
Add options.yes === true to non-interactive guard alongside TTY/CI checks
Add nvmrc mode tests, precision assertions in parseNodeVersionString tests,
and tab/minified JSON indentation tests for updateEnginesNode
Core: Disable component manifest by default - #34408, thanks @yannbf!
[!NOTE] Version >=0.5.0 of @​storybook/addon-mcp enables component manifests again. If you're upgrading Storybook from version >= 10.3.0 to >= 10.3.5 and are using the MCP addon, you should also upgrade @​storybook/addon-mcp to keep the docs toolset in the MCP server.
e8d657 fix: nvmrc precision logic, detect-indent for JSON, options.yes guard
Add NodeVersionPrecision type and precision field to parseNodeVersionString
so callers know if the input was major-only, major.minor, or full
Add mode:'nvmrc' option to isNodeVersionSupported: major-only "22" means
"latest 22.x" (supported), not 22.0.0 (which is not); major.minor "22.14"
checks at minor level rather than treating as 22.14.0
Use mode:'nvmrc' + precision in PreflightCheckCommand and node-version-check
nvmrc check paths so users with ".nvmrc: 22" are not incorrectly prompted
Replace naive indent detection in updateEnginesNode with detect-indent so
tab-indented JSON is preserved correctly (not converted to spaces)
Add options.yes === true to non-interactive guard alongside TTY/CI checks
Add nvmrc mode tests, precision assertions in parseNodeVersionString tests,
and tab/minified JSON indentation tests for updateEnginesNode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Updated Packages