Fixes#6934Fixes#7390
This PR also adds a test case for checking matchers, including when they
should fail
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
This PR makes connection string parsing more sensible in Bun.SQL,
without breaking the default fallback of postgres
Added some tests checking for connection string precedence
---------
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: Ciro Spaciari <ciro.spaciari@gmail.com>
## Summary
- Fixes#22481 where `Socket.write()` was throwing
"Stream._isArrayBufferView is not a function" when passed a Uint8Array
- The helper methods were being added to the wrong Stream export
- Now adds them directly to the Stream constructor in
`internal/streams/legacy.ts` where they're actually used
## Test plan
- Added regression test in `test/regression/issue/22481.test.ts`
- Test verifies that sockets can write Uint8Array, Buffer, and other
TypedArray views
- All tests pass with the fix
🤖 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>
### What does this PR do?
Since `JSBundlerPlugin` did not inherit from `JSDestructibleObject`, it
did not call the destructor. This means it never called the destructor
on `BundlerPlugin`, which means it leaked the WTF::Vector of RegExp and
strings.
This adds a small `WriteBarrierList` abstraction that is a
`WriteBarrier` guarded by the owning `JSCell`'s `cellLock()` that has a
`visitChildren` function. This also removes two usages of `JSC::Strong`
on the `Zig::GlboalObject` and replaces them with the
`WriteBarrierList`.
### How did you verify your code works?
Added a test. The test did not previously fail. But it's still good to
have a test that checks the onLoad callbacks are finalized.
## Summary
Implements the `typeof undefined === 'u'` minification optimization from
esbuild in Bun's minifier, and fixes dead code elimination (DCE) for
typeof comparisons with string literals.
### Part 1: Minification Optimization
This optimization transforms:
- `typeof x === "undefined"` → `typeof x > "u"`
- `typeof x !== "undefined"` → `typeof x < "u"`
- `typeof x == "undefined"` → `typeof x > "u"`
- `typeof x != "undefined"` → `typeof x < "u"`
Also handles flipped operands (`"undefined" === typeof x`).
### Part 2: DCE Fix for Typeof Comparisons
Fixed dead code elimination to properly handle typeof comparisons with
strings (e.g., `typeof x <= 'u'`). These patterns can now be correctly
eliminated when they reference unbound identifiers that would throw
ReferenceErrors.
## Before/After
### Minification
Before:
```javascript
console.log(typeof x === "undefined");
```
After:
```javascript
console.log(typeof x > "u");
```
### Dead Code Elimination
Before (incorrectly kept):
```javascript
var REMOVE_1 = typeof x <= 'u' ? x : null;
```
After (correctly eliminated):
```javascript
// removed
```
## Implementation
### Minification
- Added `tryOptimizeTypeofUndefined` function in
`src/ast/visitBinaryExpression.zig`
- Handles all 4 equality operators and both operand orders
- Only optimizes when both sides match the expected pattern (typeof
expression + "undefined" string)
- Replaces "undefined" with "u" and changes operators to `>` (for
equality) or `<` (for inequality)
### DCE Improvements
- Extended `isSideEffectFreeUnboundIdentifierRef` in `src/ast/P.zig` to
handle comparison operators (`<`, `>`, `<=`, `>=`)
- Added comparison operators to `simplifyUnusedExpr` in
`src/ast/SideEffects.zig`
- Now correctly identifies when typeof comparisons guard against
undefined references
## Test Plan
✅ Added comprehensive test in `test/bundler/bundler_minify.test.ts` that
verifies:
- All 8 variations work correctly (4 operators × 2 operand orders)
- Cases that shouldn't be optimized are left unchanged
- Matches esbuild's behavior exactly using inline snapshots
✅ DCE test `dce/DCETypeOfCompareStringGuardCondition` now passes:
- Correctly eliminates dead code with typeof comparison patterns
- Maintains compatibility with esbuild's DCE behavior
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
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
Fixes#12548 - TypeScript syntax doesn't work in BunPlugin when using
`loader: 'ts'`
## The Problem
When creating a virtual module with `build.module()` and specifying
`loader: 'ts'`, TypeScript syntax like `import { type TSchema }` would
fail to parse with errors like:
```
error: Expected "}" but found "TSchema"
error: Expected "from" but found "}"
```
The same code worked fine when using `loader: 'tsx'`, indicating the
TypeScript parser wasn't being configured correctly for `.ts` files.
## Root Cause
The bug was caused by an enum value mismatch between C++ and Zig:
### Before (Incorrect)
- **C++ (`headers-handwritten.h`)**: `jsx=0, js=1, ts=2, tsx=3, ...`
- **Zig API (`api/schema.zig`)**: `jsx=1, js=2, ts=3, tsx=4, ...`
- **Zig Internal (`options.zig`)**: `jsx=0, js=1, ts=2, tsx=3, ...`
When a plugin returned `loader: 'ts'`, the C++ code correctly parsed the
string "ts" and set `BunLoaderTypeTS=2`. However, when this value was
passed to Zig's `Bun__transpileVirtualModule` function (which expects
`api.Loader`), the value `2` was interpreted as `api.Loader.js` instead
of `api.Loader.ts`, causing the TypeScript parser to not be enabled.
### Design Context
The codebase has two loader enum systems by design:
- **`api.Loader`**: External API interface used for C++/Zig
communication
- **`options.Loader`**: Internal representation used within Zig
The conversion between them happens via `options.Loader.fromAPI()` and
`.toAPI()` functions. The C++ layer should use `api.Loader` values since
that's what the interface functions expect.
## The Fix
1. **Aligned enum values**: Updated the `BunLoaderType` constants in
`headers-handwritten.h` to match the values in `api/schema.zig`,
ensuring C++ and Zig agree on the enum values
2. **Removed unnecessary assertion**: Removed the assertion that
`plugin_runner` must be non-null for virtual modules, as it's not
actually required for modules created via `build.module()`
3. **Added regression test**: Created comprehensive test in
`test/regression/issue/12548.test.ts` that verifies TypeScript syntax
works correctly with the `'ts'` loader
## Testing
### New Tests Pass
- ✅ `test/regression/issue/12548.test.ts` - 2 tests verifying TypeScript
type imports work with `'ts'` loader
### Existing Tests Still Pass
- ✅ `test/js/bun/plugin/plugins.test.ts` - 28 pass
- ✅ `test/bundler/bundler_plugin.test.ts` - 52 pass
- ✅ `test/bundler/bundler_loader.test.ts` - 27 pass
- ✅ `test/bundler/esbuild/loader.test.ts` - 10 pass
- ✅ `test/bundler/bundler_plugin_chain.test.ts` - 13 pass
### Manual Verification
```javascript
// This now works correctly with loader: 'ts'
Bun.plugin({
setup(build) {
build.module('hi', () => ({
contents: "import { type TSchema } from '@sinclair/typebox'",
loader: 'ts', // ✅ Works now (previously failed)
}))
},
})
```
🤖 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>
## Summary
- Fixed napi_strict_equals to use JavaScript === operator semantics
instead of Object.is()
- Added missing recv parameter validation in napi_call_function
- Fixed napi_create_array_with_length boundary handling to match Node.js
behavior
## Changes
### napi_strict_equals
- Changed from isSameValue (Object.is semantics) to isStrictEqual (===
semantics)
- Now correctly implements JavaScript strict equality: NaN !== NaN and
-0 === 0
- Added new JSC binding JSC__JSValue__isStrictEqual to support this
### napi_call_function
- Added NAPI_CHECK_ARG(env, recv) validation to match Node.js behavior
- Prevents crashes when recv parameter is null/undefined
### napi_create_array_with_length
- Fixed boundary value handling for negative and oversized lengths
- Now correctly clamps negative signed values to 0 (e.g., when size_t
0x80000000 becomes negative in i32)
- Matches Node.js V8 implementation which casts size_t to int then
clamps to min 0
## Test plan
- [x] Added comprehensive C++ tests in
test/napi/napi-app/standalone_tests.cpp
- [x] Added corresponding JavaScript tests in test/napi/napi.test.ts
- [x] Tests verify:
- Strict equality semantics (NaN, -0/0, normal values)
- Null recv parameter handling
- Array creation with boundary values (negative, oversized, edge cases)
🤖 Generated with [Claude Code](https://claude.ai/code)
## Summary
Fixes#22475
`cookie.isExpired()` was incorrectly returning `false` for cookies with
`Expires` set to Unix epoch (Thu, 01 Jan 1970 00:00:00 GMT).
## The Problem
The bug had two parts:
1. **In `Cookie::isExpired()`**: The condition `m_expires < 1`
incorrectly treated Unix epoch (0) as a session cookie instead of an
expired cookie.
2. **In `Cookie::parse()`**: When parsing date strings that evaluate to
0 (Unix epoch), the code used implicit boolean conversion which treated
0 as false, preventing the expires value from being set.
## The Fix
- Removed the `m_expires < 1` check from `isExpired()`, keeping only the
check for `emptyExpiresAtValue` to identify session cookies
- Fixed date parsing to use `std::isfinite()` instead of implicit
boolean conversion, properly handling Unix epoch (0)
## Test Plan
- Added regression test in `test/regression/issue/22475.test.ts`
covering Unix epoch and edge cases
- All existing cookie tests pass (`bun bd test test/js/bun/cookie/`)
- Manually tested the reported issue from #22475
```javascript
const cookies = [
'a=; Expires=Thu, 01 Jan 1970 00:00:00 GMT',
'b=; Expires=Thu, 01 Jan 1970 00:00:01 GMT'
];
for (const _cookie of cookies) {
const cookie = new Bun.Cookie(_cookie);
console.log(cookie.name, cookie.expires, cookie.isExpired());
}
```
Now correctly outputs:
```
a 1970-01-01T00:00:00.000Z true
b 1970-01-01T00:00:01.000Z true
```
🤖 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>
### What does this PR do?
The constructor was using `isUtf8` instead of `isAscii`.
Instead of this change maybe we should remove the constructors for
`isAscii` and `isUtf8`. It looks like we do this for most native
functions, but would be more breaking than correcting the current bug.
### How did you verify your code works?
Added a test
### What does this PR do?
Fix request body streaming in node-fetch wrapper.
### How did you verify your code works?
Added a test that previously failed
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
This PR implements the `--workspaces` flag for the `bun run` command,
allowing scripts to be run in all workspace packages as defined in the
`"workspaces"` field in package.json.
Fixes the infinite loop issue reported in
https://github.com/threepointone/bun-workspace-bug-repro
## Changes
- Added `--workspaces` flag to run scripts in all workspace packages
- Added `--if-present` flag to gracefully skip packages without the
script
- Root package is excluded when using `--workspaces` to prevent infinite
recursion
- Added comprehensive tests for the new functionality
## Usage
```bash
# Run "test" script in all workspace packages
bun run --workspaces test
# Skip packages that don't have the script
bun run --workspaces --if-present build
# Combine with filters
bun run --filter="@scope/*" test
```
## Behavior
The `--workspaces` flag must come **before** the script name (matching
npm's behavior):
- ✅ `bun run --workspaces test`
- ❌ `bun run test --workspaces` (treated as passthrough to script)
## Test Plan
- [x] Added test cases in `test/cli/run/workspaces.test.ts`
- [x] Verified fix for infinite loop issue in
https://github.com/threepointone/bun-workspace-bug-repro
- [x] Tested with `--if-present` flag
- [x] All tests pass locally
🤖 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: Dylan Conway <dylan.conway567@gmail.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
Fixes compatibility issue with Node.js libraries that use
`Object.assign(promise, childProcess)` pattern, specifically `tinyspawn`
(used by `youtube-dl-exec`).
## Problem
In Node.js, child process stdio properties (`stdin`, `stdout`, `stderr`,
`stdio`) are enumerable own properties that can be copied by
`Object.assign()`. In Bun, they were non-enumerable getters on the
prototype, causing `Object.assign()` to fail copying them.
This broke libraries like:
- `tinyspawn` - uses `Object.assign(promise, childProcess)` to merge
properties
- `youtube-dl-exec` - depends on tinyspawn internally
## Solution
Make stdio properties enumerable own properties during spawn while
preserving:
- ✅ Lazy initialization (streams created only when accessed)
- ✅ Original getter functionality and caching
- ✅ Performance (minimal overhead)
## Testing
- Added comprehensive regression tests
- Verified compatibility with `tinyspawn` and `youtube-dl-exec`
- Existing child_process tests still pass
## Related
- Fixes: https://github.com/microlinkhq/youtube-dl-exec/issues/246🤖 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>
## Summary
This PR implements `perf_hooks.monitorEventLoopDelay()` for Node.js
compatibility, enabling monitoring of event loop delays and collection
of performance metrics via histograms.
Fixes#17650
## Implementation Details
### JavaScript Layer (`perf_hooks.ts`)
- Added `IntervalHistogram` class with:
- `enable()` / `disable()` methods with proper state tracking
- `reset()` method to clear histogram data
- Properties: `min`, `max`, `mean`, `stddev`, `exceeds`, `percentiles`
- `percentile(p)` method with validation
- Full input validation matching Node.js behavior (TypeError vs
RangeError)
### C++ Bindings (`JSNodePerformanceHooksHistogramPrototype.cpp`)
- `jsFunction_monitorEventLoopDelay` - Creates histogram for event loop
monitoring
- `jsFunction_enableEventLoopDelay` - Enables monitoring and starts
timer
- `jsFunction_disableEventLoopDelay` - Disables monitoring and stops
timer
- `JSNodePerformanceHooksHistogram_recordDelay` - Records delay
measurements
### Zig Implementation (`EventLoopDelayMonitor.zig`)
- Embedded `EventLoopTimer` that fires periodically based on resolution
- Tracks last fire time and calculates delay between expected vs actual
- Records delays > 0 to the histogram
- Integrates seamlessly with existing Timer system
## Testing
✅ All tests pass:
- Custom test suite with 8 comprehensive tests
- Adapted Node.js core test for full compatibility
- Tests cover enable/disable behavior, percentiles, error handling, and
delay recording
## Test plan
- [x] Run `bun test
test/js/node/perf_hooks/test-monitorEventLoopDelay.test.js`
- [x] Run adapted Node.js test
`test/js/node/test/sequential/test-performance-eventloopdelay-adapted.test.js`
- [x] Verify proper error handling for invalid arguments
- [x] Confirm delay measurements are recorded 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>
### What does this PR do?
update harness.ts
### How did you verify your code works?
CI
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
- Fixed embedded resource path resolution when using
`Bun.build({compile: true})` API for Windows targets
- Fixed relative path handling for `--outfile` parameter in compilation
## Details
This PR fixes two regressions introduced after v1.2.19 in the
`Bun.build({compile})` feature:
### 1. Embedded Resource Path Issue
When using `Bun.build({compile: true})`, the module prefix wasn't being
set to the target-specific base path, causing embedded resources to fail
with "ENOENT: no such file or directory" errors on Windows (e.g.,
`B:/~BUN/root/` paths).
**Fix**: Ensure the target-specific base path is used as the module
prefix in `doCompilation`, matching the behavior of the CLI build
command.
### 2. PE Metadata with Relative Paths
When using relative paths with `--outfile` (e.g.,
`--outfile=forward/slash` or `--outfile=back\\slash`), the compilation
would fail with "FailedToLoadExecutable" error.
**Fix**: Ensure relative paths are properly converted to absolute paths
before PE metadata operations.
## Test Plan
- [x] Tested `Bun.build({compile: true})` with embedded resources
- [x] Tested relative path handling with nested directories
- [x] Verified compiled executables run 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: Zack Radisic <zack@theradisic.com>
### What does this PR do?
Allow upgrade to websockets using fetch
This will avoid hanging in http.request and is a step necessary to
implement the upgrade event in the node:http client.
Changes in node:http need to be made in another PR to support 'upgrade'
event (see https://github.com/oven-sh/bun/pull/22412)
### How did you verify your code works?
Test
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
- Automatically removes the "Original Filename" field from Windows
single-file executables
- Prevents compiled executables from incorrectly showing "bun.exe" as
their original filename
- Adds comprehensive tests to verify the field is properly removed
## Problem
When creating single-file executables on Windows, the "Original
Filename" metadata field was showing "bun.exe" regardless of the actual
executable name. This was confusing for users and incorrect from a
metadata perspective.
## Solution
Modified `rescle__setWindowsMetadata()` in
`src/bun.js/bindings/windows/rescle-binding.cpp` to automatically clear
the `OriginalFilename` field by setting it to an empty string whenever
Windows metadata is updated during executable creation.
## Test Plan
- [x] Added tests in `test/bundler/compile-windows-metadata.test.ts` to
verify:
- Original Filename field is empty in basic compilation
- Original Filename field remains empty even when all other metadata is
set
- [x] Verified cross-platform compilation with `bun run zig:check-all` -
all platforms compile successfully
The tests will run on Windows CI to verify the behavior is correct.
🤖 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>
### 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?
Enable connecting to different databases for Redis.
### How did you verify your code works?
Unit tests were added.
### Credits
Thank you very much @HeyItsBATMAN for your original PR. I've made
extremely slight changes to your PR. I apologize for it taking so long
to review and merge your PR.
---------
Co-authored-by: Kai Niebes <kai.niebes@outlook.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
Fixes#18413 - Empty chunked gzip responses were causing `Decompression
error: ShortRead`
## The Issue
When a server sends an empty response with `Content-Encoding: gzip` and
`Transfer-Encoding: chunked`, Bun was throwing a `ShortRead` error. This
occurred because the code was checking if `avail_in == 0` (no input
data) and immediately returning an error, without attempting to
decompress what could be a valid empty gzip stream.
## The Fix
Instead of checking `avail_in == 0` before calling `inflate()`, we now:
1. Always call `inflate()` even when `avail_in == 0`
2. Check the return code from `inflate()`
3. If it returns `BufError` with `avail_in == 0`, then we truly need
more data and return `ShortRead`
4. If it returns `StreamEnd`, it was a valid empty gzip stream and we
finish successfully
This approach correctly distinguishes between "no data yet" and "valid
empty gzip stream".
## Why This Works
- A valid empty gzip stream still has headers and trailers (~20 bytes)
- The zlib `inflate()` function can handle empty streams correctly
- `BufError` with `avail_in == 0` specifically means "need more input
data"
## Test Plan
✅ Added regression test in `test/regression/issue/18413.test.ts`
covering:
- Empty chunked gzip response
- Empty non-chunked gzip response
- Empty chunked response without gzip
✅ Verified all existing gzip-related tests still pass
✅ Tested with the original failing case from the issue
🤖 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: Ciro Spaciari <ciro.spaciari@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
### What does this PR do?
Actually run the Timer/TimerZ tests in CI and disable
describeWithContainer in macos
### How did you verify your code works?
CI
---------
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>
## Summary
- Fixes binary format handling for PostgreSQL TIME and TIMETZ data types
- Resolves issue where time values were returned as garbled binary data
with null bytes
## Problem
When PostgreSQL returns TIME or TIMETZ columns in binary format, Bun.sql
was not properly converting them from their binary representation
(microseconds since midnight) to readable time strings. This resulted in
corrupted output like `\u0000\u0000\u0000\u0000\u0076` instead of proper
time values like `09:00:00`.
## Solution
Added proper binary format decoding for:
- **TIME (OID 1083)**: Converts 8 bytes of microseconds since midnight
to `HH:MM:SS.ffffff` format
- **TIMETZ (OID 1266)**: Converts 8 bytes of microseconds + 4 bytes of
timezone offset to `HH:MM:SS.ffffff±HH:MM` format
## Changes
- Added binary format handling in `src/sql/postgres/DataCell.zig` for
TIME and TIMETZ types
- Added `InvalidTimeFormat` error to `AnyPostgresError` error set
- Properly formats microseconds with trailing zero removal
- Handles timezone offsets correctly (PostgreSQL uses negative values
for positive UTC offsets)
## Test plan
Added comprehensive tests in `test/js/bun/sql/postgres-time.test.ts`:
- [x] TIME and TIMETZ column values with various formats
- [x] NULL handling
- [x] Array types (TIME[] and TIMETZ[])
- [x] JSONB structures containing time strings
- [x] Verification that no binary/null bytes appear in output
All tests pass locally with PostgreSQL.
🤖 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>
## Summary
Fixes#11029 - `crypto.verify()` now correctly handles null/undefined
algorithm parameter for RSA keys, matching Node.js behavior.
## Problem
When calling `crypto.verify()` with a null or undefined algorithm
parameter, Bun was throwing an error:
```
error: error:06000077:public key routines:OPENSSL_internal:NO_DEFAULT_DIGEST
```
## Root Cause
The issue stems from the difference between OpenSSL (used by Node.js)
and BoringSSL (used by Bun):
- **OpenSSL v3**: Automatically provides SHA256 as the default digest
for RSA keys when NULL is passed
- **BoringSSL**: Returns an error when NULL digest is passed for RSA
keys
## Solution
This fix explicitly sets SHA256 as the default digest for RSA keys when
no algorithm is specified, achieving OpenSSL-compatible behavior.
## OpenSSL v3 Source Code Analysis
I traced through the OpenSSL v3 source code to understand exactly how it
handles null digests:
### 1. Entry Point (`crypto/evp/m_sigver.c`)
When `EVP_DigestSignInit` or `EVP_DigestVerifyInit` is called with NULL
digest:
```c
// Lines 215-220 in do_sigver_init function
if (mdname == NULL && !reinit) {
if (evp_keymgmt_util_get_deflt_digest_name(tmp_keymgmt, provkey,
locmdname,
sizeof(locmdname)) > 0) {
mdname = canon_mdname(locmdname);
}
}
```
### 2. Default Digest Query (`crypto/evp/keymgmt_lib.c`)
```c
// Lines 533-571 in evp_keymgmt_util_get_deflt_digest_name
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST,
mddefault, sizeof(mddefault));
if (!evp_keymgmt_get_params(keymgmt, keydata, params))
return 0;
```
### 3. RSA Provider Implementation
(`providers/implementations/keymgmt/rsa_kmgmt.c`)
```c
// Line 54: Define the default
#define RSA_DEFAULT_MD "SHA256"
// Lines 351-355: Return it for RSA keys
if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST)) != NULL
&& (rsa_type != RSA_FLAG_TYPE_RSASSAPSS
|| ossl_rsa_pss_params_30_is_unrestricted(pss_params))) {
if (!OSSL_PARAM_set_utf8_string(p, RSA_DEFAULT_MD))
return 0;
}
```
## Implementation Details
The fix includes extensive documentation in the source code explaining:
- The OpenSSL v3 mechanism with specific file paths and line numbers
- Why BoringSSL behaves differently
- Why Ed25519/Ed448 keys are handled differently (they don't need a
digest)
## Test Plan
✅ Added comprehensive regression test in
`test/regression/issue/11029-crypto-verify-null-algorithm.test.ts`
✅ Tests cover:
- RSA keys with null/undefined algorithm
- Ed25519 keys with null algorithm
- Cross-verification between null and explicit SHA256
- `createVerify()` compatibility
✅ All tests pass and behavior matches Node.js
## Verification
```bash
# Test with Bun
bun test test/regression/issue/11029-crypto-verify-null-algorithm.test.ts
# Compare with Node.js behavior
node -e "const crypto = require('crypto');
const {publicKey, privateKey} = crypto.generateKeyPairSync('rsa', {modulusLength: 2048});
const data = Buffer.from('test');
const sig = crypto.sign(null, data, privateKey);
console.log('Node.js verify with null:', crypto.verify(null, data, publicKey, sig));"
```
🤖 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>
## Summary
- Fixes crash when running shell commands with variable assignments
piped to other commands
- Resolves#15714
## Problem
The shell was crashing with "Invalid tag" error when running commands
like:
```bash
bun exec "FOO=bar BAR=baz | echo hi"
```
## Root Cause
In `Pipeline.zig`, the `cmds` array was allocated with the wrong size:
- It used `node.items.len` (which includes assignments)
- But only filled entries for actual commands (assignments are skipped
in pipelines)
- This left uninitialized memory that caused crashes when accessed
## Solution
Changed the allocation to use the correct `cmd_count` instead of
`node.items.len`:
```zig
// Before
this.cmds = if (cmd_count >= 1) bun.handleOom(this.base.allocator().alloc(CmdOrResult, this.node.items.len)) else null;
// After
this.cmds = if (cmd_count >= 1) bun.handleOom(this.base.allocator().alloc(CmdOrResult, cmd_count)) else null;
```
## Test plan
✅ Added comprehensive regression test in
`test/regression/issue/15714.test.ts` that:
- Tests the exact case from the issue
- Tests multiple assignments
- Tests single assignment
- Tests assignments in middle of pipeline
- Verified test fails on main branch (exit code 133 = SIGTRAP)
- Verified test passes with fix
🤖 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: Zack Radisic <56137411+zackradisic@users.noreply.github.com>
## Summary
This PR refactors the `Buffer.concat` implementation to use modern C++
spans for safer memory operations and adds proper error handling for
oversized buffers.
## Changes
- **Use spans instead of raw pointers**: Replaced pointer arithmetic
with `typedSpan()` and `span()` methods for safer memory access
- **Add MAX_ARRAY_BUFFER_SIZE check**: Added explicit check with a
descriptive error message when attempting to create buffers larger than
JavaScriptCore's limit (4GB)
- **Improve loop logic**: Changed loop counter from `int` to `size_t`
and simplified the iteration using span sizes
- **Enhanced test coverage**: Updated tests to verify the new error
message and added comprehensive test cases for various Buffer.concat
scenarios
## Test Plan
All existing tests pass, plus added new tests:
- ✅ Error handling for oversized buffers
- ✅ Normal buffer concatenation
- ✅ totalLength parameter handling (exact, larger, smaller)
- ✅ Empty array handling
- ✅ Single buffer handling
```bash
./build/debug/bun-debug test test/js/node/buffer-concat.test.ts
# Result: 6 pass, 0 fail
```
🤖 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>