## Summary
- When running `bun <file>` on a file with an unsupported type (e.g.,
`.css`, `.yaml`, `.toml`), Bun now shows a helpful error message instead
of the misleading "File not found"
- Tracks when a file is resolved but has a loader that can't be run
directly
- Shows the actual file path and file type in the error message
**Before:**
```
error: File not found "test.css"
```
**After:**
```
error: Cannot run "/path/to/test.css"
note: Bun cannot run css files directly
```
## Test plan
- [x] Added regression test in `test/regression/issue/1365.test.ts`
- [x] Test verifies unsupported files show "Cannot run" error
- [x] Test verifies nonexistent files still show "File not found"
- [x] Test fails with `USE_SYSTEM_BUN=1` and passes with debug build
Fixes#1365🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
- Fixes the entry point wrapper to distinguish between Server
configuration objects and already-running Server instances
- When a Server object from `Bun.serve()` is exported as the default
export, Bun no longer tries to call `Bun.serve()` on it again
## Root Cause
The entry point wrapper in `src/bundler/entry_points.zig` checks if the
default export has a `fetch` method to auto-start servers:
```javascript
if (typeof entryNamespace?.default?.fetch === 'function' || ...) {
const server = Bun.serve(entryNamespace.default);
}
```
However, `Server` objects returned from `Bun.serve()` also have a
`fetch` method (for programmatic request handling), so the wrapper
mistakenly tried to call `Bun.serve(server)` on an already-running
server.
## Solution
Added an `isServerConfig()` helper that checks:
1. The object has a `fetch` function or `app` property (config object
indicators)
2. The object does NOT have a `stop` method (Server instance indicator)
Server instances have `stop`, `reload`, `upgrade`, etc. methods, while
config objects don't.
## Test plan
- [x] Added regression test that verifies exporting a Server as default
export works without errors
- [x] Added test that verifies config objects with `fetch` still trigger
auto-start
- [x] Verified test fails with `USE_SYSTEM_BUN=1` and passes with the
fix
Fixes#26142🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Fixes the `handleProtocols` option not setting the selected protocol
in WebSocket upgrade responses
- Removes duplicate protocol header values in responses
## Test plan
- Added regression tests in `test/regression/issue/3613.test.ts`
- Verified using fetch to check actual response headers contain the
correct protocol
Fixes#3613🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
Add support for setting the `Content-Encoding` header in S3 `.write()`
and `.writer()` calls, following the same pattern as
`Content-Disposition`.
This allows users to specify the encoding of uploaded content:
```typescript
// With .write()
await s3file.write("compressed data", { contentEncoding: "gzip" });
// With .writer()
const writer = s3file.writer({ contentEncoding: "gzip" });
writer.write("compressed data");
await writer.end();
// With bucket.write()
await bucket.write("key", data, { contentEncoding: "br" });
```
## Implementation
- Extended `SignedHeaders.Key` from 6 bits to 7 bits (64→128
combinations) to accommodate the new header
- Added `content_encoding` to `S3CredentialsWithOptions`, `SignOptions`,
and `SignResult` structs
- Updated `CanonicalRequest` format strings to include
`content-encoding` in AWS SigV4 signing
- Added `getContentEncoding()` method to `Headers` for fetch-based S3
uploads
- Expanded `_headers` array from 9 to 10 elements
- Pass `content_encoding` through all S3 upload paths (upload,
uploadStream, writableStream)
## Test plan
- Added tests for "should be able to set content-encoding"
- Added tests for "should be able to set content-encoding in writer"
- Tests verify the Content-Encoding header is properly set on uploaded
objects via presigned URL fetch
- All 4 new tests pass with `bun bd test` and fail with
`USE_SYSTEM_BUN=1` (confirming the feature is new)
## Changelog
> Describe your changes in 1-2 sentences. These will be featured on
[bun.sh/blog](https://bun.sh/blog) and Bun's release notes.
Added `contentEncoding` option to S3 `.write()` and `.writer()` methods,
allowing users to set the `Content-Encoding` header when uploading
objects.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
Fixed `http.request()` and `https.request()` hanging indefinitely when a
GET request includes a body (via `req.write()`).
### Approach
Instead of adding a public `allowGetBody` option to `fetch()`, this PR
creates a dedicated internal function `nodeHttpClient` that:
- Uses a comptime parameter to avoid code duplication
- Allows body on GET/HEAD/OPTIONS requests (Node.js behavior)
- Is only accessible internally via `$newZigFunction`
- Keeps the public `Bun.fetch()` API unchanged (Web Standards compliant)
### Implementation
1. **fetch.zig**: Refactored to use `fetchImpl(comptime allow_get_body:
bool, ...)` shared implementation
- `Bun__fetch_()` calls `fetchImpl(false, ...)` - validates body on
GET/HEAD/OPTIONS
- `nodeHttpClient()` calls `fetchImpl(true, ...)` - allows body on
GET/HEAD/OPTIONS
2. **_http_client.ts**: Uses `$newZigFunction("fetch.zig",
"nodeHttpClient", 2)` for HTTP requests
## Test plan
- [x] Added regression test at `test/regression/issue/26143.test.ts`
- [x] Test verifies GET requests with body complete successfully
- [x] Test verifies HEAD requests with body complete successfully
- [x] Test verifies `Bun.fetch()` still throws on GET with body (Web
Standards)
- [x] Test fails on current release (v1.3.6) and passes with this fix
Fixes#26143🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
Co-authored-by: Ciro Spaciari MacBook <ciro@anthropic.com>
## Summary
- Fixes `bun completions` crashing with `BrokenPipe` error when piped to
commands that close stdout early (e.g., `bun completions | true`)
- The fix catches `error.BrokenPipe` and exits cleanly with status 0
instead of propagating the error
## Test plan
- [x] Added regression test that pipes `bun completions` to `true` and
verifies no BrokenPipe error occurs
- [x] Verified test fails with system Bun and passes with fixed build
Fixes#2977🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
- S3 `File.presign()` was ignoring the `contentDisposition` and `type`
options
- These options are now properly included as
`response-content-disposition` and `response-content-type` query
parameters in the presigned URL
- Added `content_type` field to `SignOptions` and
`S3CredentialsWithOptions` structs
- Added parsing for the `type` option in `getCredentialsWithOptions()`
- Query parameters are added in correct alphabetical order for AWS
Signature V4 compliance
## Test plan
- [x] Added regression test in `test/regression/issue/25750.test.ts`
- [x] Verified tests pass with debug build: `bun bd test
test/regression/issue/25750.test.ts`
- [x] Verified tests fail with system bun (without fix):
`USE_SYSTEM_BUN=1 bun test test/regression/issue/25750.test.ts`
- [x] Verified existing S3 presign tests still pass
- [x] Verified existing S3 signature order tests still pass
Fixes#25750🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
### What does this PR do?
Doubles the hardcoded max http header count
### How did you verify your code works?
ci (?)
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
- Fixes bug where `fetch()` with mTLS would use the first client
certificate for all subsequent requests to the same host, ignoring
per-request `tls` options
- Corrects `SSLConfig.isSame()` to properly compare all fields (was
incorrectly returning early when both optional fields were null)
- Sets `disable_keepalive=true` when reusing cached SSL contexts to
prevent socket pooling issues
Fixes#26125
## Test plan
- [x] Added regression test `test/regression/issue/26125.test.ts`
- [x] Verified test fails with system Bun 1.3.6 (demonstrates the bug)
- [x] Verified test passes with patched build
🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Fixes the broken pipe behavior for `process.stdout.write()` to match
Node.js
- When writing to a broken pipe (stdout destroyed), the process now
properly exits with code 1 instead of 0
- EPIPE errors are now properly propagated to JavaScript via the
stream's error event
## Test plan
- [x] Added regression test `test/regression/issue/1632.test.ts`
- [x] Verified test fails with system bun (exit code 0) and passes with
debug build (exit code 1)
- [x] Verified `console.log` still ignores errors (uses `catch {}`) and
doesn't crash
- [x] Verified callback-based `process.stdout.write()` receives EPIPE
error
## Changes
1. **`src/io/PipeWriter.zig`**: Return EPIPE as an error instead of
treating it as successful end-of-file (`.done`)
2. **`src/shell/IOWriter.zig`**: Track `broken_pipe` flag when EPIPE is
received via `onError` callback, and propagate error properly
3. **`src/js/internal/fs/streams.ts`**: When a write fails without a
callback, emit the error on the stream via `this.destroy(err)` to match
Node.js behavior
Fixes#1632🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Add colon (`:`) to the list of characters that require quoting in yarn
lockfile version strings
- This fixes yarn parse errors when using `workspace:*` dependencies in
monorepo setups
Fixes#3192
## Test plan
- [x] Added regression test that verifies `workspace:*` versions are
properly quoted
- [x] Test fails with system bun (before fix)
- [x] Test passes with debug build (after fix)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- When a module exports `globalThis` (e.g., `module.exports =
globalThis`), Bun's auto-serve detection incorrectly triggered because
`globalThis.fetch` is the Fetch API function
- Scripts that export globalThis (like `core-js/es/global-this.js`)
would start a development server on port 3000 instead of exiting
normally
- Added explicit check to skip auto-serve when the default export is
`globalThis` itself
Fixes#440
## Test plan
- [x] Added test case `test/regression/issue/440.test.ts` that verifies:
- `module.exports = globalThis` does not start a server
- `export default globalThis` does not start a server
- [x] Verified test fails with system Bun (without fix)
- [x] Verified test passes with debug build (with fix)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Fix memory leak in YAML parser that caused segfaults after high-volume
parsing
- Added `defer parser.deinit()` to free internal data structures
(context, block_indents, anchors, tag_handles, whitespace_buf)
- Fixes#26088
## Test plan
- [x] Added regression test at `test/regression/issue/26088.test.ts`
- [x] Verified YAML parsing still works correctly with debug build
- [x] Ran subset of YAML tests to confirm no regressions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
- Fixes#3657 - `fs.watch` on directory doesn't emit `change` events for
files created after watch starts
When watching a directory with `fs.watch`, files created after the watch
was established would only emit a 'rename' event on creation, but
subsequent modifications would not emit 'change' events.
## Root Cause
The issue was twofold:
1. `watch_dir_mask` in INotifyWatcher.zig was missing `IN.MODIFY`, so
the inotify system call was not subscribed to file modification events
for watched directories.
2. When directory events were processed in path_watcher.zig, all events
were hardcoded to emit 'rename' instead of properly distinguishing
between file creation/deletion ('rename') and file modification
('change').
## Changes
- Adds `IN.MODIFY` to `watch_dir_mask` to receive modification events
- Adds a `create` flag to `WatchEvent.Op` to track `IN.CREATE` events
- Updates directory event processing to emit 'change' for pure write
events and 'rename' for create/delete/move events
## Test plan
- [x] Added regression test `test/regression/issue/3657.test.ts`
- [x] Verified test fails with system Bun (before fix)
- [x] Verified test passes with debug build (after fix)
- [x] Verified manual reproduction from issue now works correctly
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
Fixes#25640
- Fixed bug where compiled binaries with `autoloadBunfig: false` would
still load `bunfig.toml` when `execArgv` was also provided
- The issue was that `Command.init(.AutoCommand)` was called to parse
execArgv, which loaded bunfig before checking the disable flag
## Test plan
- [x] Added tests for `autoloadBunfig: false` with `execArgv` in
`test/bundler/bundler_compile_autoload.test.ts`
- [x] Verified tests pass with debug build: `bun bd test
test/bundler/bundler_compile_autoload.test.ts`
- [x] Verified tests fail with system bun (demonstrates fix works):
`USE_SYSTEM_BUN=1 bun test test/bundler/bundler_compile_autoload.test.ts
-t "AutoloadBunfigDisabledWithExecArgv"`
- [x] All existing autoload tests still pass (22 tests total)
🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Fixed lazy-loaded chunks from dynamic imports not appearing in
`frontend.files` when using `--splitting` with `--compile` in fullstack
builds
- Updated `computeChunks.zig` to mark non-entry-point chunks as browser
chunks when they contain browser-targeted files
- Updated `HTMLImportManifest.zig` to include browser chunks from server
builds in the files manifest
Fixes#25628
## Test plan
- [ ] Added regression test `test/regression/issue/25628.test.ts` that
verifies lazy chunks appear in `frontend.files`
- [ ] Manually verified: system bun reports `CHUNK_COUNT:1` (bug), debug
bun reports `CHUNK_COUNT:2` (fix)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- CSS logical border-radius properties (`border-start-start-radius`,
`border-start-end-radius`, `border-end-end-radius`,
`border-end-start-radius`) were being silently dropped when processed by
the CSS bundler
- The bug was in `src/css/properties/border_radius.zig` where
`VendorPrefix{}` (all fields false) was used instead of `VendorPrefix{
.none = true }` when computing prefixes for logical properties
- This caused the properties to be dropped by a later `isEmpty()` check
since an empty prefix struct was returned
## Test plan
- [x] Added regression test `test/regression/issue/25785.test.ts`
- [x] Verified test fails with system Bun (`USE_SYSTEM_BUN=1 bun test`)
- [x] Verified test passes with fixed bun-debug (`bun bd test`)
Fixes#25785🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
- Fixes#25972: TestReporter domain events not firing when debugger
connects after test discovery
When a debugger client connects and enables the TestReporter domain
after tests have been discovered (e.g., using `--inspect` instead of
`--inspect-wait`), the `TestReporter.found`, `TestReporter.start`, and
`TestReporter.end` events would not fire. This is because tests
discovered without an enabled debugger have `test_id_for_debugger = 0`,
and the event emission code checks for non-zero IDs.
The fix retroactively assigns test IDs and reports discovered tests when
`TestReporter.enable` is called:
1. Check if there's an active test file in collection or execution phase
2. Iterate through the test tree (DescribeScopes and test entries)
3. Assign unique `test_id_for_debugger` values to each test/describe
4. Send `TestReporter.found` events for each discovered test
## Test plan
- [ ] Verify IDE integrations can now receive test telemetry when
connecting after test discovery
- [ ] Ensure existing `--inspect-wait` behavior continues to work
(debugger enabled before discovery)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Implements the `-l` (long listing) flag functionality for the shell
`ls` builtin
- The flag was being parsed but never used - output was identical to
short format
- Now displays proper long listing format: file type, permissions, hard
link count, UID, GID, size, modification time, and filename
## Test plan
- [x] Added regression test in `test/regression/issue/25831.test.ts`
- [x] Test passes with debug build: `bun bd test
test/regression/issue/25831.test.ts`
- [x] Test fails with system bun (confirming the bug exists):
`USE_SYSTEM_BUN=1 bun test test/regression/issue/25831.test.ts`
Example output with fix:
```
$ bun -e 'import { $ } from "bun"; console.log(await $`ls -l`.text())'
drwxr-xr-x 2 1000 1000 4096 Jan 12 15:30 subdir
-rw-r--r-- 1 1000 1000 11 Jan 12 15:30 file.txt
```
Fixes#25831🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
Fixes https://github.com/oven-sh/bun/issues/26082
- Fixes a bug where standalone executables compiled with
`--compile-exec-argv` would intercept `--version`, `-v`, `--help`, and
`-h` flags before user code could handle them
- CLI applications using libraries like `commander` can now properly
implement their own version and help commands
## Root Cause
When `--compile-exec-argv` is used, `Command.init` was being called with
`.AutoCommand`, which parses ALL arguments (including user arguments).
The `Arguments.parse` function intercepts `--version`/`--help` flags for
`AutoCommand`, preventing them from reaching user code.
## Fix
Temporarily set `bun.argv` to only include the executable name +
embedded exec argv options when calling `Command.init`. This ensures:
1. Bun's embedded options (like `--smol`, `--use-system-ca`) are
properly parsed
2. User arguments (including `--version`/`--help`) are NOT intercepted
by Bun's parser
3. User arguments are properly passed through to user code
## Test plan
- [x] Added tests for `--version`, `-v`, `--help`, and `-h` flags in
`compile-argv.test.ts`
- [x] Verified tests fail with `USE_SYSTEM_BUN=1` (proving the bug
exists)
- [x] Verified tests pass with debug build
- [x] Verified existing compile-argv tests still pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Adds a CLAUDE.md file to `test/js/node/test/parallel/` documenting
that these are official Node.js tests
- Explains that these tests should not be modified since they come from
the Node.js repository
- Documents how to run these tests with debug builds (`bun bd
<file-path>` instead of `bun bd test`)
## Test plan
- [x] Verified file was created correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Fix a hang in sequential MySQL transactions where an INSERT is awaited
followed by a SELECT returned in an array
- The issue occurred because `handleResultSetOK`'s defer block only
called `queue.advance()` without flushing, causing queries added during
the JS callback to not be properly sent
- Changed to call `flushQueue()` instead of just `advance()` to ensure
data is actually sent to the server
Fixes#26030
## Test plan
- Added regression test `test/regression/issue/26030.test.ts` with three
test cases:
- `Sequential transactions with INSERT and returned SELECT should not
hang` - reproduces the exact pattern from the bug report
- `Sequential transactions with returned array of multiple queries` -
tests returning multiple queries in array
- `Many sequential transactions with awaited INSERT and returned SELECT`
- stress tests with 5 sequential transactions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Fixed a bug where named function expressions were not renamed when
their name shadowed an outer symbol that's referenced inside the
function body
- This caused infinite recursion at runtime when namespace imports were
inlined
- Particularly affected Svelte 5 apps in dev mode
## Test plan
- [x] Added regression test that reproduces the issue
- [x] Verified test fails with system bun and passes with fix
- [x] Ran bundler tests (bundler_regressions, bundler_naming,
bundler_edgecase, bundler_minify) - all pass
## Root cause
The bundler was skipping `function_args` scopes when renaming symbols.
This meant named function expression names (which are declared in the
function_args scope) were never considered for renaming when they
collided with outer symbols.
For example, this code:
```javascript
import * as $ from './lib';
$.doSomething(function get() {
return $.get(123); // Should call outer get
});
```
Would be bundled as:
```javascript
function get(x) { return x * 2; } // from lib
doSomething(function get() {
return get(123); // Calls itself - infinite recursion!
});
```
Instead of:
```javascript
function get(x) { return x * 2; }
doSomething(function get2() { // Renamed to avoid collision
return get(123); // Correctly calls outer get
});
```
Fixes#25648🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
- Fixed MySQL VARCHAR/CHAR/TEXT columns with binary collations (like
`utf8mb4_bin`) being incorrectly returned as `Buffer` instead of
`string`
- The fix checks for `character_set == 63` (binary collation) in
addition to the BINARY flag to properly distinguish true binary types
Fixes#26063
## Root Cause
PR #26011 introduced a fix for binary column handling that checked
`column.flags.BINARY` to determine if data should be returned as
`Buffer`. However, MySQL sets the BINARY flag on VARCHAR/CHAR/TEXT
columns with binary collations (like `utf8mb4_bin`) even though they
should return strings.
The proper way to detect true binary types (BINARY, VARBINARY, BLOB) is
to check if `character_set == 63` (the "binary" collation), not just the
BINARY flag.
## Changes
1. **Text Protocol** (`ResultSet.zig:143-148`): Updated binary check to
`column.flags.BINARY and column.character_set == 63`
2. **Binary Protocol** (`DecodeBinaryValue.zig:154-156`): Added
`character_set` parameter and updated binary check
## Test plan
- [ ] Added regression test `test/regression/issue/26063.test.ts` that
tests VARCHAR, CHAR, and TEXT columns with `utf8mb4_bin` collation
return strings
- [ ] Test verifies that true BINARY/VARBINARY/BLOB columns still return
Buffers
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
- Fixed `bun install --frozen-lockfile` to use scope-specific registry
for scoped packages when the lockfile has an empty registry URL
When parsing a `bun.lock` file with an empty registry URL for a scoped
package (like `@example/test-package`), bun was unconditionally using
the default npm registry (`https://registry.npmjs.org/`) instead of
looking up the scope-specific registry from `bunfig.toml`.
For example, with this configuration in `bunfig.toml`:
```toml
[install.scopes]
example = { url = "https://npm.pkg.github.com" }
```
And this lockfile entry with an empty registry URL:
```json
"@example/test-package": ["@example/test-package@1.0.0", "", {}, "sha512-AAAA"]
```
bun would try to fetch from
`https://registry.npmjs.org/@example/test-package/-/...` instead of
`https://npm.pkg.github.com/@example/test-package/-/...`.
The fix uses `manager.scopeForPackageName()` (the same pattern used in
`pnpm.zig`) to look up the correct scope-specific registry URL.
## Test plan
- [x] Added regression test `test/regression/issue/026039.test.ts` that
verifies:
- Scoped packages use the scope-specific registry from `bunfig.toml`
- Non-scoped packages continue to use the default registry
- [x] Verified test fails with system bun (without fix) and passes with
debug build (with fix)
Fixes#26039🤖 Generated with [Claude Code](https://claude.ai/code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
### What does this PR do?
### How did you verify your code works?
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Previously, reactFastRefresh was silently ignored when target was not
'browser', even when explicitly enabled. This was confusing as there was
no warning or error.
This change removes the `target == .browser` check, trusting explicit
user intent. If users enable reactFastRefresh with a non-browser target,
the transform will now be applied. If `$RefreshReg$` is not defined at
runtime, it will fail fast with a clear error rather than silently doing
nothing.
Use case: Terminal UIs (like [termcast](https://termcast.app)) need
React Fast Refresh with target: 'bun' for hot reloading in non-browser
environments.
### How did you verify your code works?
Updated existing test removing target browser
## Summary
- Fixes `bun init --minimal` creating Cursor rules files and CLAUDE.md
when it shouldn't
- Adds regression test to verify `--minimal` only creates package.json
and tsconfig.json
## Test plan
- [x] Verify test fails with system bun (unfixed): `USE_SYSTEM_BUN=1 bun
test test/cli/init/init.test.ts -t "bun init --minimal"`
- [x] Verify test passes with debug build: `bun bd test
test/cli/init/init.test.ts -t "bun init --minimal"`
- [x] All existing init tests pass: `bun bd test
test/cli/init/init.test.ts`
Fixes#26050🤖 Generated with [Claude Code](https://claude.ai/code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Add `_idleStart` property (getter/setter) to the Timeout object
returned by `setTimeout()` and `setInterval()`
- The property returns a monotonic timestamp (in milliseconds)
representing when the timer was created
- This mimics Node.js's behavior where `_idleStart` is the libuv
timestamp at timer creation time
## Test plan
- [x] Verified test fails with `USE_SYSTEM_BUN=1 bun test
test/regression/issue/25639.test.ts`
- [x] Verified test passes with `bun bd test
test/regression/issue/25639.test.ts`
- [x] Manual verification:
```bash
# Bun with fix - _idleStart exists
./build/debug/bun-debug -e "const t = setTimeout(() => {}, 0);
console.log('_idleStart' in t, typeof t._idleStart); clearTimeout(t)"
# Output: true number
# Node.js reference - same behavior
node -e "const t = setTimeout(() => {}, 0); console.log('_idleStart' in
t, typeof t._idleStart); clearTimeout(t)"
# Output: true number
```
Closes#25639🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Fixes handler context not being restored after minifying nested CSS
rules
- Adds regression test for the issue
## Test plan
- [x] Test fails with `USE_SYSTEM_BUN=1 bun test
test/regression/issue/25794.test.ts`
- [x] Test passes with `bun bd test test/regression/issue/25794.test.ts`
Fixes#25794🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
Fix a memory leak in `RequestContext.doRenderWithBody()` where
`Strong.Impl` memory was leaked when proxying streaming responses
through Bun's HTTP server.
## Problem
When a streaming response (e.g., from a proxied fetch request) was
forwarded through Bun's server:
1. `response_body_readable_stream_ref` was initialized at line 1836
(from `lock.readable`) or line 1841 (via `Strong.init()`)
2. For `.Bytes` streams with `has_received_last_chunk=false`, a **new**
Strong reference was created at line 1902
3. The old Strong reference was **never deinit'd**, causing
`Strong.Impl` memory to leak
This leak accumulated over time with every streaming response proxied
through the server.
## Solution
Add `this.response_body_readable_stream_ref.deinit()` before creating
the new Strong reference. This is safe because:
- `stream` exists as a stack-local variable
- JSC's conservative GC tracks stack-local JSValues
- No GC can occur between consecutive synchronous Zig statements
- Therefore, `stream` won't be collected between `deinit()` and
`Strong.init()`
## Test
Added `test/js/web/fetch/server-response-stream-leak.test.ts` which:
- Creates a backend server that returns delayed streaming responses
- Creates a proxy server that forwards the streaming responses
- Makes 200 requests and checks that ReadableStream objects don't
accumulate
- Fails on system Bun v1.3.5 (202 leaked), passes with the fix
## Related
Similar to the Strong reference leak fixes in:
- #23313 (fetch memory leak)
- #25846 (fetch cyclic reference leak)
## What does this PR do?
Currently binary columns are returned as strings which means they get
corrupted when encoded in UTF8. This PR returns binary columns as
Buffers which is what user's actually expect and is also consistent with
PostgreSQL and SQLite.
### How did you verify your code works?
I added tests to verify the correct behavior. Before there were no tests
for binary columns at all.
This fixes#23991
Fixes#25862
### What does this PR do?
When a client sends pipelined data immediately after CONNECT request
headers in the same TCP segment, Bun now properly delivers this data to
the `head` parameter of the 'connect' event handler, matching Node.js
behavior.
This enables compatibility with Cap'n Proto's KJ HTTP library used by
Cloudflare's workerd runtime, which pipelines RPC data after CONNECT.
### How did you verify your code works?
<img width="694" height="612" alt="CleanShot 2026-01-09 at 15 30 22@2x"
src="https://github.com/user-attachments/assets/3ffe840e-1792-429c-8303-d98ac3e6912a"
/>
Tests
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
- Add comprehensive TypeScript type definitions for `Bun.Archive` in
`bun.d.ts`
- `ArchiveInput` and `ArchiveCompression` types
- Full JSDoc documentation with examples for all methods (`from`,
`write`, `extract`, `blob`, `bytes`, `files`)
- Add documentation page at `docs/runtime/archive.mdx`
- Quickstart examples
- Creating and extracting archives
- `files()` method with glob filtering
- Compression support
- Full API reference section
- Add Archive to docs sidebar under "Data & Storage"
- Add `files()` benchmark comparing `Bun.Archive.files()` vs node-tar
- Shows ~7x speedup for reading archive contents into memory (59µs vs
434µs)
## Test plan
- [x] TypeScript types compile correctly
- [x] Documentation renders properly in Mintlify format
- [x] Benchmark runs successfully and shows performance comparison
- [x] Verified `files()` method works correctly with both Bun.Archive
and node-tar
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
- Fixes a path traversal vulnerability via symlink when installing
GitHub packages
- Validates symlink targets before creation to ensure they stay within
the extraction directory
- Rejects absolute symlinks and relative paths that would escape the
extraction directory
## Details
When extracting GitHub tarballs, Bun did not validate symlink targets. A
malicious tarball could:
1. Create a symlink pointing outside the extraction directory (e.g.,
`../../../../../../../tmp`)
2. Include a file entry through that symlink path (e.g.,
`symlink-to-tmp/pwned.txt`)
When extracted, the symlink would be created first, then the file would
be written through it, ending up outside the intended package directory
(e.g., `/tmp/pwned.txt`).
### The Fix
Added `isSymlinkTargetSafe()` function that:
1. Rejects absolute symlink targets (starting with `/`)
2. Normalizes the combined path (symlink location + target) and rejects
if the result starts with `..` (would escape)
## Test plan
- [x] Added regression test
`test/cli/install/symlink-path-traversal.test.ts`
- [x] Tests verify relative path traversal symlinks are blocked
- [x] Tests verify absolute symlink targets are blocked
- [x] Tests verify safe relative symlinks within the package still work
- [x] Verified test fails with system bun (vulnerable) and passes with
debug build (fixed)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
### What does this PR do?
remove agent in global WebSocket (in node.js it uses dispatcher not
agent) add agent support in ws module (this actually uses agent)
### How did you verify your code works?
Tests
## Summary
Fixes#25869
Two fixes to enable `jest.useFakeTimers()` to work with
`@testing-library/react` and `@testing-library/user-event`:
- Set `setTimeout.clock = true` when fake timers are enabled.
testing-library/react's `jestFakeTimersAreEnabled()` checks for this
property to determine if `jest.advanceTimersByTime()` should be called
when draining the microtask queue. Without this, testing-library never
advances timers.
- Make `advanceTimersByTime(0)` fire `setTimeout(fn, 0)` timers.
`setTimeout(fn, 0)` is internally scheduled with a 1ms delay per HTML
spec. Jest/testing-library expect `advanceTimersByTime(0)` to fire such
"immediate" timers, but we were advancing by 0ms so they never fired.
## Test plan
- [x] All 30 existing fake timer tests pass
- [x] New regression test validates both fixes
- [x] Original user-event reproduction now works (test completes instead
of hanging)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
- **libarchive.zig:110**: Fix self-assignment bug where `this.pos` was
assigned to itself instead of `new_pos`
- **s3/credentials.zig:165,176,199**: Fix impossible range checks -
`and` should be `or` for pageSize, partSize, and retry validation (a
value cannot be both less than MIN and greater than MAX simultaneously)
- **postgres.zig:14**: Fix copy-paste error where createConnection
function was internally named "createQuery"
## Test plan
- [ ] Verify S3 credential validation now properly rejects out-of-range
values for pageSize, partSize, and retry
- [ ] Verify libarchive seek operations work correctly
- [ ] Verify postgres createConnection function has correct internal
name
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
## Summary
- Fixes#25903 - `Bun.write()` mode option ignored when copying from
`Bun.file()`
- The destination file now correctly uses the specified `mode` option
instead of default permissions
- Works on Linux (via open flags), macOS (chmod after clonefile), and
Windows (chmod after copyfile)
## Test plan
- [x] Added regression test in `test/regression/issue/25903.test.ts`
- [x] Test passes with `bun bd test test/regression/issue/25903.test.ts`
- [x] Test fails with `USE_SYSTEM_BUN=1 bun test
test/regression/issue/25903.test.ts` (verifies the bug exists)
## Changes
- `src/bun.js/webcore/Blob.zig`: Add `mode` field to `WriteFileOptions`
and parse from options
- `src/bun.js/webcore/blob/copy_file.zig`: Use `destination_mode` in
`CopyFile` struct and `doOpenFile`
- `packages/bun-types/bun.d.ts`: Add `mode` option to BunFile copy
overloads
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Add support for in-memory entrypoints and files in `Bun.build` via the
`files` option:
```ts
await Bun.build({
entrypoints: ["/app/index.ts"],
files: {
"/app/index.ts": `
import { greet } from "./greet.ts";
console.log(greet("World"));
`,
"/app/greet.ts": `
export function greet(name: string) {
return "Hello, " + name + "!";
}
`,
},
});
```
### Features
- **Bundle entirely from memory**: No files on disk needed
- **Override files on disk**: In-memory files take priority over disk
files
- **Mix disk and virtual files**: Real files can import virtual files
and vice versa
- **Multiple content types**: Supports `string`, `Blob`, `TypedArray`,
and `ArrayBuffer`
### Use Cases
- Code generation at build time
- Injecting build-time constants
- Testing with mock modules
- Bundling dynamically generated code
- Overriding configuration files for different environments
### Implementation Details
- Added `FileMap` struct in `JSBundler.zig` with `resolve`, `get`,
`contains`, `fromJS`, and `deinit` methods
- Uses `"memory"` namespace to avoid `pathWithPrettyInitialized`
allocation issues during linking phase
- FileMap checks added in:
- `runResolver` (entry point resolution)
- `runResolutionForParseTask` (import resolution)
- `enqueueEntryPoints` (entry point handling)
- `getCodeForParseTaskWithoutPlugins` (file content reading)
- Root directory defaults to cwd when all entrypoints are in the FileMap
- Added TypeScript types with JSDoc documentation
- Added bundler documentation with examples
## Test plan
- [x] Basic in-memory file bundling
- [x] In-memory files with absolute imports
- [x] In-memory files with relative imports (same dir, subdirs, parent
dirs)
- [x] Nested/chained imports between in-memory files
- [x] TypeScript and JSX support
- [x] Blob, Uint8Array, and ArrayBuffer content types
- [x] Re-exports and default exports
- [x] In-memory file overrides real file on disk
- [x] Real file on disk imports in-memory file via relative path
- [x] Mixed disk and memory files with complex import graphs
Run tests with: `bun bd test test/bundler/bundler_files.test.ts`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
## Summary
This PR implements a new `Bun.JSONC.parse()` API that allows parsing
JSONC (JSON with Comments) files. It addresses the feature request from
issue #16257 by providing a native API for parsing JSON with comments
and trailing commas.
The implementation follows the same pattern as `Bun.YAML` and
`Bun.TOML`, leveraging the existing `TSConfigParser` which already
handles JSONC parsing internally.
## Features
- **Parse JSON with comments**: Supports both `//` single-line and `/*
*/` block comments
- **Handle trailing commas**: Works with trailing commas in objects and
arrays
- **Full JavaScript object conversion**: Returns native JavaScript
objects/arrays
- **Error handling**: Proper error throwing for invalid JSON
- **TypeScript compatibility**: Works with TypeScript config files and
other JSONC formats
## Usage Example
```javascript
const result = Bun.JSONC.parse(`{
// This is a comment
"name": "my-app",
"version": "1.0.0", // trailing comma is allowed
"dependencies": {
"react": "^18.0.0",
},
}`);
// Returns native JavaScript object
```
## Implementation Details
- Created `JSONCObject.zig` following the same pattern as
`YAMLObject.zig` and `TOMLObject.zig`
- Uses the existing `TSConfigParser` from `json.zig` which already
handles comments and trailing commas
- Added proper C++ bindings and exports following Bun's established
patterns
- Comprehensive test suite covering various JSONC features
## Test Plan
- [x] Basic JSON parsing works
- [x] Single-line comments (`//`) are handled correctly
- [x] Block comments (`/* */`) are handled correctly
- [x] Trailing commas in objects and arrays work
- [x] Complex nested structures parse correctly
- [x] Error handling for invalid JSON
- [x] Empty objects and arrays work
- [x] Boolean and null values work correctly
🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>