Implements the 'dependencies' lifecycle script that runs when the dependency
tree is modified during bun install.
Behavior:
- Runs for root package when dependencies change (did_meta_hash_change)
- Runs for workspace packages when their dependencies change
- Does NOT run on subsequent installs when nothing changes
This improves on npm which only runs the dependencies script for the root
package and ignores workspace packages entirely. Bun's implementation is
consistent with how other lifecycle scripts like postinstall work.
### What does this PR do?
This was creating `Zig::FFIFunction` when we could instead use a plain
`JSC::JSFunction`
### How did you verify your code works?
Added a test
### What does this PR do?
`blob.stream(undefined)`
### How did you verify your code works?
Added a test
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Fixes ENG-21490
### How did you verify your code works?
Added a test that would previously fail due to timeout. It also confirms
the parsed result is correct.
---------
Co-authored-by: taylor.fish <contact@taylor.fish>
### What does this PR do?
Makes sure we are creating error messages with an allocator that will
not `deinit` at the end of function scope on error.
fixes ENG-21528
### How did you verify your code works?
Added a test
## Summary
Implements `--no-env-file` CLI flag and bunfig configuration options to
disable automatic `.env` file loading at runtime and in the bundler.
## Motivation
Users may want to disable automatic `.env` file loading for:
- Production environments where env vars are managed externally
- CI/CD pipelines where .env files should be ignored
- Testing scenarios where explicit env control is needed
- Security contexts where .env files should not be trusted
## Changes
### CLI Flag
- Added `--no-env-file` flag that disables loading of default .env files
- Still respects explicit `--env-file` arguments for intentional env
loading
### Bunfig Configuration
Added support for disabling .env loading via `bunfig.toml`:
- `env = false` - disables default .env file loading
- `env = null` - disables default .env file loading
- `env.file = false` - disables default .env file loading
- `env.file = null` - disables default .env file loading
### Implementation
- Added `disable_default_env_files` field to `api.TransformOptions` with
serialization support
- Added `disable_default_env_files` field to `options.Env` struct
- Implemented `loadEnvConfig` in bunfig parser to handle env
configuration
- Wired up flag throughout runtime and bundler code paths
- Preserved package.json script runner behavior (always skips default
.env files)
## Tests
Added comprehensive test suite (`test/cli/run/no-envfile.test.ts`) with
9 tests covering:
- `--no-env-file` flag with `.env`, `.env.local`,
`.env.development.local`
- Bunfig configurations: `env = false`, `env.file = false`, `env = true`
- `--no-env-file` with `-e` eval flag
- `--no-env-file` combined with `--env-file` (explicit files still load)
- Production mode behavior
All tests pass with debug bun and fail with system bun (as expected).
## Example Usage
```bash
# Disable all default .env files
bun --no-env-file index.js
# Disable defaults but load explicit file
bun --no-env-file --env-file .env.production index.js
# Disable via bunfig.toml
cat > bunfig.toml << 'CONFIG'
env = false
CONFIG
bun index.js
```
## Files Changed
- `src/cli/Arguments.zig` - CLI flag parsing
- `src/api/schema.zig` - API schema field with encode/decode
- `src/options.zig` - Env struct field and wiring
- `src/bunfig.zig` - Config parsing with loadEnvConfig
- `src/transpiler.zig` - Runtime wiring
- `src/bun.js.zig` - Runtime wiring
- `src/cli/exec_command.zig` - Runtime wiring
- `src/cli/run_command.zig` - Preserved package.json script runner
behavior
- `test/cli/run/no-envfile.test.ts` - Comprehensive test suite
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
### What does this PR do?
Ensures strings that would parse as a number with leading zeroes aren't
emitted without quotes.
fixes#23691
### How did you verify your code works?
Added a test
### What does this PR do?
The assertion was too strict.
This pr changes to assertion to allow multiple of the same dependency id
to be present. Also changes all the assertions to debug assertions.
fixes#24510
### How did you verify your code works?
Manually, and added a new test
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Marko Vejnovic <marko@bun.com>
Fixes ENG-21481
Updates ci_info to include more CIs. It makes it codegen the ci
detection based on the json from the ci-info package. Also it supports
setting CI=true to force ci detected.
---------
Co-authored-by: pfg <pfg@pfg.pw>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Fixes `bun pm ls --all` crash with unresolved optional peer
dependencies.
Fixes `bun pm ls` crash with empty lockfiles.
Fixes#24502
### How did you verify your code works?
Added a test for both crashes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Fixes https://github.com/oven-sh/bun/issues/24385
### How did you verify your code works?
Confirmed that the test added in the first commit fails on mainline
`bun` and is fixed in this PR.
---------
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>
Fixes#23865, Fixes ENG-21446
Previously, a termination exception would be thrown. We didn't handle it
properly and eventually it got caught by a `catch @panic()` handler.
Now, no termination exception is thrown.
```
drainMicrotasksWithGlobal calls JSC__JSGlobalObject__drainMicrotasks
JSC__JSGlobalObject__drainMicrotasks returns m_terminationException
-> drainMicrotasksWithGlobal
-> event_loop.zig:exit, which catches the error and discards it
-> ...
```
For workers, we will need to handle termination exceptions in this
codepath.
~~Previously, it would see the exception, call
reportUncaughtExceptoinAtEventLoop, but the exception would still
survive and return out from the catch scope. You're not supposed to
still have an exception signaled at the exit of a catch scope. Exception
checker may not have caught it because maybe the branch wasn't taken.~~
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
pulled out of https://github.com/oven-sh/bun/pull/21809
- brings the ASAN behavior on linux closer in sync with macos
- fixes some tests to also pass in node
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
### What does this PR do?
Fixes#24387
### How did you verify your code works?
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Marko Vejnovic <marko@bun.com>
## Summary
Fixes a segfault that occurred when calling `process.dlopen` with
`null`, `undefined`, or primitive values for `exports`.
Previously, this would cause a crash at address `0x00000000` in
`node_module_register` due to dereferencing an uninitialized
`strongExportsObject`.
## Changes
- Modified `src/bun.js/bindings/v8/node.cpp` to use JSC's `toObject()`
instead of manual type checking
- This matches Node.js `ToObject()` behavior:
- Throws `TypeError` for `null`/`undefined`
- Creates wrapper objects for primitives
- Preserves existing objects
## Test Plan
Added `test/js/node/process/dlopen-non-object-exports.test.ts` with
three test cases:
- Null exports (should throw)
- Undefined exports (should throw)
- Primitive exports (should create wrapper)
All tests pass with the fix.
## Related Issue
Fixes the first bug discovered in the segfault investigation.
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Fixes incorrect JWK "d" field length for exported elliptic curve private
keys. The "d" field is now correctly padded to ensure RFC 7518
compliance.
## Problem
When exporting EC private keys to JWK format, the "d" field would
sometimes be shorter than required by RFC 7518 because
`convertToBytes()` doesn't pad the result when the BIGNUM has leading
zeros. This caused incompatibility with Chrome's strict validation,
though Node.js and Firefox would accept the malformed keys.
Expected lengths per RFC 7518:
- P-256: 32 bytes → 43 base64url characters
- P-384: 48 bytes → 64 base64url characters
- P-521: 66 bytes → 88 base64url characters
## Solution
Changed `src/bun.js/bindings/webcrypto/CryptoKeyECOpenSSL.cpp:420` to
use `convertToBytesExpand(privateKey, keySizeInBytes)` instead of
`convertToBytes(privateKey)`, ensuring the private key is padded with
leading zeros when necessary. This matches the behavior already used for
the x and y public key coordinates.
## Test plan
- ✅ Added regression test in `test/regression/issue/24399.test.ts` that
generates multiple keys for each curve and verifies correct "d" field
length
- ✅ Test fails with `USE_SYSTEM_BUN=1 bun test` (reproduces the bug)
- ✅ Test passes with `bun bd test` (verifies the fix)
- ✅ Existing crypto tests pass
Fixes#24399🤖 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>
### What does this PR do?
Refactored NAPI property and element access to use inline methods and
improved error handling. Added comprehensive tests for default value
behavior and numeric string key operations in NAPI, ensuring correct
handling of missing properties, integer keys, and property deletion.
Updated TypeScript tests to cover new scenarios.
### How did you verify your code works?
Tests
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
## Summary
Fixes 100% CPU usage on idle WebSocket servers between bun-v1.2.23 and
bun-v1.3.0.
Many users reported WebSocket server CPU usage jumping to 100% on idle
connections after upgrading to v1.3.0. Investigation revealed a missing
`poll_ref.unref()` call in the WebSocket upgrade path.
## Root Cause
In commit 625e537f5d (#23348), the `OnBeforeOpen` callback mechanism was
removed as part of refactoring the WebSocket upgrade process. However,
this callback contained a critical cleanup step:
```zig
defer ctx.this.poll_ref.unref(ctx.globalObject.bunVM());
```
When a `NodeHTTPResponse` is created, `poll_ref.ref()` is called (line
314) to keep the event loop alive while handling the HTTP request. After
a WebSocket upgrade, the HTTP response object is no longer relevant and
its `poll_ref` must be unref'd to indicate the request processing is
complete.
Without this unref, the event loop maintains an active reference even
after the upgrade completes, causing the CPU to spin at 100% waiting for
events on what should be an idle connection.
## Changes
- Added `poll_ref.unref()` call in `NodeHTTPResponse.upgrade()` after
setting the `upgraded` flag
- Added regression test to verify event loop properly exits after
WebSocket upgrade
## Test Plan
- [x] Code compiles successfully
- [x] Existing WebSocket tests pass
- [x] Manual testing confirms CPU usage returns to normal on idle
WebSocket connections
## Related Issues
Fixes issue reported by users between bun-v1.2.23 and bun-v1.3.0
regarding 100% CPU usage on idle WebSocket servers.
🤖 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: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Adds `"configVersion"` to bun.lock(b). The version will be used to keep
default settings the same if they would be breaking across bun versions.
fixes ENG-21389
fixes ENG-21388
### How did you verify your code works?
TODO:
- [ ] new project
- [ ] existing project without configVersion
- [ ] existing project with configVersion
- [ ] same as above but with bun.lockb
- [ ] configVersion@0 defaults to hoisted linker
- [ ] new projects use isolated linker
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
This PR introduces a new postinstall optimization system that
significantly reduces the need to run lifecycle scripts for certain
packages by intelligently handling their requirements at install time.
## Key Features
### 1. Native Binlink Optimization
When packages like `esbuild` ship platform-specific binaries as optional
dependencies, we now:
- Detect the native binlink pattern (enabled by default for `esbuild`)
- Find the matching platform-specific dependency based on target CPU/OS
- Link binaries directly from the platform-specific package (e.g.,
`@esbuild/darwin-arm64`)
- Fall back gracefully if the platform-specific package isn't found
**Result**: No postinstall scripts needed for esbuild and similar
packages.
### 2. Lifecycle Script Skipping
For packages like `sharp` that run heavy postinstall scripts:
- Skip lifecycle scripts entirely (enabled by default for `sharp`)
- Prevents downloading large binaries or compiling native code
unnecessarily
- Reduces install time and potential failures in restricted environments
## Configuration
Both features can be configured via `package.json`:
```json
{
"nativeDependencies": ["esbuild", "my-custom-package"],
"ignoreScripts": ["sharp", "another-package"]
}
```
Set to empty arrays to disable defaults:
```json
{
"nativeDependencies": [],
"ignoreScripts": []
}
```
Environment variable overrides:
- `BUN_FEATURE_FLAG_DISABLE_NATIVE_DEPENDENCY_LINKER=1` - disable native
binlink
- `BUN_FEATURE_FLAG_DISABLE_IGNORE_SCRIPTS=1` - disable script ignoring
## Implementation Details
### Core Components
- **`postinstall_optimizer.zig`**: New file containing the optimizer
logic
- `PostinstallOptimizer` enum with `native_binlink` and `ignore`
variants
- `List` type to track optimization strategies per package hash
- Defaults for `esbuild` (native binlink) and `sharp` (ignore)
- **`Bin.Linker` changes**: Extended to support separate target paths
- `target_node_modules_path`: Where to find the actual binary
- `target_package_name`: Name of the package containing the binary
- Fallback logic when native binlink optimization fails
### Modified Components
- **PackageInstaller.zig**: Checks optimizer before:
- Enqueueing lifecycle scripts
- Linking binaries (with platform-specific package resolution)
- **isolated_install/Installer.zig**: Similar checks for isolated linker
mode
- `maybeReplaceNodeModulesPath()` resolves platform-specific packages
- Retry logic without optimization on failure
- **Lockfile**: Added `postinstall_optimizer` field to persist
configuration
## Changes Included
- Updated `esbuild` from 0.21.5 to 0.25.11 (testing with latest)
- VS Code launch config updates for debugging install with new flags
- New feature flags in `env_var.zig`
## Test Plan
- [x] Existing install tests pass
- [ ] Test esbuild install without postinstall scripts running
- [ ] Test sharp install with scripts skipped
- [ ] Test custom package.json configuration
- [ ] Test fallback when platform-specific package not found
- [ ] Test feature flag overrides
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Native binlink optimization: installs platform-specific binaries when
available, with a safe retry fallback and verbose logging option.
* Per-package postinstall controls to optionally skip lifecycle scripts.
* New feature flags to disable native binlink optimization and to
disable lifecycle-script ignoring.
* **Tests**
* End-to-end tests and test packages added to validate native binlink
behavior across install scenarios and linker modes.
* **Documentation**
* Bench README and sample app migrated to a Next.js-based setup.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
Fixes Next.js 16 + React Compiler build failure when using Bun runtime.
## Issue
When `Module._resolveFilename` was overridden (e.g., by Next.js's
require-hook), Bun was not passing the `options` parameter (which
contains `paths`) to the override function. This caused resolution
failures when the override tried to use custom resolution paths.
Additionally, when `Module._resolveFilename` was called directly with
`options.paths`, Bun was ignoring the paths parameter and using default
resolution.
## Root Causes
1. In `ImportMetaObject.cpp`, when calling an overridden
`_resolveFilename` function, the options object with paths was not being
passed as the 4th argument.
2. In `NodeModuleModule.cpp`, `jsFunctionResolveFileName` was calling
`Bun__resolveSync` without extracting and using the `options.paths`
parameter.
## Solution
1. In `ImportMetaObject.cpp`: When `userPathList` is provided, construct
an options object with `{paths: userPathList}` and pass it as the 4th
argument to the overridden `_resolveFilename` function.
2. In `NodeModuleModule.cpp`: Extract `options.paths` from the 4th
argument and call `Bun__resolveSyncWithPaths` when paths are provided,
instead of always using `Bun__resolveSync`.
## Reproduction
Before this fix, running:
```bash
bun --bun next build --turbopack
```
on a Next.js 16 app with React Compiler enabled would fail with:
```
Cannot find module './node_modules/babel-plugin-react-compiler'
```
## Testing
- Added comprehensive tests for `Module._resolveFilename` with
`options.paths`
- Verified Next.js 16 + React Compiler + Turbopack builds successfully
with Bun
- All 5 new tests pass with the fix, 3 fail without it
- All existing tests continue to pass
## Files Changed
- `src/bun.js/bindings/ImportMetaObject.cpp` - Pass options to override
- `src/bun.js/modules/NodeModuleModule.cpp` - Handle options.paths in
_resolveFilename
- `test/js/node/module/module-resolve-filename-paths.test.js` - New test
suite
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
### What does this PR do?
fixes#23901
### How did you verify your code works?
with a test
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
Fixes a bug where `bun update --interactive` only updated `package.json`
but didn't actually install the updated packages. Users had to manually
run `bun install` afterwards.
## Root Cause
The bug was in `savePackageJson()` in
`src/cli/update_interactive_command.zig`:
1. The function wrote the updated `package.json` to disk
2. But it **didn't update the in-memory cache**
(`WorkspacePackageJSONCache`)
3. When `installWithManager()` ran, it called `getWithPath()` which
returned the **stale cached version**
4. So the installation proceeded with the old dependencies
## The Fix
Update the cache entry after writing to disk (line 116):
```zig
package_json.*.source.contents = new_package_json_source;
```
This matches the behavior in `updatePackageJSONAndInstall.zig` line 269.
## Test Plan
Added comprehensive regression tests in
`test/cli/update_interactive_install.test.ts`:
- ✅ Verifies that `package.json` is updated
- ✅ Verifies that `node_modules` is updated (this was failing before the
fix)
- ✅ Tests both normal update and `--latest` flag
- ✅ Compares installed version to confirm packages were actually
installed
Run tests with:
```bash
bun bd test test/cli/update_interactive_install.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: Jarred Sumner <jarred@jarredsumner.com>