Compare commits

...

348 Commits

Author SHA1 Message Date
Claude Bot
8612285e3d fix: preserve stack traces for errors after structuredClone
After calling structuredClone() on an Error object, the error would lose
its internal JSC stack trace. When console.error formatted the cloned error,
it fell back to parsing the .stack string property. However, the V8-style
stack trace parser would stop early when encountering frames without
function names (e.g., top-level code execution frames).

These anonymous frames are formatted as "at /path/to/file:line:column"
without parentheses, which the parser previously treated as invalid and
stopped parsing.

This fix updates the V8StackTraceIterator to properly handle frames
without function names by parsing them as anonymous frames with just
the source location information.
2025-11-11 05:01:14 +00:00
github-actions[bot]
0a307ed880 deps: update sqlite to 3.51.0 (#24530) 2025-11-09 01:09:25 -08:00
robobun
b4f85c8866 Update docs example versions to 1.3.2 (#24522)
## Summary

Updated all example version placeholders in documentation from 1.3.1 and
1.2.20 to 1.3.2.

## Changes

Updated version examples in:
- Installation examples (Linux/macOS and Windows install commands)
- Package manager output examples (`bun install`, `bun publish`, `bun
pm` commands)
- Test runner output examples
- Spawn/child process output examples
- Fetch User-Agent header examples in debugging docs
- `Bun.version` API example

## Notes

- Historical version references (e.g., "As of Bun v1.x.x..." or "Bun
v1.x.x+ required") were intentionally **preserved** as they document
when features were introduced
- Generic package.json version examples (non-Bun package versions) were
**preserved**
- Only example outputs and code snippets showing current Bun version
were updated

## Files Changed (13 total)

- `docs/installation.mdx`
- `docs/guides/install/from-npm-install-to-bun-install.mdx`
- `docs/guides/install/add-peer.mdx`
- `docs/bundler/html-static.mdx` (6 occurrences)
- `docs/test/dom.mdx`
- `docs/pm/cli/publish.mdx`
- `docs/pm/cli/pm.mdx`
- `docs/guides/test/snapshot.mdx` (2 occurrences)
- `docs/guides/ecosystem/nuxt.mdx`
- `docs/guides/util/version.mdx`
- `docs/runtime/debugger.mdx` (3 occurrences)
- `docs/runtime/networking/fetch.mdx`
- `docs/runtime/child-process.mdx`

**Total:** 23 version references updated

🤖 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: Michael H <git@riskymh.dev>
2025-11-09 16:20:04 +11:00
Michael H
614e8292e3 docs: fix discord invite (#24498)
### What does this PR do?

we don't have the discord vanity invite

### How did you verify your code works?
2025-11-08 21:09:57 -08:00
Michael H
3829b6d0aa add .mdx to .gitattributes (#24525)
### What does this PR do?

### How did you verify your code works?
2025-11-08 20:56:38 -08:00
Meghan Denny
f30e3951a7 Bump 2025-11-07 23:58:34 -08:00
Michael H
b131639cc5 ci: run modified tests first (#24463)
Co-authored-by: Meghan Denny <meghan@bun.com>
2025-11-07 21:49:58 -08:00
Jarred Sumner
b9b07172aa Update package.json 2025-11-07 21:22:53 -08:00
Marko Vejnovic
02b474415d bug(ENG-21479): Fix Valkey URL Parsing (#24458)
### 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>
2025-11-07 21:18:07 -08:00
Dylan Conway
de9a38bd11 fix(install): create bun.lock instead of bun.lockb if npm/yarn/pnpm migration fails (#24494)
### 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>
2025-11-07 20:58:44 -08:00
Marko Vejnovic
2e57c6bf95 fix(ENG-21492): Fix private git+ssh installs (#24490)
### What does this PR do?

This PR is the fix-only version of
https://github.com/oven-sh/bun/pull/24486. Unfortunately due to
complexity setting up all CI agents to ping private git repos, I was
unable to get CI passing there.

### How did you verify your code works?

I ran this:

```
marko@fedora:~/Desktop/bun-4$ bun add git+ssh://git@github.com:oven-sh/private-install-test-repo.git#5b37e644a2ef23fad0da4027042f01b194b179e8
bun add v1.3.2-canary.108 (44402ad2)
  🔍 Resolving [1/1] error: "git clone" for "git+ssh://git@github.com:oven-sh/private-install-test-repo.git#5b37e644a2ef23fad0da4027042f01b194b179e8" failed
error: InstallFailed cloning repository for git+ssh://git@github.com:oven-sh/private-install-test-repo.git#5b37e644a2ef23fad0da4027042f01b194b179e8
error: git+ssh://git@github.com:oven-sh/private-install-test-repo.git#5b37e644a2ef23fad0da4027042f01b194b179e8 failed to resolve
```

followed by

```
marko@fedora:~/Desktop/bun-4$ BUN_DEBUG_QUIET_LOGS=1 ./build/debug/bun-debug add git+ssh://git@github.com:oven-sh/private-install-test-repo.git#5b37e644a2ef23fad0da4027042f01b194b179e8
bun add v1.3.2 (0db90b25)

installed private-install-test-repo@git+ssh://git@github.com:oven-sh/private-install-test-repo.git#5b37e644a2ef23fad0da4027042f01b194b179e8

[1.61s] done
```

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2025-11-07 19:56:34 -08:00
Lydia Hallie
35a57ff008 Add Upstash guide with Bun Redis (#24493) 2025-11-07 18:32:19 -08:00
Meghan Denny
7a931d5b26 [publish images] 2025-11-07 16:41:57 -08:00
Meghan Denny
2b42be9dcc [publish images] 2025-11-07 16:40:13 -08:00
Meghan Denny
e6be28b8d4 [publish images] 2025-11-07 16:37:57 -08:00
Meghan Denny
d0a1984a20 ci: skip running tests when a PR only changes docs (#24459)
fixes https://linear.app/oven/issue/ENG-21489
2025-11-07 15:52:37 -08:00
Lydia Hallie
1896c75d78 Add deploy guides for AWS Lambda, Google Run, DigitalOcean (#24414)
Adds deployment guides for Bun apps on AWS Lambda, Google Cloud Run, and
DigitalOcean using a custom `Dockerfile`

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-11-07 15:03:36 -08:00
Marko Vejnovic
3a810da66c build(ENG-21466): Fix sccache not caching across builds (#24423) 2025-11-07 14:33:26 -08:00
Jarred Sumner
0db90b2526 Implement isolated event loop for spawnSync (#24436) 2025-11-07 05:28:33 -08:00
Jarred Sumner
6f8138b6e4 in build Add NO_SCCACHE env var 2025-11-07 04:40:29 -08:00
taylor.fish
23a2b2129c Use std.debug.captureStackTrace on all platforms (#24456)
In the crash reporter, we currently use glibc's `backtrace()` function
on glibc Linux targets. However, this has resulted in poor stack traces
in many scenarios, particularly when a JSC signal handlers is involved,
in which case the stack trace tends to have only one frame—the signal
handler itself. Considering that JSC installs a signal handler for SEGV,
this is particularly bad.

Zig's `std.debug.captureStackTrace` generates considerably more complete
stack traces, but it has an issue where the top frame is missing when a
signal handler is involved. This is unfortunate, but it's still the
better option for now. Note that our stack traces on macOS also have
this missing frame issue.

In the future, we will investigate backporting the changes to stack
trace capturing that were recently made in Zig's `master` branch, since
that seems to have fixed the missing frame issue.

This PR still uses the stack trace provided by `backtrace()` if it
returns more frames than `captureStackTrace`. In particular, ARM may
need this behavior.

(For internal tracking: fixes ENG-21406)
2025-11-07 04:07:53 -08:00
Jarred Sumner
8ec856124c Add ccache back, with fallback for sccache 2025-11-07 04:01:10 -08:00
Jarred Sumner
94bc68f72c Ignore maxBuffer when not piped (#24440)
### What does this PR do?

### How did you verify your code works?
2025-11-07 00:54:01 -08:00
Marko Vejnovic
75f271a306 ENG-21473: Fix installations without sccache (#24453) 2025-11-06 17:26:28 -08:00
Marko Vejnovic
267be9a54a ci(ENG-21474): Minor Cleanup (#24450) 2025-11-06 17:26:19 -08:00
Alistair Smith
44402ad27a Document & cover some missing spawn/spawnSync options (#24417) 2025-11-06 14:37:26 -08:00
pfg
e01f454635 Fix #23865 (#24355)
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>
2025-11-05 22:04:14 -08:00
Jarred Sumner
f56232a810 Move Bun.spawn & Bun.spawnSync into a separate file (#24425)
### 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>
2025-11-05 22:03:27 -08:00
Marko Vejnovic
cf0ae19c2a ENG-21468: RELEASE=1 disables sccache (#24428)
### What does this PR do?

What the title says

### How did you verify your code works?

Tested locally:

```bash
killall sccache
RELEASE=1 bun run build
sccache --show-stats
```

```
marko@fedora:~/Desktop/bun-2$ sccache --show-stats
Compile requests                      0
Compile requests executed             0
Cache hits                            0
Cache misses                          0
Cache hits rate                       -
Cache timeouts                        0
Cache read errors                     0
Forced recaches                       0
Cache write errors                    0
Cache errors                          0
Compilations                          0
Compilation failures                  0
Non-cacheable compilations            0
Non-cacheable calls                   0
Non-compilation calls                 0
Unsupported compiler calls            0
Average cache write               0.000 s
Average compiler                  0.000 s
Average cache read hit            0.000 s
Failed distributed compilations       0
Cache location                  Local disk: "/home/marko/.cache/sccache"
Use direct/preprocessor mode?   yes
Version (client)                0.12.0
Max cache size                       10 GiB
```

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-11-05 22:03:10 -08:00
Jarred Sumner
4ac293bf01 Add error when loading known unsupported v8 c++ api (#24384)
### What does this PR do?

### How did you verify your code works?
2025-11-05 19:17:03 -08:00
Jarred Sumner
314088ab37 Update no-validate-exceptions.txt 2025-11-05 19:07:42 -08:00
Marko Vejnovic
86a0ff442a build(ENG-21464): Remove sccache --show-stats on local builds (#24421)
Co-authored-by: Meghan Denny <meghan@bun.com>
2025-11-05 16:26:48 -08:00
Meghan Denny
f4404a55db misc tidyings from another branch (#24406)
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>
2025-11-05 15:28:28 -08:00
Marko Vejnovic
1d4e3c0ab2 [publish images] 2025-11-05 14:34:31 -08:00
Marko Vejnovic
782f684b2e build(ENG-21330): Replace ccache with sccache (#24200) 2025-11-05 14:30:56 -08:00
Alistair Smith
995d988c73 Clear module cache when require'ing an es module with TLA throws (#24389)
### 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>
2025-11-05 13:55:49 -08:00
robobun
c7b9e0dc92 fix(node): prevent crash with null/undefined exports in process.dlopen (#24403)
## 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>
2025-11-05 13:53:08 -08:00
robobun
df5d0fcfa1 fix: ensure EC private key JWK "d" field has correct length (#24400)
## 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>
2025-11-05 13:49:13 -08:00
taylor.fish
4a326979f4 Fix bindgenv2 type annotations (#24139) 2025-11-05 12:45:43 -08:00
Marko Vejnovic
b3f8930c4a ENG-21460: Docs CLRF to LF (#24416) 2025-11-05 12:22:27 -08:00
Alistair Smith
126f4686af remove outdated docs ci workflows 2025-11-05 11:19:07 -08:00
Lydia Hallie
1606a9f24e Replace old docs with new docs repo (#24201) 2025-11-05 11:14:21 -08:00
Meghan Denny
550522e99b napi: unskip passing tests (#24359) 2025-11-04 16:59:23 -08:00
Alistair Smith
46d4ed3c33 Fix #24154 (#24382) 2025-11-04 13:11:52 -08:00
Meghan Denny
fa219a2f8e js: update node:_http_agent (#24275)
pulled out of https://github.com/oven-sh/bun/pull/21809

+7 node tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-11-04 11:56:33 -08:00
csvlad
4250ce6157 fix: vi typing in bun:test (#24248) 2025-11-04 08:27:30 -08:00
nkxxll
f8dce87f24 docs(bun-types): Replace depricated readableStreamToText in type docu… (#24372)
Co-authored-by: Alistair Smith <hi@alistair.sh>
2025-11-04 07:43:46 -08:00
Jarred Sumner
359f04d81f Improve NAPI property and element handling (#24358)
### 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>
2025-11-04 03:21:07 -08:00
robobun
9ce2504554 fix(node:http): unref poll_ref on WebSocket upgrade to prevent CPU spin (#24271)
## 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>
2025-11-03 23:27:26 -08:00
Jarred Sumner
5d76a0b2f8 Revert incorrect remaining_in_buffer check 2025-11-03 23:02:22 -08:00
Ciro Spaciari
8a9249c216 fix(tls) undo some changes added in root_certs (#24350)
### What does this PR do?
Restore call to us_get_default_ca_certificates, and
X509_STORE_set_default_paths

Fixes https://github.com/oven-sh/bun/issues/23735
### How did you verify your code works?
Manually test running:
```bash
bun -e "await fetch('https://secure-api.eloview.com').then(res => res.t
ext()).then(console.log);"
```
should not result in:
```js
error: unable to get local issuer certificate
  path: "https://secure-api.eloview.com/",
 errno: 0,
  code: "UNABLE_TO_GET_ISSUER_CERT_LOCALLY"
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Enhanced system root certificate handling to ensure consistent
validation across all secure connections.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-11-03 22:59:46 -08:00
Dylan Conway
aad4d800ff add "configVersion" to bun.lock(b) (#24236)
### 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>
2025-11-03 22:20:07 -08:00
Jarred Sumner
528620e9ae Add postinstall optimizer with native binlink support and script skipping (#24283)
## 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>
2025-11-03 20:36:22 -08:00
robobun
7197fb1f04 Fix Module._resolveFilename to pass options.paths to overridden functions (#24325)
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>
2025-11-03 20:28:33 -08:00
robobun
946470dcd7 Refactor: move FetchTasklet to separate file (#24330)
## Summary

Extract `FetchTasklet` struct from `src/bun.js/webcore/fetch.zig` into
its own file at `src/bun.js/webcore/fetch/FetchTasklet.zig` to improve
code organization and modularity.

## Changes

- Moved `FetchTasklet` struct definition (1336 lines) to new file
`src/bun.js/webcore/fetch/FetchTasklet.zig`
- Added all necessary imports to the new file
- Updated `fetch.zig` line 61 to import `FetchTasklet` from the new
location: `pub const FetchTasklet =
@import("./fetch/FetchTasklet.zig").FetchTasklet;`
- Verified compilation succeeds with `bun bd`

## Impact

- No functional changes - this is a pure refactoring
- Improves code organization by separating the large `FetchTasklet`
implementation
- Makes the codebase more maintainable and easier to navigate
- Reduces `fetch.zig` from 2768 lines to 1433 lines

## Test plan

- [x] Built successfully with `bun bd`
- [x] No changes to functionality - pure code organization refactor

🤖 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>
2025-11-03 02:21:49 -08:00
Michael H
d76fad3618 fix update interactive to keep npm aliases (#23903)
### 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>
2025-11-03 02:12:24 -08:00
robobun
bdaab89253 Fix bun update --interactive not installing packages (#24280)
## 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>
2025-11-03 01:57:02 -08:00
Jarred Sumner
797847639a Fix process.mainModule = ${value} (#23698)
### What does this PR do?

### How did you verify your code works?
2025-11-02 01:19:01 -07:00
robobun
39c43170e6 Add ServerWebSocket.subscriptions getter (#24299)
## Summary

Adds a `subscriptions` getter to `ServerWebSocket` that returns an array
of all topics the WebSocket is currently subscribed to.

## Implementation

- Added `getTopicsCount()` and `iterateTopics()` helpers to uWS
WebSocket
- Implemented C++ function `uws_ws_get_topics_as_js_array` that:
  - Uses `JSC::MarkedArgumentBuffer` to protect values from GC
  - Constructs JSArray directly in C++ for efficiency
  - Uses template pattern for SSL/TCP variants
  - Properly handles iterator locks with explicit scopes
- Exposed as `subscriptions` getter property on ServerWebSocket
- Returns empty array when WebSocket is closed (not null)

## API

```typescript
const server = Bun.serve({
  websocket: {
    open(ws) {
      ws.subscribe("chat");
      ws.subscribe("notifications");
      console.log(ws.subscriptions); // ["chat", "notifications"]
      
      ws.unsubscribe("chat");
      console.log(ws.subscriptions); // ["notifications"]
    }
  }
});
```

## Test Coverage

Added 5 comprehensive test cases covering:
- Basic subscription/unsubscription flow
- All subscriptions removed
- Behavior after WebSocket close
- Duplicate subscriptions (should only appear once)
- Multiple subscribe/unsubscribe cycles

All tests pass with 24 assertions.

🤖 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>
2025-11-01 22:43:21 -07:00
Dylan Conway
f770b1b1c7 fix(install): fix optional peer resolving (#24272)
### What does this PR do?
Allows optional peers to resolve to package if possible.

Optional peers aren't auto-installed, but they should still be given a
chance to resolve. If they're always left unresolved it's possible for
multiple dependencies on the same package to result in different peer
resolutions when they should be the same. For example, this bug this
could cause monorepos using elysia to have corrupt node_modules because
there might be more than one copy of elysia in `node_modules/.bun` (or
more than the expected number of copies).

fixes #23725
most likely fixes #23895

fixes ENG-21411

### How did you verify your code works?
Added a test for optional peers and non-optional peers that would
previously trigger this bug.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Improved resolution of optional peer dependencies during isolated
installations, with better propagation across package hierarchies.

* **Tests**
* Added comprehensive test suite covering optional peer dependency
scenarios in isolated workspaces.
* Added test fixtures for packages with peer and optional peer
dependencies.
* Enhanced lockfile migration test verification using snapshot-based
assertions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-11-01 22:38:36 -07:00
Dylan Conway
42543fb544 fix(NAPI): return detached buffer from napi_create_external_buffer if empty (#24297)
### What does this PR do?
When `napi_create_external_buffer` receives empty input, the returned
buffer should be detached.

This fixes the remaining tests in `ref-napi` other than three that use a
few uv symbols
<img width="329" height="159" alt="Screenshot 2025-11-01 at 8 38 01 PM"
src="https://github.com/user-attachments/assets/2c75f937-79c5-467a-bde3-44e45e05d9a0"
/>

### How did you verify your code works?
Added tests for correct values from `napi_get_buffer_info`,
`napi_get_arraybuffer_info`, and `napi_is_detached_arraybuffer` when
given an empty buffer from `napi_create_external_buffer`

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-11-01 22:21:41 -07:00
Jarred Sumner
60c0fd7786 Move to the right folder 2025-11-01 21:15:09 -07:00
github-actions[bot]
219b9c6cfc deps: update libdeflate to v1.25 (#24295)
## What does this PR do?

Updates libdeflate to version v1.25

Compare:
96836d7d9d...c8c56a20f8

Auto-updated by [this
workflow](https://github.com/oven-sh/bun/actions/workflows/update-libdeflate.yml)

Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2025-11-01 21:07:20 -07:00
robobun
a912eca96a Add event loop architecture documentation (#24300)
## Summary

Adds comprehensive documentation explaining how Bun's event loop works,
including task draining, microtasks, process.nextTick, and I/O polling
integration.

## What does this document?

- **Task draining algorithm**: Shows the exact flow for processing each
task (run → release weak refs → drain microtasks → deferred tasks)
- **Process.nextTick ordering**: Explains batching behavior - all
nextTick callbacks in current batch run, then microtasks drain
- **Microtask integration**: How JavaScriptCore's microtask queue and
Bun's nextTick queue interact
- **I/O polling**: How uSockets epoll/kqueue events integrate with the
event loop
- **Timer ordering**: Why setImmediate runs before setTimeout
- **Enter/Exit mechanism**: How the counter prevents excessive microtask
draining

## Visual aids

Includes ASCII flowcharts showing:
- Main tick flow
- autoTick flow (with I/O polling)
- Per-task draining sequence

## Code references

All explanations include specific file paths and line numbers for
verification:
- `src/bun.js/event_loop/Task.zig`
- `src/bun.js/event_loop.zig`
- `src/bun.js/bindings/ZigGlobalObject.cpp`
- `src/js/builtins/ProcessObjectInternals.ts`
- `packages/bun-usockets/src/eventing/epoll_kqueue.c`

## Examples

Includes JavaScript examples demonstrating:
- nextTick vs Promise ordering
- Batching behavior when nextTick callbacks schedule more nextTicks
- setImmediate vs setTimeout ordering

🤖 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>
2025-11-01 20:59:35 -07:00
Jarred Sumner
8058d78b6a Deflake test/cli/run/cpu-prof.test.ts 2025-11-01 20:17:56 -07:00
Jarred Sumner
8b98746808 Update .coderabbit.yaml 2025-11-01 19:58:13 -07:00
Jarred Sumner
f50b44e35b Update .coderabbit.yaml
Update .coderabbit.yaml
2025-11-01 19:56:55 -07:00
Jarred Sumner
b02d46498e Don't set isIdle when it is not in fact idle (#24274)
### What does this PR do?

### How did you verify your code works?


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved HTTP connection handling during write failures to ensure more
reliable timeout behavior and connection state management.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-11-01 19:39:51 -07:00
Dylan Conway
28be8a9915 fix(NAPI): empty input napi_create_external_buffer (#24293)
### What does this PR do?
If the input was empty `ArrayBuffer::createFromBytes` would create a
buffer that `JSUint8Array::create` would see as detached, so it would
throw an exception. This would likely cause crashes in `node-addon-api`
because finalize data is freed if `napi_create_external_buffer` fails,
and we already setup the finalizer.

Example of creating empty buffer:

a7f62a4caa/src/binding.cc (L687)

fixes #6737
fixes #10965
fixes #12331
fixes #12937
fixes #13622
most likely fixes #14822
### How did you verify your code works?
Manually and added tests.
2025-11-01 19:21:02 -07:00
Meghan Denny
5aeef40479 Update .coderabbit.yaml
docs have a trailing slash for folders and i got a comment in 24275 so im tempted to think it may be necessary
2025-11-01 02:40:03 -07:00
Meghan Denny
9953d78a66 Update .coderabbit.yaml
don't edit the original description
leave the summary in the walkthrough comment
2025-11-01 02:36:05 -07:00
Meghan Denny
0564b81e64 node: stop skipping test-http-full-response.js on linux (#21154) [publish images] 2025-10-31 23:24:32 -07:00
robobun
7c9e8a2b10 Remove MemoryReportingAllocator (#24251)
## Summary

Removes the `MemoryReportingAllocator` wrapper and simplifies
`fetch.zig` to use `bun.default_allocator` directly. The
`MemoryReportingAllocator` was wrapping `bun.default_allocator` to track
memory usage for reporting to the VM, but this added unnecessary
complexity and indirection without meaningful benefit.

## Changes

**Deleted:**
- `src/allocators/MemoryReportingAllocator.zig` (96 lines)

**Modified `src/bun.js/webcore/fetch.zig`:**
- Removed `memory_reporter: *bun.MemoryReportingAllocator` field from
`FetchTasklet` struct
- Removed `memory_reporter: *bun.MemoryReportingAllocator` field from
`FetchOptions` struct
- Replaced all `this.memory_reporter.allocator()` calls with
`bun.default_allocator`
- Removed all `this.memory_reporter.discard()` calls (no longer needed)
- Simplified `fetch()` function by removing memory reporter
allocation/wrapping/cleanup code
- Updated `deinit()` and `clearData()` to use `bun.default_allocator`
directly

**Cleanup:**
- Removed `MemoryReportingAllocator` export from `src/allocators.zig`
- Removed `MemoryReportingAllocator` export from `src/bun.zig`
- Removed `bun.MemoryReportingAllocator.isInstance()` check from
`src/safety/alloc.zig`

## Testing

-  Builds successfully with `bun bd`
- All fetch operations now use `bun.default_allocator` directly

## Impact

- **Net -116 lines** of code
- Eliminates allocator wrapper overhead in fetch operations
- Simplifies memory management code
- No functional changes to fetch behavior

🤖 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>
2025-10-31 19:50:55 -07:00
robobun
c5def80191 Fix Output.enable_ansi_colors usage to check stdout vs stderr (#24212)
## Summary

Updated all 49 usages of `Output.enable_ansi_colors` to properly check
either `Output.enable_ansi_colors_stdout` or
`Output.enable_ansi_colors_stderr` based on their output destination.

This prevents bugs where ANSI colors are checked against the wrong
stream (e.g., checking stdout colors when writing to stderr).

## Changes

### Added
- `Output.enable_ansi_colors` now a `@compileError` to prevent future
misuse with helpful error message directing to correct variants

### Deleted
- `Output.isEmojiEnabled()` - replaced all usages with
`enable_ansi_colors_stderr` (all were error/progress output)
- `Output.prettyWithPrinterFn()` - removed unused dead code

### Updated by Output Destination

**Stderr (error/diagnostic output):**
- logger.zig: Log messages and errors
- crash_handler.zig: Crash reports and stack traces (10 instances)
- PackageInstaller.zig: Error messages from lifecycle scripts (3
instances)
- JSValue.zig: Test expectation error messages
- JSGlobalObject.zig: Exception throwing
- pack_command.zig: Progress indicators
- VirtualMachine.zig: Exception printing (2 instances)
- Test expect files: Test failure messages and diffs (10 instances)
- diff_format.zig: Test diff output
- ProgressStrings.zig: Package manager progress emojis (6 functions)
- security_scanner.zig: Security scan progress emoji
- output.zig: panic(), resetTerminal()

**Stdout (primary output/interactive UI):**
- hot_reloader.zig: Terminal clearing on reload
- Version.zig: Version diff formatting
- install_with_manager.zig: Package installation tree
- update_interactive_command.zig: Interactive update UI (2 instances)
- init_command.zig: Interactive radio buttons
- create_command.zig: Template creation output (2 instances)
- outdated_command.zig: Outdated packages table
- publish_command.zig: Box drawing characters (6 instances)

**Backward Compatible:**
- BunObject.zig: `Bun.enableANSIColors` property returns `(stdout ||
stderr)` to maintain compatibility
- fmt.zig: Removed unused `.default` field from Options struct

## Test Plan

-  All changes compile successfully with `bun run zig:check`
-  Verified all 49 usages have been updated to appropriate variant
-  Verified no remaining references to deprecated functions/variables
-  Compile error triggers if someone tries to use
`Output.enable_ansi_colors`

## Stats

- 24 files changed
- 58 insertions, 77 deletions (net -19 lines)
- 49 usages correctly updated
- 3 items deleted/deprecated

🤖 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>
2025-10-31 19:08:41 -07:00
Meghan Denny
fb6384160d Update .coderabbit.yaml
this was already the case and we dont want it to comment on common or fixtures either
2025-10-31 16:29:05 -07:00
Jarred Sumner
759018caf9 Make duplicate issue checker text use the magic words 2025-10-31 02:30:25 -07:00
Jarred Sumner
b3b465937f Only disable coderabbit for tests from Node.js. 2025-10-31 02:30:11 -07:00
Jarred Sumner
570b0a03a4 Fix duplicate issue closer
Broken in 9d4a04cff9
2025-10-31 02:07:46 -07:00
Meghan Denny
358596afbd Update .coderabbit.yaml: fix parsing error
smh yaml
2025-10-31 00:15:30 -07:00
Dylan Conway
5b5b02dee6 fix(bunfig): make sure bunfig is loaded once (#24210)
### What does this PR do?
calling `loadConfigPath` could allow loading bunfig more than once.
### How did you verify your code works?
manually

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-30 17:57:56 -07:00
Meghan Denny
8f0f06ba52 Create .coderabbit.yaml 2025-10-30 17:52:10 -07:00
Marko Vejnovic
90ce355ef0 chore(ENG-21402): Remove Unused CMake Code (#24228) 2025-10-30 11:41:56 -07:00
robobun
476e1cfe69 Make 'bun list' an alias for 'bun pm ls' (#24159)
## Summary

This PR makes `bun list` an alias for `bun pm ls`, allowing users to
list their dependency tree with a shorter command.

## Changes

- Updated `src/cli.zig` to route `list` command to
`PackageManagerCommand` instead of `ReservedCommand`
- Modified `src/cli/package_manager_command.zig` to detect when `bun
list` is invoked directly and treat it as `ls`
- Updated help text in `bun pm --help` to show both `bun list` and `bun
pm ls` as valid options

## Implementation Details

The implementation follows the same pattern used for `bun whoami`, which
is also a direct alias to a pm subcommand. When `bun list` is detected,
it's internally converted to the `ls` subcommand.

## Testing

Tested locally:
-  `bun list` shows the dependency tree
-  `bun list --all` works correctly with the `--all` flag
-  `bun pm ls` continues to work (backward compatible)

## Test Output

```bash
$ bun list
/tmp/test-bun-list node_modules (3)
└── react@18.3.1

$ bun list --all
/tmp/test-bun-list node_modules
├── js-tokens@4.0.0
├── loose-envify@1.4.0
└── react@18.3.1

$ bun pm ls
/tmp/test-bun-list node_modules (3)
└── react@18.3.1
```

🤖 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>
2025-10-29 21:05:25 -07:00
robobun
646aede0d4 Fix CPU profiler timestamps - use setDouble() instead of setInteger() (#24206)
## Summary

Fixes CPU profiler generating invalid timestamps that Chrome DevTools
couldn't parse (though VSCode's profiler viewer accepted them).

## The Problem

CPU profiles generated by `--cpu-prof` had timestamps that were either:
1. Negative (in the original broken profile from the gist)
2. Truncated/corrupted (after initial timestamp calculation fix)

Example from the broken profile:
```json
{
  "startTime": -822663297,
  "endTime": -804820609
}
```

After initial fix, timestamps were positive but still wrong:
```json
{
  "startTime": 1573519100,  // Should be ~1761784720948727
  "endTime": 1573849434
}
```

## Root Cause

**Primary Issue**: `WTF::JSON::Object::setInteger()` has precision
issues with large values (> 2^31). When setting timestamps like
`1761784720948727` (microseconds since Unix epoch - 16 digits), the
method was truncating/corrupting them.

**Secondary Issue**: The timestamp calculation logic needed
clarification - now explicitly uses the earliest sample's wall clock
time as startTime and calculates a consistent wallClockOffset.

## The Fix

### src/bun.js/bindings/BunCPUProfiler.cpp

Changed from `setInteger()` to `setDouble()` for timestamp
serialization:

```cpp
// Before (broken):
json->setInteger("startTime"_s, static_cast<long long>(startTime));
json->setInteger("endTime"_s, static_cast<long long>(endTime));

// After (fixed):
json->setDouble("startTime"_s, startTime);
json->setDouble("endTime"_s, endTime);
```

JSON `Number` type can precisely represent integers up to 2^53 (~9
quadrillion), which is far more than needed for microsecond timestamps
(~10^15 for current dates).

Also clarified the timestamp calculation to use `wallClockStart`
directly as the profile's `startTime` and calculate a `wallClockOffset`
for converting stopwatch times to wall clock times.

### test/cli/run/cpu-prof.test.ts

Added validation that timestamps are:
- Positive
- In microseconds (> 1000000000000000, < 3000000000000000)
- Within valid Unix epoch range

## Testing

```bash
bun bd test test/cli/run/cpu-prof.test.ts
```

All tests pass 

Generated profile now has correct timestamps:
```json
{
  "startTime": 1761784720948727.2,
  "endTime": 1761784721305814
}
```

## Why VSCode Worked But Chrome DevTools Didn't

- **VSCode**: Only cares about relative timing (duration = endTime -
startTime), doesn't validate absolute timestamp ranges
- **Chrome DevTools**: Expects timestamps in microseconds since Unix
epoch (positive, ~16 digits), fails validation when timestamps are
negative, too small, or out of valid range

## References

- Gist with CPU profile format documentation:
https://gist.github.com/Jarred-Sumner/2c12da481845e20ce6a6175ee8b05a3e
- Chrome DevTools Protocol - Profiler:
https://chromedevtools.github.io/devtools-protocol/tot/Profiler/

🤖 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>
2025-10-29 20:55:48 -07:00
Marko Vejnovic
1d728bb778 feat(ENG-21324): Implement hosted_git_info.zig (#24138)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2025-10-29 19:29:04 -07:00
robobun
a7fc6eb354 Implement --cpu-prof CLI flag (#24112)
## Summary

Implements the `--cpu-prof` CLI flag for Bun to profile CPU usage and
save results in Chrome CPU Profiler JSON format, compatible with Chrome
DevTools and VSCode.

## Implementation Details

- Uses JSC's `SamplingProfiler` to collect CPU samples during execution
- Converts samples to Chrome CPU Profiler JSON format on exit
- Supports `--cpu-prof-name` to customize output filename
- Supports `--cpu-prof-dir` to specify output directory
- Default filename: `CPU.YYYYMMDD.HHMMSS.PID.0.001.cpuprofile`

## Key Features

 **Chrome DevTools Compatible** - 100% compatible with Node.js CPU
profile format
 **Absolute Timestamps** - Uses wall clock time (microseconds since
epoch)
 **1ms Sampling** - Matches Node.js sampling frequency for comparable
granularity
 **Thread-Safe** - Properly shuts down background sampling thread
before processing
 **Memory-Safe** - Uses HeapIterationScope and DeferGC for safe heap
access
 **Cross-Platform** - Compiles on Windows, macOS, and Linux with proper
path handling

## Technical Challenges Solved

1. **Heap Corruption** - Fixed by calling `profiler->shutdown()` before
processing traces
2. **Memory Safety** - Added `HeapIterationScope` and `DeferGC` when
accessing JSCells
3. **Timestamp Accuracy** - Explicitly start stopwatch and convert to
absolute wall clock time
4. **Path Handling** - Used `bun.path.joinAbsStringBufZ` with proper cwd
resolution
5. **Windows Support** - UTF-16 path conversion for Windows
compatibility
6. **Atomic Writes** - Used `bun.sys.File.writeFile` with ENOENT retry

## Testing

All tests pass (4/4):
-  Generates profile with default name
-  `--cpu-prof-name` sets custom filename
-  `--cpu-prof-dir` sets custom directory
-  Profile captures function names

Verified format compatibility:
- JSON structure matches Node.js exactly
- All samples reference valid nodes
- Timestamps use absolute microseconds since epoch
- Cross-platform compilation verified with `bun run zig:check-all`

## Example Usage

```bash
# Basic usage
bun --cpu-prof script.js

# Custom filename
bun --cpu-prof --cpu-prof-name my-profile.cpuprofile script.js

# Custom directory
bun --cpu-prof --cpu-prof-dir ./profiles script.js
```

Output can be opened in Chrome DevTools (Performance → Load Profile) or
VSCode's CPU profiling viewer.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-29 16:41:21 -07:00
robobun
ddd4018bda Improve snapshot error messages in CI environments (#23419)
## Summary

This PR improves snapshot error messages when running tests in CI
environments to make debugging easier by showing exactly what snapshot
was being created and what value was attempted.

## Changes

### 1. Inline Snapshot Errors
**Before:**
```
Updating inline snapshots is disabled in CI environments unless --update-snapshots is used.
```

**After:**
```
Inline snapshot creation is not allowed in CI environments unless --update-snapshots is used.
If this is not a CI environment, set the environment variable CI=false to force allow.

Received: this is new
```

- Changed message to say "creation" instead of "updating" (more
accurate)
- Shows the received value that was attempted using Jest's pretty
printer

### 2. Snapshot File Errors
**Before:**
```
Snapshot creation is not allowed in CI environments unless --update-snapshots is used
If this is not a CI environment, set the environment variable CI=false to force allow.

Received: this is new
```

**After:**
```
Snapshot creation is not allowed in CI environments unless --update-snapshots is used
If this is not a CI environment, set the environment variable CI=false to force allow.

Snapshot name: "new snapshot 1"
Received: this is new
```

- Now shows the snapshot name that was being looked for
- Shows the received value using Jest's pretty printer

## Implementation Details

- Added `last_error_snapshot_name` field to `Snapshots` struct to pass
snapshot name from `getOrPut()` to error handler
- Removed unreachable code path for inline snapshot updates (mismatches
error earlier with diff)
- Updated test expectations in `ci-restrictions.test.ts`

## Test Plan

```bash
# Test inline snapshot creation in CI
cd /tmp/snapshot-test
echo 'import { test, expect } from "bun:test";
test("new inline snapshot", () => {
  expect("this is new").toMatchInlineSnapshot();
});' > test.js
GITHUB_ACTIONS=1 bun test test.js

# Test snapshot file creation in CI
echo 'import { test, expect } from "bun:test";
test("new snapshot", () => {
  expect("this is new").toMatchSnapshot();
});' > test2.js
GITHUB_ACTIONS=1 bun test test2.js
```

Both should show improved error messages with the received values and
snapshot name.

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pfg <pfg@pfg.pw>
2025-10-29 15:55:41 -07:00
robobun
1de4448425 Fix duplicate issue bot to respect 👎 reactions and not re-close reopened issues (#24203)
## Summary

Fixed two bugs in the auto-close-duplicates bot:

- **Respect 👎 reactions from ANY user**: Previously only the issue
author's thumbs down would prevent auto-closing. Now any user can
indicate disagreement with the duplicate detection.
- **Don't re-close reopened issues**: The bot now checks if an issue was
previously reopened and skips auto-closing to respect user intent.

## Changes

1. Modified `fetchAllReactions` call to check all reactions, not just
the author's
2. Changed `authorThumbsDown` logic to `hasThumbsDown` (checks any
user's reaction)
3. Added `wasIssueReopened()` function to query issue events timeline
4. Added check to skip issues with "reopened" events in their history

## Test plan

- [ ] Manually test the script doesn't close issues with 👎 reactions
from non-authors
- [ ] Verify reopened issues are not auto-closed again
- [ ] Check that legitimate duplicates without objections still get
closed properly

🤖 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>
2025-10-29 15:41:44 -07:00
Meghan Denny
9d4a04cff9 scripts/auto-close-duplicates.ts: dont change the labels 2025-10-29 14:57:32 -07:00
Jarred Sumner
9d0ef94557 Mark test as flaky on macOS CI 2025-10-29 14:51:29 -07:00
Jarred Sumner
a5f8b0e8dd react-dom-server requires messagechannel now i guess 2025-10-29 08:14:08 +01:00
Jarred Sumner
fe1bc56637 Add workerd benchmark 2025-10-29 07:16:32 +01:00
robobun
98c04e37ec Fix source index bounds check in sourcemap decoder (#24145)
## Summary

Fix the source index bounds check in `src/sourcemap/Mapping.zig` to
correctly validate indices against the range `[0, sources_count)`.

## Changes

- Changed the bounds check condition from `source_index > sources_count`
to `source_index >= sources_count` on line 452
- This prevents accepting `source_index == sources_count`, which would
be out of bounds when indexing into the sources array

## Test plan

- [x] Built successfully with `bun bd`
- The existing test suite should continue to pass

🤖 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>
2025-10-28 12:32:53 -07:00
robobun
4f1b90ad1d Fix EventEmitter crash in removeAllListeners with removeListener meta-listener (#24148)
## Summary

Fixes #24147

- Fixed EventEmitter crash when `removeAllListeners()` is called from
within an event handler while a `removeListener` meta-listener is
registered
- Added undefined check before iterating over listeners array to match
Node.js behavior
- Added comprehensive regression tests

## Bug Description

When `removeAllListeners(type)` was called:
1. From within an event handler 
2. While a `removeListener` meta-listener was registered
3. For an event type with no listeners

It would crash with: `TypeError: undefined is not an object (evaluating
'this._events')`

## Root Cause

The `removeAllListeners` function tried to access `listeners.length`
without checking if `listeners` was defined first. When called with an
event type that had no listeners, `events[type]` returned `undefined`,
causing the crash.

## Fix

Added a check `if (listeners !== undefined)` before iterating, matching
the behavior in Node.js core:
https://github.com/nodejs/node/blob/main/lib/events.js#L768

## Test plan

-  Created regression test in `test/regression/issue/24147.test.ts`
-  Verified test fails with `USE_SYSTEM_BUN=1 bun test` (reproduces
bug)
-  Verified test passes with `bun bd test` (confirms fix)
-  Test covers the exact reproduction case from the issue
-  Additional tests for edge cases (actual listeners, nested calls)

🤖 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>
2025-10-28 12:32:15 -07:00
robobun
51431b6e65 Fix sourcemap comparator to use strict weak ordering (#24146)
## Summary

Fixes the comparator function in `src/sourcemap/Mapping.zig` to use
strict weak ordering as required by sort algorithms.

## Changes

- Changed `<=` to `<` in the column comparison to ensure strict ordering
- Refactored the comparator to use clearer if-statement structure
- Added index comparison as a tiebreaker for stable sorting when both
line and column positions are equal

## Problem

The original comparator used `<=` which would return true for equal
elements, violating the strict weak ordering requirement. This could
lead to undefined behavior in sorting.

**Before:**
```zig
return a.lines.zeroBased() < b.lines.zeroBased() or (a.lines.zeroBased() == b.lines.zeroBased() and a.columns.zeroBased() <= b.columns.zeroBased());
```

**After:**
```zig
if (a.lines.zeroBased() != b.lines.zeroBased()) {
    return a.lines.zeroBased() < b.lines.zeroBased();
}
if (a.columns.zeroBased() != b.columns.zeroBased()) {
    return a.columns.zeroBased() < b.columns.zeroBased();
}
return a_index < b_index;
```

## Test plan

- [x] Verified compilation with `bun bd`
- The sort now properly follows strict weak ordering semantics

🤖 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>
2025-10-28 12:31:42 -07:00
robobun
eb77bdd286 Refactor: Split sourcemap.zig into separate struct files (#24141)
## Summary

This PR refactors the sourcemap module by extracting large structs from
`src/sourcemap/sourcemap.zig` into their own dedicated files, improving
code organization and maintainability.

## Changes

- **Extracted `ParsedSourceMap` struct** to
`src/sourcemap/ParsedSourceMap.zig`
  - Made `SourceContentPtr` and related methods public
  - Made `standaloneModuleGraphData` public for external access
  
- **Extracted `Chunk` struct** to `src/sourcemap/Chunk.zig`
  - Added import for `appendMappingToBuffer` from parent module
  - Includes all nested types: `VLQSourceMap`, `NewBuilder`, `Builder`
  
- **Extracted `Mapping` struct** to `src/sourcemap/Mapping.zig`
  - Added necessary imports: `assert`, `ParseResult`, `debug`
  - Includes nested types: `MappingWithoutName`, `List`, `Lookup`

- **Updated `src/sourcemap/sourcemap.zig`**
- Replaced struct definitions with imports:
`@import("./StructName.zig")`
  - Maintained all public APIs

All structs now follow the `const StructName = @This()` pattern for
top-level declarations.

## Testing

-  Compiled successfully with `bun bd`
-  All existing functionality preserved
-  No API changes - fully backwards compatible

## Before

- Single 2000+ line file with multiple large structs
- Difficult to navigate and maintain

## After

- Modular structure with separate files for each major struct
- Easier to find and modify specific functionality
- Better code organization

🤖 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>
2025-10-28 00:05:16 -07:00
Jarred Sumner
523fc14d76 Deflake websocket test 2025-10-27 18:58:06 -07:00
Felipe Cardozo
a0a69ee146 fix: body already used error to throw TypeError (#24114)
Should fix https://github.com/oven-sh/bun/issues/24104

### What does this PR do?

This PR is changing `ERR_BODY_ALREADY_USED` to be TypeError instead of
Error.


### How did you verify your code works?
A test case added to verify that request call correctly throws a
TypeError after another request call on the same Request, confirming the
fix addresses the issue.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-27 18:31:33 -07:00
robobun
668eba0eb8 fix(node:http): Fix ServerResponse.writableNeedDrain causing stream pause (#24137)
## Summary

Fixes #19111

This PR fixes a bug where `fs.createReadStream().pipe(ServerResponse)`
would fail to transfer data when ServerResponse had no handle
(standalone usage). This affected Vite's static file serving and other
middleware adapters using the connect-to-web pattern.

## Root Cause

The bug was in the `ServerResponse.writableNeedDrain` getter at line
1529 of `_http_server.ts`:

```typescript
return !this.destroyed && !this.finished && (this[kHandle]?.bufferedAmount ?? 1) !== 0;
```

When `ServerResponse` had no handle (which is common in middleware
scenarios), the nullish coalescing operator defaulted `bufferedAmount`
to **1** instead of **0**. This caused `writableNeedDrain` to always
return `true`.

## Impact

When `pipe()` checks `dest.writableNeedDrain === true`, it immediately
pauses the source stream to handle backpressure. With the bug,
standalone ServerResponse instances always appeared to need draining,
causing piped streams to pause and never resume.

## Fix

Changed the default value from `1` to `0`:

```typescript
return !this.destroyed && !this.finished && (this[kHandle]?.bufferedAmount ?? 0) !== 0;
```

## Test Plan

-  Added regression test in `test/regression/issue/19111.test.ts`
-  Verified fix with actual Vite middleware reproduction
-  Confirmed behavior matches Node.js

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>
2025-10-27 15:24:38 -07:00
robobun
6580b563b0 Refactor Subprocess to use JSRef instead of hasPendingActivity (#24090)
## Summary

Refactors `Subprocess` to use explicit strong/weak reference management
via `JSRef` instead of the `hasPendingActivity` mechanism that relies on
JSC's internal `WeakHandleOwner`.

## Changes

### Core Refactoring
- **JSRef.zig**: Added `update()` method to update references in-place
- **subprocess.zig**: Changed `this_jsvalue: JSValue` to `this_value:
JSRef`
- **subprocess.zig**: Renamed `hasPendingActivityNonThreadsafe()` to
`computeHasPendingActivity()`
- **subprocess.zig**: Updated `updateHasPendingActivity()` to
upgrade/downgrade `JSRef` based on pending activity
- **subprocess.zig**: Removed `hasPendingActivity()` C callback function
- **subprocess.zig**: Updated `finalize()` to call
`this_value.finalize()`
- **BunObject.classes.ts**: Set `hasPendingActivity: false` for
Subprocess
- **Writable.zig**: Updated references from `this_jsvalue` to
`this_value.tryGet()`
- **ipc.zig**: Updated references from `this_jsvalue` to
`this_value.tryGet()`

## How It Works

**Before**: Used `hasPendingActivity: true` which created a `JSC::Weak`
reference with a `JSC::WeakHandleOwner` that kept the object alive as
long as the C callback returned true.

**After**: Uses `JSRef` with explicit lifecycle management:
1. Starts with a **weak** reference when subprocess is created
2. Immediately calls `updateHasPendingActivity()` after creation
3. **Upgrades to strong** reference when `computeHasPendingActivity()`
returns true:
   - Subprocess hasn't exited
   - Has active stdio streams
   - Has active IPC connection
4. **Downgrades to weak** reference when all activity completes
5. GC can collect the subprocess once it's weak and no other references
exist

## Benefits

- Explicit control over subprocess lifecycle instead of relying on JSC's
internal mechanisms
- Clearer semantics: strong reference = "keep alive", weak reference =
"can be GC'd"
- Removes dependency on `WeakHandleOwner` callback overhead

## Testing

-  `test/js/bun/spawn/spawn.ipc.test.ts` - All 4 tests pass
-  `test/js/bun/spawn/spawn-stress.test.ts` - All tests pass (100
iterations)
- ⚠️ `test/js/bun/spawn/spawnSync.test.ts` - 3/6 pass (3 pre-existing
timing-based failures unrelated to this change)

Manual testing confirms:
- Subprocess is kept alive without user reference while running
- Subprocess can be GC'd after completion
- IPC keeps subprocess alive correctly
- No crashes or memory leaks

🤖 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>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-27 14:19:38 -07:00
Meghan Denny
f3ed784a6b scripts: teach machine.mjs how to spawn a freebsd image on aws (#24109)
exploratory look into https://github.com/oven-sh/bun/issues/1524
this still leaves that far off from being closed but an important first
step
this is important because this script is used to spawn our base images
for CI and will provide boxes for local testing

not sure how far i'll get but a rough "road to freebsd" map for anyone
reading:

- [x] this
- [ ] ensure `bootstrap.sh` can run successfully
- [ ] ensure WebKit can build from source
- [ ] ensure other dependencies can build from source
- [ ] add freebsd to our WebKit fork releases
- [ ] add freebsd to our Zig fork releases
- [ ] ensure bun can build from source
- [ ] run `[build images]` and add freebsd to CI
- [ ] fix runtime test failures

<img width="2072" height="956" alt="image"
src="https://github.com/user-attachments/assets/ea1acf45-b746-4ffa-8043-be674b87bb60"
/>
2025-10-27 13:11:00 -07:00
Meghan Denny
64bfd8b938 Revert "deps: update elysia to 1.4.13" (#24133) 2025-10-27 12:49:41 -07:00
Meghan Denny
2afafbfa23 zig: remove Location.suggestion (#23478) 2025-10-27 12:26:21 -07:00
Meghan Denny
1e849b905a zig: bun.sourcemap -> bun.SourceMap (#23477) 2025-10-27 12:26:09 -07:00
Jarred Sumner
b280e8d326 Enable more sanitizers in CI (#24117)
### What does this PR do?

We were only enabling UBSAN in debug builds. This was probably a
mistake.

### How did you verify your code works?
2025-10-27 02:37:05 -07:00
Jarred Sumner
b7ae21d0bc Mark flaky test as TODO 2025-10-26 14:29:31 -07:00
robobun
a75cef5079 Add comprehensive documentation for JSRef (#24095)
## Summary

- Adds detailed documentation explaining JSRef's intended usage
- Includes a complete example showing common patterns
- Explains the three states (weak, strong, finalized) 
- Provides guidelines on when to use strong vs weak references
- References real examples from the codebase (ServerWebSocket,
UDPSocket, MySQLConnection, ValkeyClient)

## Motivation

JSRef is a critical type for managing JavaScript object references from
native code, but it lacked comprehensive documentation explaining its
usage patterns and lifecycle management. This makes it clearer how to
properly use JSRef to:

- Safely maintain references to JS objects from native code
- Control whether references prevent garbage collection
- Manage the upgrade/downgrade pattern based on object activity

## Test plan

Documentation-only change, no functional changes.

🤖 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>
2025-10-26 01:28:27 -07:00
github-actions[bot]
4c00d8f016 deps: update elysia to 1.4.13 (#24085)
## What does this PR do?

Updates elysia to version 1.4.13

Compare: https://github.com/elysiajs/elysia/compare/1.4.12...1.4.13

Auto-updated by [this
workflow](https://github.com/oven-sh/bun/actions/workflows/update-vendor.yml)

Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2025-10-25 22:03:34 -07:00
Jarred Sumner
f58a066236 Update CLAUDE.md 2025-10-25 21:34:24 -07:00
robobun
3367fa6ae3 Refactor: Extract ModuleLoader components into separate files (#24083)
## Summary

Split `ModuleLoader.zig` into smaller, more focused modules for better
code organization and maintainability:

- `AsyncModule` → `src/bun.js/AsyncModule.zig` (lines 69-806)
- `RuntimeTranspilerStore` → `src/bun.js/RuntimeTranspilerStore.zig`
(lines 2028-2606)
- `HardcodedModule` → `src/bun.js/HardcodedModule.zig` (lines 2618-3040)

## Changes

- Extracted three large components from `ModuleLoader.zig` into separate
files
- Updated imports in all affected files
- Made necessary functions/constants public (`dumpSource`,
`dumpSourceString`, `setBreakPointOnFirstLine`, `bun_aliases`)
- Updated `ModuleLoader.zig` to import the new modules

## Testing

- Build passes successfully (`bun bd`)
- Basic module loading verified with smoke tests
- Existing resolve tests continue to pass

🤖 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>
2025-10-25 20:43:02 -07:00
Meghan Denny
a2b262ed69 ci: update bun version to 1.3.1 (#24053) [publish images] 2025-10-25 15:53:02 -07:00
Meghan Denny
fb1fbe62e6 ci: update alpine linux to 3.22 (#24052) [publish images] 2025-10-25 15:52:34 -07:00
Jarred Sumner
d2c2842420 Autoformat 2025-10-25 00:05:28 -07:00
Jarred Sumner
0fba69d50c Add some internal deprecation @compileError messages 2025-10-24 23:42:20 -07:00
SUZUKI Sosuke
f4b6396eac Fix unhandled exception in JSC__JSPromise__wrap when resolving promise (#23961)
### What does this PR do?

Previously, `JSC__JSPromise__wrap` would call
`JSC::JSPromise::resolvedPromise(globalObject, result)` without checking
if an exception was thrown during promise resolution. This
could happen in certain edge cases, such as when the result value is a
thenable that triggers stack overflow, or when the promise resolution
mechanism itself encounters an error.
When such exceptions occurred, they would escape back to the Zig code,
causing the CatchScope assertion to fail with "ASSERTION FAILED:
Unexpected exception observed on thread"
instead of being properly handled.

This PR adds an exception check immediately after calling
`JSC::JSPromise::resolvedPromise()` and before the `RELEASE_AND_RETURN`
macro. If an exception is detected, the function
now clears it and returns a rejected promise with the exception value,
ensuring consistent error handling behavior. This matches the pattern
already used earlier in the function
for the initial function call exception handling.

### How did you verify your code works?

new and existing tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-24 21:36:33 -07:00
robobun
cfe561a083 fix: allow lifecycle hooks to accept options as second parameter (#24039)
## Summary

Fixes #23133

This PR fixes a bug where lifecycle hooks (`beforeAll`, `beforeEach`,
`afterAll`, `afterEach`) would throw an error when called with a
function and options object:

```typescript
beforeAll(() => {
  console.log("beforeAll")
}, { timeout: 10_000 })
```

Previously, this would throw: `error: beforeAll() expects a function as
the second argument`

## Root Cause

The issue was in `ScopeFunctions.parseArguments()` at
`src/bun.js/test/ScopeFunctions.zig:342`. When parsing two arguments, it
always treated them as `(description, callback)` instead of checking if
they could be `(callback, options)`.

## Solution

Updated the two-argument parsing logic to check if the first argument is
a function and the second is not a function. In that case, treat them as
`(callback, options)` instead of `(description, callback)`.

## Changes

- Modified `src/bun.js/test/ScopeFunctions.zig` to handle `(callback,
options)` case
- Added regression test at `test/regression/issue/23133.test.ts`

## Testing

 Verified the fix works with the reproduction case from the issue
 Added comprehensive regression test covering all lifecycle hooks with
both object and numeric timeout options
 All existing jest-hooks tests still pass
 Test fails with `USE_SYSTEM_BUN=1` and passes with the fixed build

🤖 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: pfg <pfg@pfg.pw>
2025-10-24 19:30:43 -07:00
robobun
5a7b824091 fix(css): process color-scheme rules inside @layer blocks (#24034)
## Summary

Fixes #20689

Previously, `@layer` blocks were not being processed through the CSS
minifier, which meant that `color-scheme` properties inside `@layer`
blocks would not get the required `--buncss-light`/`--buncss-dark`
variable injections needed for browsers that don't support the
`light-dark()` function.

## Changes

- Implemented proper minification for `LayerBlockRule` in
`src/css/rules/rules.zig:218-221`
- Added recursive call to `minify()` on nested rules, matching the
behavior of other at-rules like `@media` and `@supports`
- Added comprehensive tests for `color-scheme` inside `@layer` blocks

## Test Plan

Added three new test cases in `test/js/bun/css/css.test.ts`:
1. Simple `@layer` with `color-scheme: dark`
2. Named layers (`@layer shm.colors`) with multiple rules
3. Anonymous `@layer` with `color-scheme: light dark` (generates media
query)

All tests pass:
```bash
bun bd test test/js/bun/css/css.test.ts -t "color-scheme"
```

## Before

```css
/* Input */
@layer shm.colors {
  body.theme-dark {
    color-scheme: dark;
  }
}

/* Output (broken - no variables) */
@layer shm.colors {
  body.theme-dark {
    color-scheme: dark;
  }
}
```

## After

```css
/* Input */
@layer shm.colors {
  body.theme-dark {
    color-scheme: dark;
  }
}

/* Output (fixed - variables injected) */
@layer shm.colors {
  body.theme-dark {
    --buncss-light: ;
    --buncss-dark: initial;
    color-scheme: dark;
  }
}
```

🤖 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>
2025-10-24 19:27:14 -07:00
robobun
a3f18b9e0e feat(test): implement onTestFinished hook for bun:test (#24038)
## Summary

Implements `onTestFinished()` for `bun:test`, which runs after all
`afterEach` hooks have completed.

## Implementation

- Added `onTestFinished` export to the test module in `jest.zig`
- Modified `genericHook` in `bun_test.zig` to handle `onTestFinished` as
a special case that:
  - Can only be called inside a test (not in describe blocks or preload)
  - Appends hooks at the very end of the execution sequence
- Added comprehensive tests covering basic ordering, multiple callbacks,
async callbacks, and interaction with other hooks

## Execution Order

When called inside a test:
1. Test body executes
2. `afterAll` hooks (if added inside the test)
3. `afterEach` hooks
4. `onTestFinished` hooks 

## Test Plan

-  All new tests pass with `bun bd test`
-  Tests correctly fail with `USE_SYSTEM_BUN=1` (feature not in
released version)
-  Verifies correct ordering with `afterEach`, `afterAll`, and multiple
`onTestFinished` calls
-  Tests async `onTestFinished` callbacks

🤖 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>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: pfg <pfg@pfg.pw>
2025-10-24 19:07:40 -07:00
robobun
afd125fc12 docs(env_var): document silent error handling behavior (#24043)
### What does this PR do?

This PR adds documentation comments to `src/env_var.zig` that explain
the silent error handling behavior for environment variable
deserialization, based on the documentation from the closed PR #24036.

The comments clarify:

1. **Module-level documentation**: Environment variables may fail to
parse silently. When they do, the default behavior is to show a debug
warning and treat them as not set. This is intentional to avoid panics
from environment variable pollution.

2. **Inline documentation**: Deserialization errors cannot panic. Users
needing more robust configuration mechanisms should consider
alternatives to environment variables.

This documentation complements the behavior change introduced in commit
0dd6aa47ea which replaced panic with debug_warn.

### How did you verify your code works?

Ran `bun bd` successfully - the build completed without errors.

🤖 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>
2025-10-24 14:43:05 -07:00
Jarred Sumner
0dd6aa47ea Replace panic with debug warn
Closes https://github.com/oven-sh/bun/pull/24025
2025-10-24 14:14:15 -07:00
Meghan Denny
ab1395d38e zig: env_var: fix output port (#24026) 2025-10-24 12:11:20 -07:00
Marko Vejnovic
e76570f452 feat(ENG-21362): Environment Variables Store (#23930) 2025-10-23 23:08:08 -07:00
SUZUKI Sosuke
d648547942 Fix segv when process.nextTick is overwritten (#23971)
### What does this PR do?

When `process.nextTick` is overwritten, segv will be occured via
internal `processTick` call.
This patch fixes it.

### How did you verify your code works?

Tests.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-23 22:16:01 -07:00
Jarred Sumner
787a46d110 Write more data faster (#23989)
### What does this PR do?

### How did you verify your code works?
2025-10-23 17:52:13 -07:00
Braden Wong
29028bbabe docs(watch): rename filename to relativePath in recursive example (#23990)
When using `fs.watch()` with `recursive: true`, the callback receives a
relative path from the watched directory (e.g., `'subdir/file.txt'`),
not just a filename.

Renaming the parameter from `filename` to `relativePath` makes this
behavior immediately clear to developers.

**Before:**
```ts
(event, filename) => {
  console.log(`Detected ${event} in ${filename}`);
}
```

**After:**
```ts
(event, relativePath) => {
  console.log(`Detected ${event} in ${relativePath}`);
}
```

This is a documentation-only change that improves clarity without
altering any functionality.

Co-authored-by: Braden Wong <git@bradenwong.com>
2025-10-23 15:59:35 -07:00
Logan Brown
5a82e85876 Fix integer overflow when reading MySQL OK packets (#23993)
### Description
This PR fixes a crash caused by integer underflow in
`OKPacket.decodeInternal`.
Previously, when `read_size` exceeded `packet_size`, the subtraction  
`packet_size - read_size` wrapped around, producing a huge `count` value
passed into `reader.read()`. This led to an integer overflow panic at
runtime.

### What does this PR do
- Added a safe subtraction guard in `decodeInternal` to clamp
`remaining` to `0`
  when `read_size >= packet_size`.  
- Ensures empty or truncated OK packets no longer cause crashes.  
- Behavior for valid packets remains unchanged.

### Impact
Prevents integer overflow panics in MySQL OK packet parsing, improving  
stability when handling short or empty responses (e.g., queries that  
return no rows or minimal metadata).

### How did you verify your code works?
Tested with proof of concept:
https://github.com/Lillious/Bun-MySql-Integer-Overflow-PoC

---------

Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
2025-10-23 13:30:49 -07:00
taylor.fish
7bf67e78d7 Fix incorrect/suspicious uses of ZigString.Slice.cloneIfNeeded (#23937)
`ZigString.Slice.cloneIfNeeded` does *not* guarantee that the returned
slice will have been allocated by the provided allocator, which makes it
very easy to use this method incorrectly.

(For internal tracking: fixes ENG-21284)
2025-10-23 13:17:51 -07:00
SUZUKI Sosuke
fb75e077a2 Add missing empty JSValue checking for Bun.cookieMap#delete (#23951)
### What does this PR do?

Adds missing null checking for `Bun.CookieMap#delete`.

### How did you verify your code works?

Tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-23 13:14:36 -07:00
avarayr
24d9d642de ProxyTunnel: close-delimited responses via proxy cause ECONNRESET (#23719)
fixes: oven-sh/bun#23717

### What does this PR do?
- Align ProxyTunnel.onClose with
[HTTPClient.onClose](https://github.com/oven-sh/bun/blob/bun-v1.3.0/src/http.zig#L223-L241):
when a tunneled HTTPS response is in-progress and either
  - parsing chunked trailers (trailer-line states), or
- transfer-encoding is identity with content_length == null while in
.body,
treat EOF as end-of-message and complete the request, rather than
ECONNRESET.
- Schedule proxy deref instead of deref inside callbacks to avoid
lifetime hazards.

### How did you verify your code works?
- `test/js/bun/http/proxy.test.ts`: raw TLS origin returns
close-delimited 200 OK; verified no ECONNRESET and body delivered.
- Test suite passes under bun bd test.

## Risk/compat
- Only affects CONNECT/TLS path. Direct HTTP/HTTPS unchanged. Behavior
mirrors existing
[HTTPClient.onClose](https://github.com/oven-sh/bun/blob/bun-v1.3.0/src/http.zig#L223-L241).

## Repro (minimal)
See issue; core condition is no Content-Length and no Transfer-Encoding
(close-delimited).

Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
2025-10-23 13:04:23 -07:00
robobun
b278c85753 Refactor NapiEnv to use ExternalShared for safer reference counting (#23982)
## Summary

This PR refactors `NapiEnv` to use `bun.ptr.ExternalShared` instead of
manual `ref()`/`deref()` calls, fixing a use-after-free bug in the NAPI
implementation.

## Bug Fixed

The original issue was in `ThreadSafeFunction.deinit()`:
1. `maybeQueueFinalizer()` schedules a task that holds a pointer to
`this` (which includes `this.env`)
2. The task will eventually call `onDispatch()` → `deinit()`
3. But `deinit()` immediately calls `this.env.deref()` before the task
completes
4. This could cause the `NapiEnv` reference count to go to 0 while the
pointer is still in use

## Changes

### Core Changes
- Added `NapiEnv.external_shared_descriptor` and `NapiEnv.EnvRef` type
alias
- Changed struct fields from `*NapiEnv` to `NapiEnv.EnvRef` where
ownership is required:
  - `ThreadSafeFunction.env`
  - `napi_async_work.env`
  - `Finalizer.env` (now `NapiEnv.EnvRef.Optional`)

### API Changes
- Use `.get()` to access the raw `*NapiEnv` pointer from `EnvRef`
- Use `.cloneFromRaw(env)` when storing `env` in long-lived structs
- Use `EnvRef.deinit()` instead of manual `env.deref()`
- Removed manual `env.ref()` calls (now handled automatically by
`cloneFromRaw`)

### Safety Improvements
- Reference counting is now managed by the `ExternalShared` wrapper
- Prevents manual ref/deref mistakes
- Ensures proper cleanup even when operations are cancelled or fail
- No more use-after-free risks from premature deref

## Testing

Built successfully with `bun bd`. NAPI tests pass (66/83 tests, with 17
timeouts that appear to be pre-existing issues).

## Implementation Notes

Following the pattern from `Blob.zig` and `array_buffer.zig`, structs
that own a reference use `NapiEnv.EnvRef`, while functions that only
borrow temporarily continue to use `*NapiEnv` parameters.

The `ExternalShared` interface ensures:
- `.clone()` increments the ref count
- `.deinit()` decrements the ref count
- No direct access to the internal ref/deref functions

This makes the ownership semantics explicit and type-safe.

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: taylor.fish <contact@taylor.fish>
2025-10-22 21:46:26 -07:00
robobun
066f706a99 Fix CSS view-transition pseudo-elements with class selectors (#23957) 2025-10-22 16:45:03 -07:00
robobun
0ad4e6af2d Fix Buffer.isEncoding('') to return false (#23968)
## Summary
Fixes `Buffer.isEncoding('')` to return `false` instead of `true`,
matching Node.js behavior.

## Description
Previously, `Buffer.isEncoding('')` incorrectly returned `true` in Bun,
while Node.js correctly returns `false`. This was caused by
`parseEnumerationFromView` in `JSBufferEncodingType.cpp` treating empty
strings (length 0) as valid utf8 encoding.

The fix modifies the switch statement to return `std::nullopt` for empty
strings, along with other invalid short strings.

## Changes
- Modified `src/bun.js/bindings/JSBufferEncodingType.cpp` to return
`std::nullopt` for empty strings
- Added regression test `test/regression/issue23966.test.ts`

## Test Plan
- [x] Test fails with `USE_SYSTEM_BUN=1 bun test
test/regression/issue23966.test.ts` (confirms bug exists)
- [x] Test passes with `bun bd test test/regression/issue23966.test.ts`
(confirms fix works)
- [x] Verified behavior matches Node.js v24.3.0
- [x] All test cases for valid/invalid encodings pass

Fixes #23966

🤖 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>
2025-10-22 16:15:29 -07:00
Jarred Sumner
b90abdda08 BUmp 2025-10-22 12:13:14 -07:00
Dylan Conway
89fa0f3439 Refactor napi_env to use Ref-counted NapiEnv (#23940)
### What does this PR do?

Replaces raw napi_env pointers with WTF::Ref<NapiEnv> for improved
memory management and safety. Updates related classes, function
signatures, and finalizer handling to use reference counting. Adds
ref/deref methods to NapiEnv and integrates them in Zig and C++ code
paths, ensuring proper lifecycle management for N-API environments.

### How did you verify your code works?
2025-10-21 22:58:46 -07:00
Jarred Sumner
72f1ffdaf7 Silence non-actionable worker_threads.Worker option warnings (#23941)
### What does this PR do?

### How did you verify your code works?
2025-10-21 22:56:36 -07:00
Meghan Denny
bb5f0f5d69 node:net: another memory leak fix (#23936)
found with https://github.com/oven-sh/bun/pull/21663 again
case found in `test/js/bun/net/socket.test.ts`
test `"should throw when a socket from a file descriptor has a bad file
descriptor"`
2025-10-21 21:07:08 -07:00
robobun
a3c43dc8b9 Fix Windows bunx fast path index out of bounds panic (#23938)
## Summary

Fixed a bug in the Windows bunx fast path code where UTF-8 byte length
was incorrectly used instead of UTF-16 code unit length when calculating
buffer offsets.

## Details

In `run_command.zig:1565`, the code was using `target_name.len` (UTF-8
byte length) instead of `encoded.len` (UTF-16 code unit length) when
calculating the total path length. This caused an index out of bounds
panic when package names contained multi-byte UTF-8 characters.

**Example scenario:**
- Package name contains character "中" (U+4E2D)
- UTF-8: 3 bytes (0xE4 0xB8 0xAD) → `target_name.len` counts as 3
- UTF-16: 1 code unit (0x4E2D) → `encoded.len` counts as 1
- Using the wrong length led to: `panic: index out of bounds: index 62,
len 60`

## Changes

- Changed line 1565 from `target_name.len` to `encoded.len`

## Test plan

- [x] Build compiles successfully
- [x] Code review confirms the fix addresses the root cause
- [ ] Windows-specific testing (if available)

Fixes the panic reported in Sentry/crash reports.

🤖 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>
2025-10-21 19:42:01 -07:00
Jarred Sumner
45841d6630 Check if toSlice has a bug (#23889)
### What does this PR do?
toSlice has a bug

### How did you verify your code works?

---------

Co-authored-by: taylor.fish <contact@taylor.fish>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2025-10-21 19:22:55 -07:00
taylor.fish
d846e9a1e7 Fix bun.String.toOwnedSliceReturningAllASCII (#23925)
`bun.String.toOwnedSliceReturningAllASCII` is supposed to return a
boolean indicating whether or not the string is entirely composed of
ASCII characters. However, the current implementation frequently
produces incorrect results:

* If the string is a `ZigString`, it always returns true, even though
`ZigString`s can be UTF-16 or Latin-1.
* If the string is a `StaticZigString`, it always returns false, even
though `StaticZigStrings` can be all ASCII.
* If the string is a 16-bit `WTFStringImpl`, it always returns false,
even though 16-bit `WTFString`s can be all ASCII.
* If the string is empty, it always returns false, even though empty
strings are valid ASCII strings.

`toOwnedSliceReturningAllASCII` is currently used in two places, both of
which assume its answer is accurate:

* `bun.webcore.Blob.fromJSWithoutDeferGC`
* `bun.api.ServerConfig.fromJS`

(For internal tracking: fixes ENG-21249)
2025-10-21 18:42:39 -07:00
SUZUKI Sosuke
06eea5213a Add missing exception check for ReadableStream (#23932)
### What does this PR do?

Adds missing exception check for ReadableStream.

### How did you verify your code works?

Tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-21 18:19:34 -07:00
Jarred Sumner
1aaabcf4de Add missing error handling in ShellWriter's start() method & delete assert() footgun (#23935)
### 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>
2025-10-21 18:18:37 -07:00
Marko Vejnovic
3bc78598c6 bug(SlicedString.zig): Fix incorrect assertion in SlicedString.sub (#23934)
### What does this PR do?

Fixes a small bug I found in https://github.com/oven-sh/bun/pull/23107
which caused `SlicedString` not to correctly provide us with subslices.

This would have been a **killer** use-case for the interval utility we
decided to reject in https://github.com/oven-sh/bun/pull/23882. Consider
how nice the code could've been:

```zig
pub inline fn sub(this: SlicedString, input: string) SlicedString {
    const buf_r = bun.math.interval.fromSlice(this.buf);
    const inp_r = bun.math.interval.fromSlice(this.input);

    if (Environment.allow_assert) {
        if (!buf_r.superset(inp_r)) {
            bun.Output.panic("SlicedString.sub input [{}, {}) is not a substring of the " ++
                "slice [{}, {})", .{ start_i, end_i, start_buf, end_buf });
        }
    }
    return SlicedString{ .buf = this.buf, .slice = input };
}
```

That's a lot more readable than the middle-school algebra we have here,
but here we are.

### How did you verify your code works?

CI

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-21 17:54:44 -07:00
Dylan Conway
12e22af382 set C_STANDARD to 17 (#23928)
### What does this PR do?
msvc doesn't support c23 yet
### How did you verify your code works?

---------

Co-authored-by: Marko Vejnovic <marko@bun.com>
2025-10-21 16:25:29 -07:00
robobun
88fa296dcd Add GitHub issue deduplication automation (#23926)
## Summary

This PR adds a Claude Code-powered issue deduplication system to help
reduce duplicate issues in the Bun repository.

### What's included:

1. **`/dedupe` slash command** (`.claude/commands/dedupe.md`)
- Claude Code command to find up to 3 duplicate issues for a given
GitHub issue
   - Uses parallel agent searches with diverse keywords
   - Filters out false positives

2. **Automatic dedupe on new issues**
(`.github/workflows/claude-dedupe-issues.yml`)
   - Runs automatically when a new issue is opened
   - Can also be triggered manually via workflow_dispatch
   - Uses the Claude Code base action to run the `/dedupe` command

3. **Auto-close workflow**
(`.github/workflows/auto-close-duplicates.yml`)
   - Runs daily to close issues marked as duplicates after 3 days
   - Only closes if:
     - Issue has a duplicate detection comment from bot
     - Comment is 3+ days old
     - No comments or activity after duplicate comment
     - Author hasn't reacted with 👎 to the duplicate comment

4. **Auto-close script** (`scripts/auto-close-duplicates.ts`)
   - TypeScript script that handles the auto-closing logic
   - Fetches open issues and checks for duplicate markers
   - Closes issues with proper labels and notifications

### How it works:

1. When a new issue is opened, the workflow runs Claude Code to analyze
it
2. Claude searches for duplicates and comments on the issue if any are
found
3. Users have 3 days to respond if they disagree
4. After 3 days with no activity, the issue is automatically closed

### Requirements:

- `ANTHROPIC_API_KEY` secret needs to be set in the repository settings
for the dedupe workflow to run

## Test plan

- [x] Verified workflow files have correct syntax
- [x] Verified script references correct repository (oven-sh/bun)
- [x] Verified slash command matches claude-code implementation
- [ ] Test workflow manually with workflow_dispatch (requires
ANTHROPIC_API_KEY)
- [ ] Monitor initial runs to ensure proper behavior

🤖 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>
2025-10-21 14:57:22 -07:00
robobun
cd8043b76e Fix Bun.build() compile API to properly apply sourcemaps (#23916)
## Summary

Fixes a bug where the `Bun.build()` API with `compile: true` did not
properly apply sourcemaps, even when `sourcemap: "inline"` was
specified. This resulted in error stack traces showing bundled virtual
paths (`/$bunfs/root/`) instead of actual source file names and line
numbers.

## Problem

The CLI `bun build --compile --sourcemap` worked correctly, but the
equivalent API call did not:

```javascript
// This did NOT work (before fix)
await Bun.build({
  entrypoints: ['./app.js'],
  compile: true,
  sourcemap: "inline"  // <-- Was ignored/broken
});
```

Error output showed bundled paths:
```
error: Error from helper module
      at helperFunction (/$bunfs/root/app.js:4:9)  //  Wrong path
      at main (/$bunfs/root/app.js:9:17)            //  Wrong line numbers
```

## Root Cause

The CLI explicitly overrides any sourcemap type to `.external` when
compile mode is enabled (in `/workspace/bun/src/cli/Arguments.zig`):

```zig
// when using --compile, only `external` works
if (ctx.bundler_options.compile) {
    opts.source_map = .external;
}
```

The API implementation in `JSBundler.zig` was missing this override.

## Solution

Added the same sourcemap override logic to `JSBundler.zig` when compile
mode is enabled:

```zig
// When using --compile, only `external` sourcemaps work, as we do not
// look at the source map comment. Override any other sourcemap type.
if (this.source_map != .none) {
    this.source_map = .external;
}
```

Now error output correctly shows source file names:
```
error: Error from helper module
      at helperFunction (helper.js:2:9)  //  Correct file
      at main (app.js:4:3)                //  Correct line numbers
```

## Tests

Added comprehensive test coverage in
`/workspace/bun/test/bundler/bun-build-compile-sourcemap.test.ts`:

-  `sourcemap: "inline"` works
-  `sourcemap: true` works
-  `sourcemap: "external"` works
-  Multiple source files show correct file names
-  Without sourcemap, bundled paths are shown (expected behavior)

All tests:
-  Fail with `USE_SYSTEM_BUN=1` (confirms bug exists)
-  Pass with `bun bd test` (confirms fix works)
-  Use `tempDir()` to avoid disk space issues

🤖 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>
2025-10-21 14:25:08 -07:00
Dylan Conway
840c6ca471 fix(install): avoid sleep for peer tasks when there are none (#23881)
### What does this PR do?

### How did you verify your code works?

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-21 14:24:20 -07:00
Dylan Conway
150338faab implement publicHoistPattern and hoistPattern (#23567)
### What does this PR do?
Adds support for `publicHoistPattern` in `bunfig.toml` and
`public-hoist-pattern` from `.npmrc`. This setting allows you to select
transitive packages to hoist to the root node_modules making them
available for all workspace packages.

```toml
[install]
# can be a string
publicHoistPattern = "@types*"
# or an array
publicHoistPattern = [ "@types*", "*eslint*" ]
```

`publicHoistPattern` only affects the isolated linker.

---

Adds `hoistPattern`. `hoistPattern` is the same as `publicHoistPattern`,
but applies to the `node_modules/.bun/node_modules` directory instead of
the root node_modules. Also the default value of `hoistPattern` is `*`
(everything is hoisted to `node_modules/.bun/node_modules` by default).

---

Fixes a determinism issue constructing the
`node_modules/.bun/node_modules` directory.

---

closes #23481
closes #6160
closes #23548
### How did you verify your code works?
Added tests for
- [x] only include patterns
- [x] only exclude patterns
- [x] mix of include and exclude
- [x] errors for unexpected expression types
- [x] excluding direct dependency (should still include)
- [x] match all with `*`
- [x] string and array expression types

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-21 14:18:39 -07:00
Jarred Sumner
7662de9632 Add missing libuv errcodes UV_ENOEXEC and UV_EFTYPE (#23854)
### What does this PR do?

### How did you verify your code works?
2025-10-20 23:46:44 -07:00
Jarred Sumner
789a5f4078 Fix URL heap size reporting bug (#23887)
### What does this PR do?

`short` is signed in C++ by default and not unsigned. Switched to
`uint16_t` so it's unambiguous.

### How did you verify your code works?

There is a test

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-10-20 23:04:54 -07:00
Dylan Conway
965051fd1f Revert "WIP: fix windows ENOTCONN (#23772)" (#23886)
This reverts commit 4539d241a1.

### What does this PR do?

### How did you verify your code works?
2025-10-20 22:38:18 -07:00
pfg
7750afa29b Updates eqlComptime to resolve the rope if needed (#23883)
### What does this PR do?

Fixes #23723 

### How did you verify your code works?

Test case
2025-10-20 21:18:47 -07:00
taylor.fish
2c86fdb818 Convert os.environ to WTF-8 (#23885)
* Fixes #17773
* Fixes #13728
* Fixes #11041
* Fixes ENG-21082
* Fixes https://github.com/oven-sh/bun/issues/23482
* Fixes https://github.com/oven-sh/bun/issues/23734
* Fixes https://github.com/oven-sh/bun/issues/23488
* Fixes https://github.com/oven-sh/bun/issues/23485

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-20 20:52:35 -07:00
Marko Vejnovic
07317193fe chore: Mutable deinitializers (#23876) 2025-10-20 20:39:46 -07:00
robobun
3e53ada574 Fix assertion failure when using --production flag (#23821)
Fixes #19652

## Summary

Fixes a crash that occurred when using the `--production` flag with `bun
build`, particularly on Windows where assertions are enabled in release
builds.

## Root Cause

The crash occurred because an assertion for `jsx.development` was
running **before** `jsx.development` was properly configured. The
problematic sequence was:

1. Set `NODE_ENV=production` in env map
2. Call `configureDefines()` which reads `NODE_ENV` and calls
`setProduction(true)`, setting `jsx.development=false`
3.  **Assert `jsx.development` is false** (assertion fired here, before
line 203 below)
4. Set `jsx.development = !production` on line 203 (too late)

## Changes

This PR reorders the code to move the assertion **after**
`jsx.development` is properly set:

1. Set both `BUN_ENV` and `NODE_ENV` to `"production"` in env map
2. Call `configureDefines()` 
3. Set `jsx.development = !production` (now happens first)
4.  **Assert `jsx.development` is false** (now runs after it's set)

Also adds `BUN_ENV=production` to match the behavior of setting
`NODE_ENV`.

## Test Plan

Added regression test in `test/regression/issue/19652.test.ts` that
verifies `bun build --production` doesn't crash.

The test:
-  Passes on this branch
-  Would fail on main (assertion failure)

🤖 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: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-10-20 20:37:51 -07:00
Jarred Sumner
25a8dea38b Ensure we add sourcemappings for S.Comment (#23871)
### What does this PR do?



### How did you verify your code works?

---------

Co-authored-by: pfg <pfg@pfg.pw>
2025-10-20 20:36:25 -07:00
Meghan Denny
3520393b25 zig: fix s3 list-objects memory leak (#23880) 2025-10-20 20:28:14 -07:00
Dylan Conway
8b8e98d0fb fix(install): workspace self dependencies with isolated linker (#23609)
### What does this PR do?
Fixes a bug preventing workspace self dependencies from getting
symlinked to the workspace node_modules

Fixes #23605
### How did you verify your code works?
Added a test for normal `"workspace:*"` deps, and `"workspace:."` under
a different name.

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-20 19:48:47 -07:00
robobun
b1f83d0bb2 fix: Response.json() throws TypeError for non-JSON serializable top-level values (#21258)
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: Meghan Denny <meghan@bun.com>
2025-10-20 19:46:22 -07:00
Jarred Sumner
32a28385dd Guard fs.watchFile's last_stat field with a mutex (#23840)
### What does this PR do?

We read and write this field on multiple threads. Let's add a mutex.

Fixes BUN-MGB

### How did you verify your code works?

---------

Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
2025-10-20 19:40:41 -07:00
Marko Vejnovic
881514a18a chore: Remove some dead code (#23879)
### What does this PR do?

Removes unused code.

### How did you verify your code works?

CI
2025-10-20 19:39:27 -07:00
Meghan Denny
6dffd32d52 node: fix test-fs-promises-file-handle-readLines.mjs (#22399)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-20 19:39:10 -07:00
robobun
5971bf67ef fix: buffer allocation for path operations with very long paths (#23819)
## Summary

Fixed an off-by-one error in buffer allocation for several path module
functions when handling paths longer than `PATH_SIZE` (typically 4096
bytes on most platforms).

## Changes

- `normalizeJS_T`: Added +1 to buffer allocation for null terminator
- `relativeJS_T`: Added +1 to buffer allocation for null terminator  
- `toNamespacedPathJS_T`: Added +9 bytes (8 for possible UNC prefix + 1
for null terminator)

## Test plan

- Added tests for `path.normalize()` with paths up to 100,000 characters
- Added tests for `path.relative()` with very long paths
- All existing path tests continue to pass

The issue occurred because when a path is exactly equal to or longer
than `PATH_SIZE`, the buffer was allocated with size equal to the path
length, but then a null terminator was written at `buf[bufSize]`, which
was out of bounds.

🤖 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>
2025-10-20 19:28:34 -07:00
robobun
686998ed3d Fix panic when WebSocket close frame is fragmented across TCP packets (#23832)
## Summary

Fixes a panic that occurred when a WebSocket close frame's payload was
split across multiple TCP packets.

## The Bug

The panic occurred at `websocket_client.zig:681`:
```
panic: index out of bounds: index 24, len 14
```

This happened when:
- A close frame had a payload of 24 bytes (2 byte code + 22 byte reason)
- The first TCP packet contained 14 bytes (header + partial payload)
- The code tried to access `data[2..24]` causing the panic

## Root Causes

1. **Bounds checking issue**: The code assumed all close frame data
would arrive in one packet and tried to `@memcpy` without verifying
sufficient data was available.

2. **Premature flag setting**: `close_received = true` was set
immediately upon entering the close state. This prevented `handleData`
from being called again when the remaining bytes arrived (early return
at line 354).

## The Fix

Implemented proper fragmentation handling for close frames, following
the same pattern used for ping frames:

- Added `close_frame_buffering` flag to track buffering state
- Buffer incoming data incrementally using the existing
`ping_frame_bytes` buffer
- Track total expected length and bytes received so far
- Only set `close_received = true` after all bytes are received
- Wait for more data if the frame is incomplete

## Testing

- Created two regression tests that fragment close frames across
multiple packets
- All existing WebSocket tests pass (`test/js/web/websocket/`)
- Verified the original panic no longer occurs

## Related

This appears to be the root cause of crashes reported on Windows when
WebSocket connections close, particularly when close frames have reasons
that get fragmented by the network stack.

---

🤖 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>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-20 18:42:19 -07:00
Jarred Sumner
b3c69e5a4e it's bun.com now 2025-10-20 18:01:25 -07:00
Ciro Spaciari
1e3e693f4a fix(MySQL) ref and status usage (#23873)
### What does this PR do?
Let MySQL unref when idle and make sure that is behaving like this.
Only set up the timers after all status changes are complete since the
timers rely on the status to determine timeouts, this was causing the
CPU usage spike to 100% (thats why only happened in TLS)
CPU usage it self will be improved in
https://github.com/oven-sh/bun/pull/23700 not in this PR

Fixes: https://github.com/oven-sh/bun/issues/23273
Fixes: https://github.com/oven-sh/bun/issues/23256
### How did you verify your code works?
Test

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-10-20 17:40:48 -07:00
robobun
2557b1cc2a Add email field support to .npmrc for registry authentication (#23709)
### What does this PR do?

This PR implements support for the `email` field in `.npmrc` files for
registry scope authentication. Some private registries (particularly
Nexus) require the email field to be specified in the registry
configuration alongside username/password or token authentication.

The email field can now be specified in `.npmrc` files like:
```ini
//registry.example.com/:email=user@example.com
//registry.example.com/:username=myuser
//registry.example.com/:_password=base64encodedpassword
```

### How did you verify your code works?

1. **Built Bun successfully** - Confirmed the code compiles without
errors using `bun bd --debug`

2. **Wrote comprehensive unit tests** - Added two test cases to
`test/cli/install/npmrc.test.ts`:
   - Test for standalone email field parsing
   - Test for email combined with username/password authentication

3. **Verified tests pass** - Ran `bun bd test
test/cli/install/npmrc.test.ts -t "email"` and confirmed both tests
pass:
   ```
   ✓ 2 pass
   ✓ 0 fail
   ✓ 6 expect() calls
   ```

4. **Code changes include**:
   - Added `email` field to `NpmRegistry` struct in `src/api/schema.zig`
   - Updated `encode()` and `decode()` methods to handle the email field
   - Modified `ini.zig` to parse and store the email field from `.npmrc`
- Removed email from the unsupported options warning (certfile and
keyfile remain unsupported)
- Updated all `NpmRegistry` struct initializations to include the email
field
   - Updated `loadNpmrcFromJS` test API to return the email field

🤖 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>
2025-10-20 16:32:04 -07:00
robobun
ebc0cfeacd fix(yaml): double-quoted strings with '...' incorrectly trigger document end error (#23491)
### What does this PR do?

Fixes #23489

The YAML parser was incorrectly treating `...` inside double-quoted
strings as document end markers, causing parse errors for strings
containing ellipsis, particularly affecting internationalized text.

### Example of the bug:
```yaml
balance: "👛 لا تمتلك محفظة... !"
```

This would fail with: `error: Unexpected document end`

### Root cause:

The bug was introduced in commit fcbd57ac48 which attempted to optimize
document marker detection by using `self.line_indent == .none` instead
of tracking newlines with a local flag. However, this check was
incomplete - it didn't track whether we had just processed a newline
character.

### The fix:

Restored the `nl` (newline) flag pattern from the single-quoted scanner
and combined it with the `line_indent` check. Document markers `...` and
`---` are now only recognized when **all** of these conditions are met:

1. We're after a newline (`nl == true`)
2. We're at column 0 (`self.line_indent == .none`)
3. Followed by whitespace or EOF

This allows `...` to appear freely in double-quoted strings while still
correctly recognizing actual document end markers at the start of lines.

### How did you verify your code works?

1. Reproduced the original issue from #23489
2. Applied the fix and verified all test cases pass:
   - Original Arabic text with emoji: `"👛 لا تمتلك محفظة... !"`
   - Various `...` positions: start, middle, end
   - Both single and double quotes
   - Multiline strings with indented `...` (issue #22392)
3. Created regression test in `test/regression/issue/23489.test.ts`
4. Verified existing YAML tests still pass (514 pass, up from 513)

cc @dylan-conway for review

---------

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>
2025-10-20 14:19:22 -07:00
Jarred Sumner
abb85018df Fixes #23649 (#23853)
### What does this PR do?

Closes #23712
Fixes #23649
Fixes regression introduced in #19817

### How did you verify your code works?

Test
2025-10-20 14:07:31 -07:00
robobun
1c4d8b1c1c fix(sql): throw proper exception for invalid MySQL parameter types (#23839)
## Summary

Fixes a panic that occurred when passing `NumberObject` or
`BooleanObject` as MySQL query parameters.

**Panic message:** `A JavaScript exception was thrown, but it was
cleared before it could be read.`

## Root Cause

The `FieldType.fromJS` function in `src/sql/mysql/MySQLTypes.zig` was
returning `error.JSError` without throwing a JavaScript exception first
for:
- `NumberObject` (created via `new Number(42)`)
- `BooleanObject` (created via `new Boolean(true)`)
- Non-indexable types

This violated the contract that `error.JSError` means "an exception has
already been thrown and is ready to be taken."

## Call Chain

1. User executes `await sql\`SELECT ${new Number(42)} as value\``
2. `FieldType.fromJS()` detects `.NumberObject` and returns
`error.JSError` without throwing
3. Error propagates to `MySQLQuery.runPreparedQuery()`
4. Code checks `hasException()` → returns false (no exception exists!)
5. Calls `mysqlErrorToJS(globalObject, "...", error.JSError)`
6. `mysqlErrorToJS` tries to `takeException(error.JSError)` but there's
no exception
7. **PANIC**

## Fix

The fix throws a proper exception with a helpful message before
returning `error.JSError`:
- `"Cannot bind NumberObject to query parameter. Use a primitive number
instead."`
- `"Cannot bind BooleanObject to query parameter. Use a primitive
boolean instead."`
- `"Cannot bind this type to query parameter"`

## Test Plan

Added regression tests in `test/js/sql/sql-mysql.test.ts`:
- Test passing `NumberObject` as parameter
- Test passing `BooleanObject` as parameter

Both tests verify that a proper error is thrown instead of crashing.

Verified manually with local MySQL server that:
-  NumberObject now throws proper error (was crashing)
-  BooleanObject now throws proper error (was crashing)
-  Primitive numbers still work correctly

🤖 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>
2025-10-20 12:31:08 -07:00
robobun
3921f76ff8 Add --only-failures flag to bun:test (#23312)
## Summary

Adds a new `--only-failures` flag to `bun test` that only displays test
failures, similar to `--dots` but without printing dots for each test.

## Motivation

When running large test suites or in CI environments, users often only
care about test failures. The existing `--dots` reporter reduces
verbosity by showing dots, but still requires visual scanning to find
failures. The `--only-failures` flag provides a cleaner output by
completely suppressing passing tests.

## Changes

- Added `--only-failures` CLI flag in `Arguments.zig`
- Added `only_failures` boolean to the test reporters struct in
`cli.zig`
- Updated test output logic in `test_command.zig` to skip non-failures
when flag is set
- Updated `jest.zig` and `bun_test.zig` to handle the new flag
- Added comprehensive tests in `only-failures.test.ts`

## Usage

```bash
bun test --only-failures
```

Example output (only shows failures):
```
test/example.test.ts:
(fail) failing test
error: expect(received).toBe(expected)

Expected: 3
Received: 2

5 pass
1 skip
2 fail
Ran 8 tests across 1 file.
```

## Test Plan

- Verified `--only-failures` flag only shows failing tests
- Verified normal test output still works without the flag
- Verified `--dots` reporter still works correctly
- Added regression tests with snapshot comparisons

🤖 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: pfg <pfg@pfg.pw>
2025-10-19 23:31:29 -07:00
robobun
74fa49963c Fix: Error when using bun build --no-bundle with HTML entrypoint (#23572)
Fixes #23569

## Summary

HTML imports require bundling to work correctly, as they need to process
and transform linked assets (JS/CSS). When `--no-bundle` is used, no
bundling or transformation happens, which causes a crash.

This change adds validation to detect HTML entrypoints when
`--no-bundle` is used and provides a clear error message explaining that
"HTML imports are only supported when bundling".

## Changes

- Added validation in `src/cli/build_command.zig` to check for HTML
entrypoints when `--no-bundle` flag is used
- Shows clear error message: "HTML imports are only supported when
bundling"
- Added regression tests in `test/regression/issue/23569.test.ts`

## Test Plan

### Before
```bash
$ bun build ./index.html --no-bundle
# Crashes without helpful error
```

### After
```bash
$ bun build ./index.html --no-bundle
error: HTML imports are only supported when bundling
```

### Tests
-  Test with `--no-bundle` flag errors correctly
-  Test with `--no-bundle --outdir` errors correctly  
-  Test without `--no-bundle` works normally
-  All 3 regression tests pass

🤖 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>
2025-10-19 23:29:29 -07:00
Dylan Conway
fb2bf3fe83 fix(pack): always include bin even if not included by files (#23606)
### What does this PR do?
Fixes #23521
### How did you verify your code works?
Added 3 previously failing tests for `"bin"`, `"directories.bin"`, and
deduplicating entry in both `"bin.directories"` and `"files"`

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-19 23:28:59 -07:00
Dylan Conway
4539d241a1 WIP: fix windows ENOTCONN (#23772)
### 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>
2025-10-19 22:27:08 -07:00
github-actions[bot]
6f3dfa79bb deps: update elysia to 1.4.12 (#23820)
## What does this PR do?

Updates elysia to version 1.4.12

Compare: https://github.com/elysiajs/elysia/compare/1.4.11...1.4.12

Auto-updated by [this
workflow](https://github.com/oven-sh/bun/actions/workflows/update-vendor.yml)

Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2025-10-19 22:25:50 -07:00
Jarred Sumner
767c61d355 Fix memory leaks & blocking syscall in Bun Shell (#23636)
## Summary

Fixes two critical bugs in Bun Shell:

1. **Memory leaks & incorrect GC reporting**: Shell objects weren't
reporting their memory usage to JavaScriptCore's garbage collector,
causing memory to accumulate unchecked. Also fixes a leak where
`ShellArgs` wasn't being freed in `Interpreter.finalize()`.

2. **Blocking I/O on macOS**: Fixes a bug where writing large amounts of
data (>1MB) to pipes would block the main thread on macOS. The issue:
`sendto()` with `MSG_NOWAIT` flag blocks on macOS despite the flag, so
we now avoid the socket fast path unless the socket is already
non-blocking.

## Changes

- Adds `memoryCost()` and `estimatedSize()` implementations across shell
AST nodes, interpreter, and I/O structures
- Reports estimated memory size to JavaScriptCore GC via
`vm.heap.reportExtraMemoryAllocated()`
- Fixes missing `this.args.deinit()` call in interpreter finalization
- Fixes `BabyList.memoryCost()` to return bytes, not element count
- Conditionally uses socket fast path in IOWriter based on platform and
socket state

## Test plan

- [x] New test: `shell-leak-args.test.ts` - validates memory doesn't
leak during parsing/execution
- [x] New test: `shell-blocking-pipe.test.ts` - validates large pipe
writes don't block the main thread
- [x] Existing shell tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
2025-10-19 22:17:19 -07:00
robobun
e63a897c66 Add debug logging for test execution with BUN_DEBUG_jest=1 (#23796)
## Summary

Adds debug logging that prints the name of each test when it starts
running, controlled by the `BUN_DEBUG_jest=1` environment variable.

## Changes

- Modified `src/bun.js/test/Execution.zig` to add logging in the
`onEntryStarted()` function
- Added a scoped logger using `bun.Output.scoped(.jest, .visible)`
- When `BUN_DEBUG_jest=1` is set, prints: `[jest] Running test: <test
name>`

## Testing

Manually tested with various test files:

**Without BUN_DEBUG_jest:**
```
$ bun bd test /tmp/test-jest-log.test.ts
bun test v1.3.1 (642d04b9)

 3 pass
 0 fail
 3 expect() calls
Ran 3 tests across 1 file. [2.90s]
```

**With BUN_DEBUG_jest=1:**
```
$ BUN_DEBUG_jest=1 bun bd test /tmp/test-jest-log.test.ts
bun test v1.3.1 (642d04b9)
[jest] Running test: first test
[jest] Running test: second test
[jest] Running test: third test

 3 pass
 0 fail
 3 expect() calls
Ran 3 tests across 1 file. [2.77s]
```

Also tested with nested describe blocks and all test names are logged
correctly.

## Notes

- This feature is only available in debug builds (not release builds)
- No tests were added as this is a debug-only feature
- Helps with debugging test execution flow and understanding when tests
start running

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: pfg <pfg@pfg.pw>
2025-10-19 21:32:53 -07:00
robobun
576b21f2ff fix(test): prevent integer overflow in pretty_format writeIndent (#23843)
## Summary

Fixes a panic that occurred when formatting deeply nested objects with
many properties in test output.

## Problem

The `writeIndent()` function in `pretty_format.zig:648` performed
`written * 2` which triggered integer overflow checking in debug builds
when formatting complex nested structures.

**Original crash:**
```
panic: integer overflow
writeIndent at bun.js/test/pretty_format.zig:648
```

**Platform:** Windows x86_64_baseline, Bun v1.3.0

## Solution

Changed from:
```zig
try writer.writeAll(buf[0 .. written * 2]);
```

To:
```zig
const byte_count = @min(buf.len, written *% 2);
try writer.writeAll(buf[0..byte_count]);
```

- Used wrapping multiplication (`*%`) to prevent overflow panic
- Added bounds checking with `@min(buf.len, ...)` for safety
- Maintains correct behavior while preventing crashes

## Test

Added regression test at
`test/js/bun/test/pretty-format-overflow.test.ts` that:
- Creates deeply nested objects (500 levels with 50 properties each)
- Verifies no panic/overflow/crash occurs when formatting
- Uses exact configuration that triggered the original crash

## Verification

-  Test passes with the fix
-  Test would crash without the fix (in debug builds)
-  No changes to behavior, only safety improvement

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-19 21:20:56 -07:00
Jarred Sumner
8eab0fc9fc Update CLAUDE.md 2025-10-19 18:45:54 -07:00
Dylan Conway
de4a5a07b1 fix(bundler): import.meta.url and esm wrapper fixes (#23803)
### What does this PR do?
Fixes printing `import.meta.url` and others with `--bytecode`. Fixes
#14954.

Fixes printing `__toESM` when output module format is CJS and input
module format is ESM.

The key change is that `__toESM`'s `isNodeMode` parameter now depends on
the **input module type** (whether the importing file uses ESM syntax
like `import`/`export`) rather than the output format. This matches
Node.js ESM behavior where importing CommonJS from `.mjs` files always
wraps the entire `module.exports` object as the default export, ignoring
`__esModule` markers.

### How did you verify your code works?

Added comprehensive test suite in `test/bundler/bundler_cjs.test.ts`
with **23 tests** covering:

#### Core Behaviors:
-  Files using `import` syntax always get `isNodeMode=1`, which
**ignores `__esModule`** markers and wraps the entire CJS module as
default
-  This matches Node.js ESM semantics for importing CJS from `.mjs`
files
-  Different CJS export patterns (`exports.x`, `module.exports = ...`,
functions, primitives)
-  Named, default, and namespace (`import *`) imports
-  Different targets (node, browser, bun) - all behave the same
-  Different output formats (esm, cjs) - format doesn't affect the
behavior
-  `.mjs` files re-exporting from `.cjs`
-  Deep re-export chains
-  Edge cases (non-boolean `__esModule`, `__esModule=false`, etc.)

#### Test Results:
- **With this PR's changes**: All 23 tests pass 
- **Without this PR (system bun)**: 22 pass, 1 fails (the one testing
that `__esModule` is ignored with import syntax + CJS format)

The failing test with system bun demonstrates the bug being fixed:
currently, format=cjs with import syntax still respects `__esModule`,
but it should ignore it (matching Node.js behavior).

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
2025-10-18 20:49:57 -07:00
Jarred Sumner
f912355587 Update process.test.js 2025-10-18 20:16:02 -07:00
Jarred Sumner
acefbe2421 Format + bump runtime transpiler cache version 2025-10-18 18:40:31 -07:00
taylor.fish
4a06991d3b Port SocketConfig to bindings generator (#23755)
(For internal tracking: fixes STAB-1471, STAB-1472, STAB-1473,
STAB-1474, STAB-1475, STAB-1476, STAB-1480, STAB-1481)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-18 18:14:01 -07:00
Jarred Sumner
74faec2cc9 Deflake test/js/bun/http/req-url-leak.test.ts 2025-10-18 18:08:08 -07:00
Jarred Sumner
abb82a6905 Deflake test/js/bun/io/bun-write.test.js 2025-10-18 18:05:47 -07:00
Jarred Sumner
47af6e92d9 Deflake test/regression/issue/21311.test.ts 2025-10-18 17:53:47 -07:00
Jarred Sumner
0cb41b1de8 Move process.title test 2025-10-18 17:13:18 -07:00
robobun
b867969e2c Remove unused EventLoopTimer.Arm return type (#23765)
## Summary

The `EventLoopTimer.Arm` result from `EventLoopTimer.fire()` was being
ignored at both call sites. This PR removes the unused return type and
simplifies the code.

## Changes

- Changed `EventLoopTimer.fire()` to return `void` instead of `Arm`
- Updated all 15 timer callback functions to return `void`
- Removed the `Arm` type definition
- Simplified the `drainTimers()` loop that was ignoring the return value
- Updated both call sites in `Timer.zig`

## Details

The `.rearm` functionality was unused - timers that need to reschedule
themselves (like DNS resolver) handle this by calling
`addTimer()`/`update()` directly rather than relying on the return
value.

This change removes:
- The `Arm` union enum type (3 lines)
- All `return .disarm` and `return .{ .rearm = ... }` statements
- The switch statement in `drainTimers()` that did nothing with the
return value

Net result: **-58 lines** of dead code removed.

## Testing

- [x] Bun builds successfully with `bun bd`

🤖 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>
2025-10-18 17:04:47 -07:00
Jarred Sumner
0b89a422bb Fix INSPECT_MAX_BYTES ESM export (#23799)
### 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>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-18 16:54:09 -07:00
mariusz4044
8e34ec311e Fix IP address retrieval in server response (#23813)
### What does this PR do?
Fix, response example - requestIP return object.

<img width="521" height="116" alt="image"
src="https://github.com/user-attachments/assets/14b90a8e-3230-4eb1-8f87-ee06392029cd"
/>

↓
<img width="333" height="115" alt="image"
src="https://github.com/user-attachments/assets/ecf006b3-f02a-4bed-8b8c-b28b8ec2adc8"
/>

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-18 16:53:28 -07:00
robobun
2ebf6c16b6 Fix bounds check in Buffer writeBigInt64/writeBigUInt64 methods (#23781)
## Summary

Fixed an unsigned integer underflow in the bounds check for
`writeBigInt64LE`, `writeBigInt64BE`, `writeBigUInt64LE`, and
`writeBigUInt64BE` methods.

## Problem

When `byteLength < 8`, the bounds check `offset > byteLength - 8` would
cause unsigned integer underflow (since both are `size_t`), resulting in
a large positive number that would pass the check. This allowed
out-of-bounds writes and caused ASAN use-after-poison errors.

**Reproduction:**
```js
const buf = Buffer.from("Hello World");
const slice = buf.slice(0, 5);
slice.writeBigUInt64BE(4096n, 10000); // ASAN error!
```

## Solution

Added an explicit `byteLength < 8` check before the subtraction to
prevent the underflow. The fix is applied to all four functions:
- `writeBigInt64LE` (src/bun.js/bindings/JSBuffer.cpp:2464)
- `writeBigInt64BE` (src/bun.js/bindings/JSBuffer.cpp:2504)
- `writeBigUInt64LE` (src/bun.js/bindings/JSBuffer.cpp:2543)
- `writeBigUInt64BE` (src/bun.js/bindings/JSBuffer.cpp:2582)

## Test plan

- Added comprehensive regression tests covering all edge cases
- Verified the original reproduction case now throws a proper RangeError
instead of crashing
- All tests pass

🤖 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>
2025-10-18 16:52:07 -07:00
robobun
6ee9dac50f Fix URLSearchParams.toJSON() assertion failure with numeric string keys (#23785)
## Summary

Fixes an assertion failure that occurred when `URLSearchParams.toJSON()`
was called with numeric string keys.

## The Problem

When using numeric string keys (e.g., `"39208"`, `"0"`, `"100"`),
calling `toJSON()` would trigger:
```
ASSERTION FAILED: !parseIndex(propertyName)
cache/webkit-6d0f3aac0b817cc0/include/JavaScriptCore/JSObjectInlines.h:444
```

Reproduction:
```javascript
const params = new URLSearchParams();
params.set("39208", "updated");
params.toJSON(); // crashes
```

## Root Cause

The `getInternalProperties` function in `JSURLSearchParams.cpp` was
using `putDirect()` to add properties to the result object. However,
`putDirect()` cannot be used with property names that can be parsed as
array indices - JSC expects such properties to use indexed storage
instead.

## The Fix

- Replace `putDirect()` with `putDirectMayBeIndex()`, which
automatically handles both regular properties and numeric indices
- Replace `getDirect()` with `get()` to properly retrieve values for
both types of properties

## Test Plan

Added comprehensive tests to `test/js/web/html/URLSearchParams.test.ts`:
-  Single numeric string keys
-  Multiple numeric keys
-  Mixed numeric and non-numeric keys  
-  Duplicate numeric keys
-  Extra arguments (original crash case)

All tests pass, and the original crash no longer occurs.

🤖 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>
2025-10-18 16:48:51 -07:00
Jarred Sumner
6a52fd8590 Update bundler_splitting.test.ts 2025-10-18 16:45:54 -07:00
Jarred Sumner
e9e9ca4ffd Enable minify.keepNames in JS builtins 2025-10-18 16:24:16 -07:00
Jarred Sumner
bd15fce066 Enable minify.keepNames in JS builtins 2025-10-18 16:23:11 -07:00
robobun
f702ae5f0f Fix panic when setting process.title with UTF-16 characters (#23783) 2025-10-18 03:14:44 -04:00
Jarred Sumner
0a92d64f0f Deflake test/js/bun/spawn/spawn-pipe-leak.test.ts 2025-10-17 21:38:49 -07:00
Jarred Sumner
d6cfb58bf4 Deflake bundler_splitting.test.ts 2025-10-17 21:32:23 -07:00
Marko Vejnovic
d9a867a4b9 fix(23621): RedisClient Invalid URL (#23714)
### What does this PR do?

Fixes #23621.

Note that the quality of this code is quite low, but since Redis is
getting a rewrite, this is a stop-gap. The tests are what really matters
here.

This whole PR is claude.

### How did you verify your code works?

CI.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-17 14:49:28 -07:00
robobun
1abfc0ea24 fix: panic when overriding Set/Map size property with non-numeric value (#23787)
## Summary

Fixes a panic that occurred when `console.log()` tried to format a Set
or Map instance with a non-numeric `size` property.

## Issue

When a Set or Map subclass overrides the `size` property with a
non-numeric value (like a constructor function, string, or other
object), calling `console.log()` on the instance would trigger a panic:

```javascript
class C1 extends Set {
    constructor() {
        super();
        Object.defineProperty(this, "size", {
            writable: true,
            enumerable: true,
            value: Set
        });
        console.log(this); // panic!
    }
}
new C1();
```

## Root Cause

In `src/bun.js/ConsoleObject.zig`, the Map and Set formatting code
called `toInt32()` directly on the `size` property value. This function
asserts that the value is not a Cell (objects/functions), causing a
panic when `size` was overridden with non-numeric values.

## Solution

Changed both Map and Set formatting to use `coerce(i32, globalThis)`
instead of `toInt32()`. This properly handles non-numeric values using
JavaScript's standard type coercion rules and propagates any coercion
errors appropriately.

## Test Plan

Added regression tests to `test/js/bun/util/inspect.test.js` that verify
Set and Map instances with overridden non-numeric `size` properties can
be inspected without panicking.

🤖 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>
2025-10-17 14:03:26 -07:00
robobun
28f0e5b3b5 Fix Headers.append() assertion with numeric string property names (#23782) 2025-10-17 16:25:54 -04:00
Jarred Sumner
a7816cfb23 Preserve original types in PosixStat 2025-10-16 21:52:22 -04:00
taylor.fish
4142f89148 Fix unnecessary reinterpret_casts from JSGlobalObject to Zig::GlobalObject (#23387)
(For internal tracking: fixes STAB-1384)
2025-10-16 11:32:29 -07:00
Alin Ali Hassan
134341d2b4 Remove duplicate 'linked' option from sourcemap (#23737)
Bun bundler documentation duplicated the "linked" type for sourcemap.

### What does this PR do?

Fix documentation mistake.

### How did you verify your code works?

No code changes have been made.
2025-10-16 12:25:39 -04:00
robobun
642d04b9f2 Add --pass-with-no-tests flag to test runner (#23424)
## Summary

This PR adds support for the `--pass-with-no-tests` CLI flag to the test
runner, addressing issue #20814.

With the latest v1.2.8 release, the test runner now fails when no tests
match a filter. While this is useful for agentic coding workflows, there
are legitimate cases where the previous behavior is preferred, such as
in monorepos where a standard test file pattern is used as a filter but
not all packages contain tests.

This flag makes the test runner behave like Jest and Vitest, exiting
with code 0 when no tests are found.

## Changes

- Added `--pass-with-no-tests` flag to CLI arguments in
`src/cli/Arguments.zig`
- Added `pass_with_no_tests` field to `TestOptions` struct in
`src/cli.zig`
- Updated test runner logic in `src/cli/test_command.zig` to respect the
flag
- Added comprehensive tests in
`test/cli/test/pass-with-no-tests.test.ts`

## Test Plan

All new tests pass:
-  `--pass-with-no-tests` exits with 0 when no test files found
-  `--pass-with-no-tests` exits with 0 when filters match no tests
-  Without flag, still exits with 1 when no tests found (preserves
existing behavior)
-  `--pass-with-no-tests` still fails when actual tests fail

Closes #20814

🤖 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: pfg <pfg@pfg.pw>
2025-10-15 17:38:02 -07:00
Meghan Denny
fadce1001d cpp: address an ErrorCode todo (#23679) 2025-10-15 16:30:18 -07:00
Ciro Spaciari
40b9a92891 fix(fetch) Reduce memory usage (#23697)
### What does this PR do?
reduce memory usage when streaming (this should be a temporary solution
until owned_and_done is fixed)
### How did you verify your code works?
Added a test that should not be flaky in CI

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-15 14:34:59 -07:00
taylor.fish
81c453cb8c Make JSValue.asCell more efficient (#23386)
Avoid calling into C++ in `jsc.JSValue.asCell`.

(For internal tracking: fixes ENG-20820)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-15 14:34:29 -07:00
pfg
1f48dcebed 'vi' was missing from bun test globals (#23674)
```ts
// a.test.ts
console.log(vi);
// $> bun test ./a.test.ts
// before: not defined
// after: defined
```

https://github.com/oven-sh/bun/issues/1825#issuecomment-3094507154
2025-10-15 14:31:27 -07:00
Meghan Denny
26870c905c build: update to C23 (#23680) 2025-10-15 13:25:28 -07:00
Meghan Denny
101e63e881 zig: address a macro todo (#23677) 2025-10-15 11:03:58 -07:00
pfg
324c0d1a39 Eliminates special handling for bun:test in the transpiler (#22888)
Eliminates special handling for bun:test in the transpiler
2025-10-14 20:51:34 -07:00
Meghan Denny
0eb470fd88 zig: handle termination exception from promise fulfullment/rejection (#23285) 2025-10-14 19:48:25 -07:00
Meghan Denny
c3bfff58d9 Revert "Add support for localAddress and localPort in TCP connections" (#23675) 2025-10-14 19:46:47 -07:00
Michael H
37ad295114 bun.shell: Add .quiet(boolean) 2025-10-14 17:43:38 -07:00
github-actions[bot]
b17133a9e9 deps: update hdrhistogram to 0.11.9 (#22276) 2025-10-14 17:03:41 -07:00
github-actions[bot]
acc42467b0 deps: update highway to 1.3.0 (#23519) 2025-10-14 17:02:05 -07:00
Jarred Sumner
bad726f943 fix(watcher): handle vim atomic save race on macOS (#23566)
## Summary

Fixes a race condition on macOS where editing the entrypoint with vim's
atomic save causes "Module not found" errors during hot reload.

## Root Cause

On macOS, kqueue watches file descriptors/inodes, not paths. Vim's
atomic save sequence:
1. Rename `a.js` to `a.js~` → kqueue reports `NOTE_RENAME` on watched fd
2. Hot reloader immediately triggers reload
3. New file hasn't been created yet → `ENOENT` error
4. Vim re-creates `a.js`, and writes file contents into it
5. Directory gets `NOTE_WRITE` but file already removed from watchlist

```
rename("a.js", "a.js~")                 = 0
openat(AT_FDCWD, "a.js", O_WRONLY|O_CREAT, 0664) = 3
ftruncate(3, 0)                         = 0
write(3, "foobar\n", 7)                 = 7
close(3)                                = 0
```

This is macOS-specific because:
- **kqueue**: watches inodes, fd becomes stale when inode deleted
- **inotify (Linux)**: watches paths, gets `IN.MOVED_TO` (not
`IN.MOVE_SELF`), so files stay in watchlist

## Solution

When the entrypoint receives `NOTE_RENAME` on macOS:
1. Set `is_waiting_for_dir_change` flag
2. Skip immediate reload
3. Wait for parent directory `NOTE_WRITE` event
4. Use `faccessat()` to verify file exists
5. Trigger reload

This only applies to the entrypoint because dependencies have buffering
time during import graph traversal.

## Test Plan

Manual testing with vim on macOS:
1. Run `bun --hot entrypoint.js`
2. Edit entrypoint with vim (`:w`)
3. Verify no "Module not found" errors
4. Verify hot reload succeeds

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: taylor.fish <contact@taylor.fish>
2025-10-14 16:33:30 -07:00
robobun
dc36d5601c Improve FFI error messages when symbol is missing ptr field (#23585)
### What does this PR do?

Fixes unhelpful FFI error messages that made debugging extremely
difficult. The user reported that when dlopen fails, the error doesn't
tell you which library failed or why.

**Before:**
```
Failed to open library. This is usually caused by a missing library or an invalid library path.
```

**After:**
```
Failed to open library "libnonexistent.so": /path/libnonexistent.so: cannot open shared object file: No such file or directory
```

### How did you verify your code works?

1. **Cross-platform compilation verified**
- Ran `bun run zig:check-all` - all platforms compile successfully
(Windows, macOS x86_64/arm64, Linux x86_64/arm64 glibc/musl)

2. **Added comprehensive regression tests**
(`test/regression/issue/dlopen-missing-symbol-error.test.ts`)
   -  Tests dlopen error shows library name when it can't be opened
   -  Tests dlopen error shows symbol name when symbol isn't found
   -  Tests linkSymbols shows helpful error when ptr is missing
   -  Tests handle both glibc and musl libc systems

3. **Manually tested error messages**
   - Missing library: Shows full path and "No such file or directory"
   - Invalid library: Shows "invalid ELF header"
   - Missing symbol: Shows symbol and library name
   - linkSymbols without ptr: Shows helpful explanation

### Implementation Details

1. **Created cross-platform getDlError() helper**
(src/bun.js/api/ffi.zig:8-21)
- On POSIX: Calls `std.c.dlerror()` to get actual system error message
- On Windows: Returns generic message (detailed errors handled in C++
layer via `GetLastError()` + `FormatMessageW()`)
- Follows the pattern established in `BunProcess.cpp` for dlopen error
handling

2. **Improved error messages**
   - dlopen errors now include library name and system error details
   - linkSymbols errors explain the ptr field requirement clearly
   - Symbol lookup errors already showed both symbol and library name

3. **Fixed linkSymbols error propagation** (src/js/bun/ffi.ts:529)
   - Added missing `if (Error.isError(result)) throw result;` check
   - Now consistent with dlopen which already had this check

### Example Error Messages

- **Missing library:** `Failed to open library "libnonexistent.so":
cannot open shared object file: No such file or directory`
- **Invalid library:** `Failed to open library "/etc/passwd": invalid
ELF header`
- **Missing symbol:** `Symbol "nonexistent_func" not found in
"libc.so.6"`
- **Missing ptr:** `Symbol "myFunc" is missing a "ptr" field. When using
linkSymbols() or CFunction()...`

Fixes the issue mentioned in:
https://fxtwitter.com/hassanalinali/status/1977710104334963015

🤖 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>
2025-10-14 14:38:17 -07:00
robobun
9086b8f203 Remove copyright header from FormatStackTraceForJS.cpp (#23665) 2025-10-14 10:38:21 -07:00
robobun
6d1ea1c14e Refactor: Move error stack trace code to FormatStackTraceForJS (#23558) 2025-10-14 10:17:47 -07:00
robobun
a7d7eeab24 chore(libuv): upgrade to latest HEAD (f3ce527e) (#23642) 2025-10-14 10:16:17 -07:00
robobun
25d23201b6 Add crash pattern rules for duplicate issue detection (#23658) 2025-10-14 10:14:52 -07:00
Jarred Sumner
bd88717ddc codegen: Add WriteBarrierEarlyInit support for classes with values and valuesArray (#23624)
## Summary

Adds comprehensive support to `generate-classes.ts` for JavaScript
classes that need both named WriteBarrier members (like callbacks) and a
dynamic array of JSValues, all properly tracked by the garbage
collector. This replaces error-prone manual `protect()/unprotect()`
calls with proper GC integration.

## Motivation

The shell interpreter was using `JSValue.protect()/unprotect()` to keep
JavaScript objects alive, which caused memory leaks when cleanup paths
didn't properly unprotect values. This is a common pattern that needed a
better solution.

## What Changed

### Code Generator (`generate-classes.ts`)

When a class has both `values: ["resolve", "reject"]` and `valuesArray:
true`:

**Generated C++ class gets:**
- `WTF::FixedVector<JSC::WriteBarrier<JSC::Unknown>> jsvalueArray`
member for dynamic array
- Individual `JSC::WriteBarrier<JSC::Unknown> m_resolve, m_reject`
members for named values
- 4 `create()` overloads covering all combinations:
  1. Basic: `create(vm, globalObject, structure, ptr)`
  2. Array only: `create(..., FixedVector<WriteBarrier<Unknown>>&&)`
  3. Named values: `create(..., JSValue resolve, JSValue reject)` 
  4. Both: `create(..., FixedVector&&, JSValue resolve, JSValue reject)`

**Constructor overloads using `WriteBarrierEarlyInit`:**
```cpp
JSShellInterpreter(VM& vm, Structure* structure, void* ptr, 
                   JSValue resolve, JSValue reject)
    : Base(vm, structure)
    , m_resolve(resolve, JSC::WriteBarrierEarlyInit)  // ← Key technique
    , m_reject(reject, JSC::WriteBarrierEarlyInit)
{
    m_ctx = ptr;
}
```

The `WriteBarrierEarlyInit` tag allows initializing WriteBarriers in the
constructor initializer list before the object is fully constructed,
which is required for proper GC integration.

**Extern C bridge functions:**
- `TypeName__createWithValues(globalObject, ptr, markedArgumentBuffer*)`
- `TypeName__createWithInitialValues(globalObject, ptr, resolve,
reject)`
- `TypeName__createWithValuesAndInitialValues(globalObject, ptr,
buffer*, resolve, reject)`

**Zig convenience wrappers:**
- `toJSWithValues(this, globalObject, markedArgumentBuffer)`
- `toJSWithInitialValues(this, globalObject, resolve, reject)`
- `toJSWithValuesAndInitialValues(this, globalObject, buffer, resolve,
reject)`

### Shell Interpreter Memory Leak Fix

**Before:**
```zig
const js_value = JSShellInterpreter.toJS(interpreter, globalThis);
resolve.protect();  // Manual reference counting
reject.protect();
// ... later in cleanup ...
resolve.unprotect();  // Easy to forget/miss in error paths
reject.unprotect();
```

**After:**
```zig
const js_value = Bun__createShellInterpreter(
    globalThis, 
    interpreter,
    parsed_shell_script,
    resolve,  // Stored with WriteBarrierEarlyInit
    reject,   // GC tracks automatically
);
// No manual memory management needed!
```

### Supporting Changes

- Added `MarkedArgumentBuffer.wrap()` helper in Zig for safe
MarkedArgumentBuffer usage
- Created `ShellBindings.cpp` with `Bun__createShellInterpreter()` using
the new API
- Removed all `protect()/unprotect()` calls from shell interpreter
- Applied pattern to both `ShellInterpreter` and `ShellArgs` classes

## Benefits

1. **No memory leaks**: GC tracks all references automatically
2. **Safer**: Cannot forget to unprotect values
3. **Cleaner code**: No manual reference counting
4. **Reusable**: Pattern works for any class needing to store JSValues
5. **Performance**: Same cost as manual protect/unprotect but safer

## Testing

Existing shell tests verify the functionality. The pattern is already
used throughout JavaScriptCore for similar cases (see
`JSWrappingFunction`, `AsyncContextFrame`, `JSModuleMock`, etc.)

## When to Use This Pattern

Use `values` + `valuesArray` + `WriteBarrierEarlyInit` when:
- Your C++ class needs to keep JavaScript values alive
- You have both known named callbacks AND dynamic arrays of values
- You want the GC to track references instead of manual
protect/unprotect
- Your class extends `JSDestructibleObject`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-13 19:15:38 -07:00
robobun
0c79e5e0dd Fix race condition in BunFrontendDevServer HMR WebSocket tests (#23625)
## Summary

Fixes flaky tests in `test/cli/inspect/BunFrontendDevServer.test.ts` by
resolving a race condition where tests would miss the `clientConnected`
event.

## Problem

Two tests were failing intermittently (~30% failure rate):
- `should notify on clientNavigated events`
- `should notify on consoleLog events`

Both tests would timeout after 5000ms waiting for the `clientConnected`
event that never arrived.

## Root Cause

In `src/bake/DevServer/HmrSocket.zig:30-41`, when a WebSocket connection
opens, the `onOpen()` handler immediately sends the `clientConnected`
inspector event.

The flaky tests had this problematic sequence:
1. Create WebSocket with `await createHMRClient()`
2. Server's `onOpen()` fires instantly and emits `clientConnected` event
3. Test then calls
`session.waitForEvent("BunFrontendDevServer.clientConnected")`
4. **Race condition**: Event already sent, test waits forever and times
out

## Solution

Set up event listeners **before** creating the WebSocket connection,
matching the pattern from the working test "should receive
clientConnected and clientDisconnected events":

```typescript
// Set up listener FIRST
const connectedEventPromise = session.waitForEvent("BunFrontendDevServer.clientConnected");

// Then create WebSocket
const ws = await createHMRClient();

// Now await the event
const connectedEvent = await connectedEventPromise;
```

## Testing

Verified with 30 consecutive test runs:
- **Before fix**: ~30% failure rate
- **After fix**: 100% pass rate (30/30 passes)

Tested with both:
- Debug build: `bun bd test` 
- System bun v1.3.0: `bun test`

🤖 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>
2025-10-13 16:26:56 -07:00
Jarred Sumner
57ab7f18d1 Update no-validate-leaksan.txt 2025-10-13 15:21:30 -07:00
Jarred Sumner
9c37549e0c Update ParsedShellScript.zig 2025-10-13 14:59:53 -07:00
Jarred Sumner
61cd9602ce Fix ASAN build issue 2025-10-13 14:56:45 -07:00
Junseong Park
8618b32c0c docs: Fix stale init docs (#22208)
Co-authored-by: Michael H <git@riskymh.dev>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Marko Vejnovic <marko@bun.com>
2025-10-13 14:46:56 -07:00
Jarred Sumner
7934e64507 Update pre-bash-zig-build.js 2025-10-13 14:25:37 -07:00
Dylan Conway
72900ec688 fix(install): EXDEV handling with linker: "isolated" (#23587)
### What does this PR do?
Handles EXDEV correctly after first clonefile fails with ENOENT

Fixes #23579
Fixes #23577
### How did you verify your code works?
Manually

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-13 11:19:17 -07:00
Dylan Conway
c820c2b0d3 fix(parser): advance by enum scopes length during visiting (#23581)
### What does this PR do?
Matches esbuild behavior.

Fixes #23578
### How did you verify your code works?
Added a test.
2025-10-13 05:11:54 -07:00
robobun
db7bcd79ff Refactor: move ZigException functions to dedicated file (#23560)
## Summary

This PR moves error-related functions from `bindings.cpp` into a new
dedicated file `ZigException.cpp` for better code organization.

## Changes

Moved the following functions to `ZigException.cpp`:
- `populateStackFrameMetadata`
- `populateStackFramePosition`  
- `populateStackFrame`
- `populateStackTrace`
- `fromErrorInstance`
- `exceptionFromString`
- `JSC__JSValue__toZigException`
- `ZigException__collectSourceLines`
- `JSC__Exception__getStackTrace`

Also moved helper functions and types:
- `V8StackTraceIterator` class
- `getNonObservable`
- `PopulateStackTraceFlags` enum
- `StringView_slice` helper
- `SYNTAX_ERROR_CODE` macro

## Test plan

- Built successfully with `bun bd`
- All exception handling functions are properly exported
- No functional changes, pure refactoring

🤖 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>
2025-10-12 16:29:56 -07:00
robobun
caa4f54b2e refactor: move ReadableStream-related functions from ZigGlobalObject.cpp to ReadableStream.cpp (#23547)
## Summary

This PR moves all ReadableStream-related functions from
`ZigGlobalObject.cpp` to `ReadableStream.cpp` for better code
organization and maintainability.

## Changes

Moved 17 functions from `ZigGlobalObject.cpp` to `ReadableStream.cpp`:

### Core ReadableStream Functions
- `ReadableStream__tee` - with `invokeReadableStreamFunction` helper
(converted to lambda)
- `ReadableStream__cancel`
- `ReadableStream__detach`
- `ReadableStream__isDisturbed`
- `ReadableStream__isLocked`
- `ReadableStreamTag__tagged`

### Stream Creation & Conversion
- `ZigGlobalObject__createNativeReadableStream`
- `ZigGlobalObject__readableStreamToArrayBufferBody`
- `ZigGlobalObject__readableStreamToArrayBuffer`
- `ZigGlobalObject__readableStreamToBytes`
- `ZigGlobalObject__readableStreamToText`
- `ZigGlobalObject__readableStreamToFormData`
- `ZigGlobalObject__readableStreamToJSON`
- `ZigGlobalObject__readableStreamToBlob`

### Host Functions
- `functionReadableStreamToArrayBuffer`
- `functionReadableStreamToBytes`

## Technical Details

### File Changes
- **ReadableStream.cpp**: Added necessary includes and all
ReadableStream functions
- **ReadableStream.h**: Added forward declarations for code generator
functions
- **ZigGlobalObject.cpp**: Removed moved functions (394 lines removed)

### Implementation Notes
- Added proper namespace declarations (`using namespace JSC; using
namespace WebCore;`) to all extern "C" functions
- Used correct namespace qualifiers for types (e.g., `Bun::IDLRawAny`,
`Bun::AbortError`)
- Added required includes: `WebCoreJSBuiltins.h`, `ZigGlobalObject.h`,
`ZigGeneratedClasses.h`, `helpers.h`, `BunClientData.h`,
`BunIDLConvert.h`

## Testing

-  Builds successfully with debug configuration
-  All functions maintain identical behavior
-  No API changes

## Benefits

1. **Better code organization**: ReadableStream functionality is now
consolidated in one place
2. **Improved maintainability**: Easier to find and modify
ReadableStream-related code
3. **Reduced file size**: `ZigGlobalObject.cpp` is now ~400 lines
smaller

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
2025-10-12 14:54:58 -07:00
Jarred Sumner
5196be53e2 Spend less time linking in debug builds 2025-10-12 14:28:42 -07:00
robobun
f00e1816ef Fix crash handler not dumping stack traces on Linux aarch64 (#23549)
### What does this PR do?

Fixes the crash handler failing to capture and display stack traces on
Linux ARM64 systems.

**Before:**
```
============================================================
panic(main thread): cast causes pointer to be null
```
No stack trace shown.

**After:**
```
============================================================
panic(main thread): cast causes pointer to be null
bun.js.api.FFIObject.Reader.u8
/workspace/bun/src/bun.js/api/FFIObject.zig:67:41

bun.js.jsc.host_fn.toJSHostCall__anon_2545765
/workspace/bun/src/bun.js/jsc/host_fn.zig:93:5
```
Full stack trace with source locations.

#### Root Cause
- Zig's `std.debug.captureStackTrace` uses `StackIterator.init()` which
falls back to frame pointer-based unwinding when no context is provided
- Frame pointer-based unwinding doesn't work reliably on ARM64, even
with `-fno-omit-frame-pointer` enabled
- This resulted in 0 frames being captured (`trace.index == 0`)

#### Changes
1. **Use glibc's backtrace() on Linux**: On Linux with glibc (not musl),
always use glibc's `backtrace()` function instead of Zig's
StackIterator. glibc's implementation properly uses DWARF unwinding
information from `.eh_frame` sections.

2. **Skip crash handler frames**: After capturing with `backtrace()`,
find the desired `begin_addr` in the trace (within 128 byte tolerance)
and filter out crash handler internal frames for cleaner output. If
`begin_addr` is not found, use the complete backtrace.

3. **Preserve existing behavior**:
   - Non-debug builds: Use WTF printer (fast, no external deps)
- Debug builds: Fall through to llvm-symbolizer (detailed source info)

### How did you verify your code works?

Reproduced the crash:
```bash
bun-debug --print 'Bun.FFI.read.u8(0)'
```

Verified that:
-  Stack traces now appear on Linux ARM64 with proper source locations
-  Crash handler frames are properly filtered out
-  llvm-symbolizer integration works for debug builds
-  WTF printer is used for release builds
-  When begin_addr is not found, complete backtrace is used

🤖 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>
2025-10-12 14:00:11 -07:00
robobun
356d0e491c fix: use std::call_once for thread-safe JSC initialization (#23542)
## What does this PR do?

Fixes a race condition where multiple threads could attempt to
initialize JavaScriptCore concurrently when the bundler's thread pool
processes files with macros.

Fixes #23540

## How did you verify your code works?

Reproduced the segfault with the Brisa project build and verified the
fix resolves it:

```bash
git clone https://github.com/brisa-build/brisa
cd brisa
bun install
bun run build
```

Before the fix: Segmentation fault with assertion failure
After the fix: Build proceeds without crashing

## Root Cause

The previous implementation used a simple boolean flag `has_loaded_jsc`
without synchronization. When multiple bundler threads tried to execute
macros simultaneously, they could race through the initialization check
before `JSC::initialize()` finished finalizing options on another
thread.

This caused crashes with:
```
ASSERTION FAILED: g_jscConfig.options.allowUnfinalizedAccess || g_jscConfig.options.isFinalized
vendor/WebKit/Source/JavaScriptCore/runtime/Options.h(146) : static OptionsStorage::Bool &JSC::Options::forceTrapAwareStackChecks()
```

## The Fix

Replace the boolean flag with `std::call_once`, which provides:
- Thread-safe initialization
- Guaranteed exactly-once execution
- Proper memory barriers to ensure visibility across threads

The initialization code is now wrapped in a lambda passed to
`std::call_once`, capturing the necessary parameters (`evalMode`,
`envp`, `envc`, `onCrash`).

🤖 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>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-12 13:55:01 -07:00
Jarred Sumner
b8b9d70cdd Emit eh-frame-hdr when not using LTO 2025-10-12 11:53:59 -07:00
robobun
755b41e85b Add BUN_WATCHER_TRACE environment variable for debugging file watcher events (#23533)
## Summary

Adds `BUN_WATCHER_TRACE` environment variable that logs all file watcher
events to a JSON file for debugging. When set, the watcher appends
detailed event information to the specified file path.

## Motivation

Debugging watch-related issues (especially with `bun --watch` and `bun
--hot`) can be difficult without visibility into what the watcher is
actually seeing. This feature provides detailed trace logs showing
exactly which files are being watched and what events are triggered.

## Implementation

- **Isolated module** (`src/watcher/WatcherTrace.zig`) - All trace logic
in separate file
- **No locking needed** - Watcher runs on its own thread, no mutex
required
- **Append-only mode** - Traces persist across multiple runs for easier
debugging
- **Silent errors** - Won't break functionality if trace file can't be
created
- **JSON format** - Easy to parse and analyze

## Usage

```bash
BUN_WATCHER_TRACE=/tmp/watch.log bun --watch script.js
BUN_WATCHER_TRACE=/tmp/hot.log bun --hot server.ts
```

## JSON Output Format

Each line is a JSON object with:
```json
{
  "timestamp": 1760280923269,
  "index": 0,
  "path": "/path/to/watched/file.js",
  "delete": false,
  "write": true,
  "rename": false,
  "metadata": false,
  "move_to": false,
  "changed_files": ["script.js"]
}
```

## Testing

All tests use stdout streaming to wait for actual reloads (no
sleeps/timeouts):
- Tests with `--watch` flag
- Tests with `fs.watch` API  
- Tests that trace file appends across multiple runs
- Tests validation of JSON format and event details

```
 4 pass
 0 fail
📊 52 expect() calls
```

## Files Changed

- `src/Watcher.zig` - Minimal integration with WatcherTrace module
- `src/watcher/WatcherTrace.zig` - New isolated trace implementation
- `src/watcher/KEventWatcher.zig` - Calls writeTraceEvents before
onFileUpdate
- `src/watcher/INotifyWatcher.zig` - Calls writeTraceEvents before
onFileUpdate
- `src/watcher/WindowsWatcher.zig` - Calls writeTraceEvents before
onFileUpdate
- `test/cli/watch/watcher-trace.test.ts` - Comprehensive tests

🤖 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>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-12 11:29:48 -07:00
github-actions[bot]
d29aa58db0 deps: update elysia to 1.4.11 (#23518)
## What does this PR do?

Updates elysia to version 1.4.11

Compare: https://github.com/elysiajs/elysia/compare/1.4.10...1.4.11

Auto-updated by [this
workflow](https://github.com/oven-sh/bun/actions/workflows/update-vendor.yml)

Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2025-10-12 09:45:43 -07:00
robobun
40da082349 fix(shell): handle UV_ENOTCONN gracefully in shell subprocess (#23520) 2025-10-12 05:40:02 -07:00
robobun
5bdc32265d Add support for localAddress and localPort in TCP connections (#23464)
## Summary

This PR implements support for `localAddress` and `localPort` options in
TCP connections, allowing users to bind outgoing connections to a
specific local IP address and port.

This addresses issue #6888 and implements Node.js-compatible behavior
for these options.

## Changes

### C Layer (uSockets)
- **`bsd.c`**: Modified `bsd_create_connect_socket()` to accept a
`local_addr` parameter and call `bind()` before `connect()` when a local
address is specified
- **`context.c`**: Updated `us_socket_context_connect()` and
`start_connections()` to parse and pass local address parameters through
the connection flow
- **`libusockets.h`**: Updated public API signatures to include
`local_host` and `local_port` parameters
- **`internal.h`**: Added `local_host` and `local_port` fields to
`us_connecting_socket_t` structure
- **`openssl.c`**: Updated SSL connection function to match the new
signature

### Zig Layer
- **`SocketContext.zig`**: Updated `connect()` method to accept and pass
through `local_host` and `local_port` parameters
- **`socket.zig`**: Modified `connectAnon()` to handle local address
binding, including IPv6 bracket removal and proper memory management
- **`Handlers.zig`**: Added `localAddress` and `localPort` fields to
`SocketConfig` and implemented parsing from JavaScript options
- **`Listener.zig`**: Updated connection structures to store and pass
local binding information
- **`socket.zig` (bun.js/api/bun)**: Modified `doConnect()` to extract
and pass local address options
- Updated all other call sites (HTTP, MySQL, PostgreSQL, Valkey) to pass
`null, 0` for backward compatibility

### JavaScript Layer
- **`net.ts`**: Enabled `localAddress` and `localPort` support by
passing these options to `doConnect()` and removing TODO comments

### Tests
- **`06888-localaddress.test.ts`**: Added comprehensive tests covering:
  - IPv4 local address binding
  - IPv4 local address and port binding
  - IPv6 local address binding (loopback)
  - Backward compatibility (connections without local address)

## Test Results

All tests pass successfully:
```
✓ TCP socket can bind to localAddress - IPv4
✓ TCP socket can bind to localAddress and localPort - IPv4
✓ TCP socket can bind to localAddress - IPv6 loopback
✓ TCP socket without localAddress works normally

4 pass, 0 fail
```

## API Usage

```typescript
import net from "net";

// Connect with a specific local address
const client = net.createConnection({
  host: "example.com",
  port: 80,
  localAddress: "192.168.1.100",  // Bind to this local IP
  localPort: 0,                    // Let system assign port (optional)
});
```

## Implementation Details

The implementation follows the same flow as Node.js:
1. JavaScript options are parsed in `Handlers.zig` 
2. Local address/port are stored in the connection configuration
3. The Zig layer processes and passes them to the C layer
4. The C layer parses the local address and calls `bind()` before
`connect()`
5. Both IPv4 and IPv6 addresses are supported

Memory management is handled properly throughout the stack, with
appropriate allocation/deallocation at each layer.

Closes #6888

🤖 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>
2025-10-11 20:54:30 -07:00
Dylan Conway
01924e9993 fix(YAML.stringify): check for more indicators at the beginning of strings (#23516)
### What does this PR do?
Makes sure strings are doubled quoted when they start with flow
indicators and `:`.

Fixes #23502
### How did you verify your code works?
Added tests for each indicator in flow and block context
2025-10-11 20:51:22 -07:00
Jarred Sumner
d963a05907 Reduce # of redundant resolver syscalls #2 (#23506)
### What does this PR do?

### How did you verify your code works?

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-11 19:53:05 -07:00
Jarred Sumner
8ccd17fe87 Make sourcemap generation faster (#23514)
### What does this PR do?

### How did you verify your code works?
2025-10-11 19:51:58 -07:00
Shlomo
1c84f87b14 chore: update Claude Code Action to stable version (#23515)
### What does this PR do?

Updates the workflow to use the stable Anthropic Claude action.

### How did you verify your code works?
2025-10-11 19:30:19 -07:00
Jarred Sumner
0e29617d4b Add missing error handling for directory entries errors (#23511)
### What does this PR do?

Add missing error handling for directory entries errors

The code was missing a check for .err

### How did you verify your code works?

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-11 19:21:14 -07:00
Jarred Sumner
f0807e22e2 Update CLAUDE.md 2025-10-11 18:16:43 -07:00
Jarred Sumner
c766c14928 Reduce # of redundant system calls in module resolver (#23505)
### What does this PR do?

### How did you verify your code works?
2025-10-11 14:57:15 -07:00
robobun
525315cf39 fix: include cookies in WebSocket upgrade response (#23499)
Fixes #23474

## Summary

When `request.cookies.set()` is called before `server.upgrade()`, the
cookies are now properly included in the WebSocket upgrade response
headers.

## Problem

Previously, cookies set on the request via `req.cookies.set()` were only
written for regular HTTP responses but were ignored during WebSocket
upgrades. Users had to manually pass cookies via the `headers` option:

```js
server.upgrade(req, {
  headers: {
    "Set-Cookie": `SessionId=${sessionId}`,
  },
});
```

## Solution

Modified `src/bun.js/api/server.zig` to check for and write cookies to
the WebSocket upgrade response after the "101 Switching Protocols"
status is set but before the actual upgrade is performed.

The fix handles both cases:
- When `upgrade()` is called without custom headers
- When `upgrade()` is called with custom headers

## Testing

Added comprehensive regression tests in
`test/regression/issue/23474.test.ts` that:
- Verify cookies are set in the upgrade response without custom headers
- Verify cookies are set in the upgrade response with custom headers
- Use `Promise.withResolvers()` for efficient async handling (no
arbitrary timeouts)

Tests confirmed:
-  Fail with system bun v1.2.23 (without fix)
-  Pass with debug build v1.3.0 (with fix)

## Manual verification

```bash
curl -i -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
  -H "Sec-WebSocket-Version: 13" \
  http://localhost:3000/ws
```

Response now includes:
```
HTTP/1.1 101 Switching Protocols
Set-Cookie: test=123; Path=/; SameSite=Lax
Upgrade: websocket
Connection: Upgrade
...
```

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-11 13:34:06 -07:00
Dylan Conway
85a2ebb717 fix #23470 (#23471)
### What does this PR do?
`CompileResult` error message memory was not managed correctly.

Fixes #23470

### How did you verify your code works?
Manually
2025-10-11 08:23:25 -07:00
Paweł Zatoka
f673ed8821 fix: fix broken scripts in the React templates after the index.ts rename (#23472) 2025-10-10 22:49:45 -07:00
Paweł Zatoka
a67ac081f1 fix: rename index.tsx in React project templates to index.ts (#23469) 2025-10-10 18:35:54 -07:00
Meghan Denny
622d36a553 Bump 2025-10-10 14:13:34 -07:00
Jarred Sumner
b0a6feca57 Update no-validate-leaksan.txt 2025-10-10 04:35:12 -07:00
robobun
012a2bab92 Fix Clang 19 detection in Nix flake by setting CMAKE compiler variables (#23445)
## Summary

Fixes Clang 19 detection in the Nix flake environment by explicitly
setting CMAKE compiler environment variables in the shellHook.

## Problem

When using `nix develop` or `nix print-dev-env`, CMake was unable to
detect the Clang 19 compiler because the `CMAKE_C_COMPILER` and
`CMAKE_CXX_COMPILER` environment variables were not being set, even
though the compiler was available in the environment.

The `shell.nix` file correctly sets these variables (lines 80-87), but
`flake.nix` was missing them.

## Solution

Updated `flake.nix` shellHook to export the same compiler environment
variables as `shell.nix`:
- `CC`, `CXX`, `AR`, `RANLIB` 
- `CMAKE_C_COMPILER`, `CMAKE_CXX_COMPILER`, `CMAKE_AR`, `CMAKE_RANLIB`

This ensures consistent compiler detection across both Nix entry points
(`nix develop` with flakes and `nix-shell` with shell.nix).

## Testing

Verified that all compiler variables are now properly set:
```bash
nix develop --accept-flake-config --impure --command bash -c 'echo "CMAKE_C_COMPILER=$CMAKE_C_COMPILER"'
# Output: CMAKE_C_COMPILER=/nix/store/.../clang-wrapper-19.1.7/bin/clang
```

Also tested with the profile workflow:
```bash
nix develop --accept-flake-config --impure --profile ./dev-profile --command true
eval "$(nix print-dev-env ./dev-profile --accept-flake-config --impure)"
echo "CMAKE_C_COMPILER=$CMAKE_C_COMPILER"
# Output: CMAKE_C_COMPILER=/nix/store/.../clang
```

🤖 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>
2025-10-10 04:11:29 -07:00
robobun
8197a5f7af Fix WriteBarrier initialization to use WriteBarrierEarlyInit (#23435)
## Summary

This PR fixes incorrect WriteBarrier initialization patterns throughout
the Bun codebase where `.set()` or `.setEarlyValue()` was being called
in the constructor body or in `finishCreation()`. According to
JavaScriptCore's `WriteBarrier.h`, WriteBarriers that are initialized
during construction should use the `WriteBarrierEarlyInit` constructor
in the initializer list to avoid triggering unnecessary write barriers.

## Changes

The following classes were updated to properly initialize WriteBarrier
fields:

1. **InternalModuleRegistry** - Initialize internal fields in
constructor using `setWithoutWriteBarrier()` instead of calling `.set()`
in `finishCreation()`
2. **AsyncContextFrame** - Pass callback and context to constructor and
use `WriteBarrierEarlyInit`
3. **JSCommonJSModule** - Pass id, filename, dirname to constructor and
use `WriteBarrierEarlyInit`
4. **JSMockImplementation** - Pass initial values to constructor and use
`WriteBarrierEarlyInit`
5. **JSConnectionsList** - Pass connection sets to constructor and use
`WriteBarrierEarlyInit`
6. **JSBunRequest** - Pass params to constructor and initialize both
`m_params` and `m_cookies` using `WriteBarrierEarlyInit`
7. **JSNodeHTTPServerSocket** - Initialize `currentResponseObject` using
`WriteBarrierEarlyInit` instead of calling `setEarlyValue()`

## Why This Matters

From JavaScriptCore's `WriteBarrier.h`:

```cpp
enum WriteBarrierEarlyInitTag { WriteBarrierEarlyInit };

// Constructor for early initialization during object construction
WriteBarrier(T* value, WriteBarrierEarlyInitTag)
{
    this->setWithoutWriteBarrier(value);
}
```

Using `WriteBarrierEarlyInit` during construction:
- Avoids triggering write barriers when they're not needed
- Is the correct pattern for initializing WriteBarriers before the
object is fully constructed
- Aligns with JavaScriptCore best practices

## Testing

-  Full debug build completes successfully
-  Basic functionality tested (CommonJS modules, HTTP requests, Node
HTTP servers)
-  No regressions observed

## Note on generate-classes.ts

The code generator (`generate-classes.ts`) does not need updates because
generated classes intentionally leave WriteBarrier fields (callbacks,
cached fields, values) uninitialized. They start with
default-constructed WriteBarriers and are populated later by Zig code
via setter functions, which is the correct pattern for those fields.

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-10 03:53:04 -07:00
pfg
c50db1dbfb fix unpaired deref when write_file fails due to nametoolong (#23438)
Fixes test\regression\issue\23316-long-path-spawn.test.ts

The problem was ``await Bun.write(join(deepPath, "test.js"),
`console.log("hello");`);`` was failing because the name was too long,
but it failed before refConcurrently was called and it called
unrefConcurrently after failing. so then when the subprocess spawned it
didn't ref.

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-10 03:48:47 -07:00
Dylan Conway
312a86fd43 fix writing UTF-16 with a trailing unpaired surrogate to process.stdout/stderr (#23444)
### What does this PR do?
Fixes `bun -p "process.stderr.write('Hello' +
String.fromCharCode(0xd800))"`.

Also fixes potential index out of bounds if there are many invalid
sequences.

This also affects `TextEncoder`.
### How did you verify your code works?
Added tests for edgecases

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-10 03:48:04 -07:00
robobun
8826b4f5f5 Fix WTFTimer issues with Atomics.waitAsync (#23442)
## Summary

Fixes two critical issues in `WTFTimer` when `Atomics.waitAsync` creates
multiple timer instances.

## Problems

### 1. Use-After-Free in `WTFTimer.fire()`

**Location:** `/workspace/bun/src/bun.js/api/Timer/WTFTimer.zig:70-82`

```zig
pub fn fire(this: *WTFTimer, _: *const bun.timespec, _: *VirtualMachine) EventLoopTimer.Arm {
    this.event_loop_timer.state = .FIRED;
    this.imminent.store(null, .seq_cst);
    this.runWithoutRemoving();  // ← Callback might destroy `this`
    return if (this.repeat)     // ← UAF: accessing freed memory
        .{ .rearm = this.event_loop_timer.next }
    else
        .disarm;
}
```

When `Atomics.waitAsync` creates a `DispatchTimer` with a timeout, the
timer fires and the callback destroys `this`, but we continue to access
it.

### 2. Imminent Pointer Corruption

**Location:** `/workspace/bun/src/bun.js/api/Timer/WTFTimer.zig:36-42`

```zig
pub fn update(this: *WTFTimer, seconds: f64, repeat: bool) void {
    // Multiple WTFTimers unconditionally overwrite the shared imminent pointer
    this.imminent.store(if (seconds == 0) this else null, .seq_cst);
    // ...
}
```

All `WTFTimer` instances share the same
`vm.eventLoop().imminent_gc_timer` atomic pointer. When multiple timers
are created (GC timer + Atomics.waitAsync timers), they stomp on each
other's imminent state.

## Solutions

### 1. UAF Fix

Read `this.repeat` and `this.event_loop_timer.next` **before** calling
`runWithoutRemoving()`:

```zig
const should_repeat = this.repeat;
const next_time = this.event_loop_timer.next;
this.runWithoutRemoving();
return if (should_repeat)
    .{ .rearm = next_time }
else
    .disarm;
```

### 2. Imminent Pointer Fix

Use compare-and-swap to only set imminent if it's null, and only clear
it if this timer was the one that set it:

```zig
if (seconds == 0) {
    _ = this.imminent.cmpxchgStrong(null, this, .seq_cst, .seq_cst);
    return;
} else {
    _ = this.imminent.cmpxchgStrong(this, null, .seq_cst, .seq_cst);
}
```

## Test Plan

Added regression test at
`test/regression/issue/atomics-waitasync-wtftimer-uaf.test.ts`:

```javascript
const buffer = new SharedArrayBuffer(16);
const view = new Int32Array(buffer);
Atomics.store(view, 0, 0);

const result = Atomics.waitAsync(view, 0, 0, 10);
setTimeout(() => {
  console.log("hi");
}, 100);
```

**Before:** Crashes with UAF under ASAN  
**After:** Runs cleanly

All existing atomics tests pass.

🤖 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>
2025-10-10 03:47:38 -07:00
robobun
f65e280521 Add Nix flake for development environment (#23406)
Provides a Nix flake as an alternative to `scripts/bootstrap.sh` for
setting up the Bun development environment.

## What's included:

- **flake.nix**: Full development environment with all dependencies from
bootstrap.sh
  - LLVM 19, CMake 3.30+, Node.js 24, Rust, Go
  - Build tools: ninja, ccache, pkg-config, make
  - Chromium dependencies for Puppeteer testing
  - gdb for core dump debugging

- **shell.nix**: Simple wrapper for `nix-shell` usage

- **cmake/CompilerFlags.cmake**: Nix compatibility fixes
  - Disable zstd debug compression (Nix's LLVM not built with zstd)
  - Set _FORTIFY_SOURCE=0 for -O0 debug builds
  - Downgrade _FORTIFY_SOURCE warning to not error

## Usage:

```bash
nix-shell
export CMAKE_SYSTEM_PROCESSOR=$(uname -m)
bun bd
```

## Verified working:
 Successfully compiles Bun debug build
 Binary tested: `./build/debug/bun-debug --version` → 1.2.24-debug
 All dependencies from bootstrap.sh included

## Advantages:
- Fully isolated (no sudo required)
- 100% reproducible dependency versions  
- Fast setup with binary caching

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-10 02:13:28 -07:00
Jarred Sumner
a686b9fc39 Update package.json 2025-10-09 23:39:37 -07:00
Zack Radisic
a3cf974752 Update bun-plugin-tailwind (#23396)
### What does this PR do?

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-09 23:39:04 -07:00
Jarred Sumner
de366cfe4b Doc updates 2025-10-09 23:37:10 -07:00
Jarred Sumner
98d1a9d110 Add some missing docs 2025-10-09 23:28:03 -07:00
Ciro Spaciari
3395774c8c improve(node:http): uncork after flushing headers to ensure data is sent immediately (#23413)
### What does this PR do?
Calls `uncork()` after flushing response headers to ensure data is sent
as soon as possible, improving responsiveness.
This behavior still works correctly even without the explicit `uncork()`
call, due to the deferred uncork logic implemented here:

6e3359dd16/packages/bun-uws/src/Loop.h (L57-L64)

A test already covers this scenario in
`test/js/node/test/parallel/test-http-flush-response-headers.js`.


### How did you verify your code works?
CI

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-09 22:56:49 -07:00
robobun
086eb73fe7 deps: update elysia to 1.4.10 (#23422)
## What does this PR do?

Updates the vendored Elysia version from 1.4.6 to 1.4.10.

## Changelog

Compare: https://github.com/elysiajs/elysia/compare/1.4.6...1.4.10

🤖 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>
2025-10-09 19:49:33 -07:00
Ciro Spaciari
979b69b673 fix(CI) (#23418)
### What does this PR do?
fix tests failing because of example.com
### How did you verify your code works?
CI

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-09 19:11:08 -07:00
Jarred Sumner
b3cfaab07f Fix: after pausing stdin, a subprocess should be able to read from stdin (#23341)
Fixes #23333, Fixes #13978

### 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>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pfg <pfg@pfg.pw>
Co-authored-by: Zack Radisic <zack@theradisic.com>
2025-10-09 19:04:41 -07:00
Meghan Denny
8574d62da0 Update LATEST 2025-10-09 18:28:48 -07:00
robobun
6e3359dd16 Bump version to 1.3.0 (#23401)
## What does this PR do?

Bumps Bun version from 1.2.24 to 1.3.0, marking the start of the 1.3.x
release series.

## Changes

- **`package.json`**: Updated version from `1.2.24` to `1.3.0`
- **`LATEST`**: Updated from `1.2.23` to `1.3.0` (used by installation
scripts)
- **`test/bundler/bundler_bun.test.ts`**: Updated version check to
include `1.3.x` so export conditions tests continue to run

## Verification

 Debug build successful showing version `1.3.0-debug`
 All platforms compile successfully via `bun run zig:check-all` (49/49
steps)
 Bundler tests pass with updated version check

## Additional Notes

- CI workflow Bun versions (e.g., `1.2.3`, `1.2.0` in
`.github/workflows/release.yml`) are intentionally left unchanged -
these are pinned versions used to run the release tooling, not the
version being released
- Docker images use `ARG BUN_VERSION` passed at build time and don't
need updates
- The actual release version comes from git tags via `${{
env.BUN_VERSION }}`

---

🤖 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>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-09 06:30:35 -07:00
Dylan Conway
3f0d16d181 fix (node:zlib): use runCallback for calling the error callback (#23397)
### What does this PR do?
Fixes debug panic running `zlib/zlib.test.js`
### How did you verify your code works?
Manually
2025-10-09 04:01:45 -07:00
pfg
46cf50dee5 Fix 23382 (unicode object key printed as 'key" in snapshot instead of "key") (#23390)
Fixes #23382

Breaking change because any existing snapshots that have unicode keys
will need to be regenerated
2025-10-08 21:25:24 -07:00
Dylan Conway
d17134f851 fix build 2025-10-08 18:34:57 -07:00
robobun
f6f7e66a2c Add back --only flag to test runner (#23385)
Fixes #23380 - this is a use-case for the `--only` flag that I missed

Adds back the `--only` flag. When running `bun test` on a full test
suite, without this flag it will run only that test in its file, but it
will run all other tests from other files. With this flag, it will not
run things from other files.

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pfg <pfg@pfg.pw>
2025-10-08 18:26:56 -07:00
robobun
6875cc3f7b test: refactor bundler_promiseall_deadcode to use itBundled helper (#23370)
## Summary

Modernizes `test/bundler/bundler_promiseall_deadcode.test.ts` to use the
`itBundled` test helper instead of manual temp directory creation and
spawning. This makes the test more concise, maintainable, and consistent
with other bundler tests.

## Changes

- Replace `tempDirWithFiles` + manual `Bun.spawn` with `itBundled`
- Use `files` object for test fixtures instead of creating a temp
directory
- Use `onAfterBundle` callback for bundled output assertions
- Use `run.validate` for runtime stderr validation
- Use `run.partialStdout` for stdout verification
- Preserve all original test assertions and behavior

## Test Results

All 3 tests pass with identical functional behavior:

```
 3 pass
 0 fail
 2 snapshots, 23 expect() calls
Ran 3 tests across 1 file. [8.95s]
```

## Verification

All original assertions are preserved:
-  Build success validation
-  Bundled output snapshots (updated paths to match itBundled format)
-  `__esm` and `__promiseAll` presence/absence checks
-  Runtime execution validation (exit code 0)
-  Runtime stderr validation (no async syntax errors)
-  Runtime stdout validation (contains expected output)

The test is now more concise (407 insertions vs 514 deletions) while
maintaining full test coverage.

🤖 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>
2025-10-08 18:25:37 -07:00
Dylan Conway
0601eb0007 Make --linker=isolated the default for bun install (#23311)
### What does this PR do?
Makes isolated installs the default install strategy for projects with
workspaces in Bun v1.3.

Also fixes creating patches with `bun patch` and `--linker isolated`

Fixes #22693

### How did you verify your code works?
Added tests for node_modules renaming `bun patch` with isolated install.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-08 18:00:38 -07:00
Michael H
767e03ef24 load local bunfig.toml for bun run earlier (for run.bun option) (#16664)
Alternative to #15596 where it now only impacts `bun run` for the same
cwd dir. This does not effect `bunx` ([even though according to code it
should load
it](7830e15650/src/cli.zig (L2597-L2628))),
and isnt as fancy as `bun install` where it ensures to check the bunfig
in `package.json` dir.

This shouldn't have any performance issues because its already loading
the file, but now its loading earlier so it can use `run.bun` option.


Fixes #11445, (as well as fixes #15484, fixes #15483, fixes #17064)

---------

Co-authored-by: pfg <pfg@pfg.pw>
2025-10-08 12:13:06 -07:00
robobun
93910f34da Fix bin linking to atomically normalize CRLF in shebang lines (#23360)
## Summary

This PR improves the correctness of bin linking by atomically
normalizing `\r\n` to `\n` in shebang lines when linking bins.

### Changes

- **Refactored shebang normalization in `src/install/bin.zig`**:
  - Extracted logic into separate `tryNormalizeShebang` function
  - Changed from in-place file modification to atomic file replacement
- Reads entire file, creates temporary file with corrected shebang, then
atomically renames
  - Properly cleans up temporary files on errors
  
- **Added test coverage**:
- New test file `test/cli/install/shebang-normalize.test.ts` verifies
CRLF normalization works correctly
- Modified existing test in `bun-link.test.ts` to use Python script with
CRLF shebang

### Why

The previous implementation modified files in-place by seeking to the
`\r` position and overwriting with `\n`. This could potentially corrupt
files if interrupted mid-write. The new atomic approach ensures file
integrity by writing to a temporary file first, then renaming it to
replace the original.

## Test plan

-  `bun bd test test/cli/install/shebang-normalize.test.ts` - passes
-  Verified bins with CRLF shebangs are normalized to LF during linking
-  Code compiles successfully

🤖 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>
2025-10-08 01:51:25 -07:00
Jarred Sumner
8e27087853 Update no-validate-leaksan.txt 2025-10-08 01:50:37 -07:00
Jarred Sumner
3c5565184e 4 less values for the global object to visit (#23368)
### What does this PR do?

### How did you verify your code works?
2025-10-08 01:14:00 -07:00
Meghan Denny
7d10e57422 test: fix claudecode-flag.test.ts (#23367) 2025-10-08 00:54:37 -07:00
Jarred Sumner
562b79c57f Deflake test/js/web/fetch/request-cyclic-reference.test.ts test/js/web/fetch/response-cyclic-reference.test.ts 2025-10-08 00:31:52 -07:00
Ciro Spaciari
625e537f5d fix(NodeHTTP) remove unneeded code add more safety measures agains raw_response after upgrade/close (#23348)
### What does this PR do?
BeforeOpen code is not necessary since we have `setOnSocketUpgraded`
callback now,and we should NOT convert websocket to a response, make
sure that no closed socket is passed to `JSNodeHTTPServerSocket`, change
isIdle to be inside AsyncSocketData to be more reliable (works for
websocket and normal sockets)

### How did you verify your code works?
CI

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-07 22:35:08 -07:00
robobun
d3ff6a5e35 Fix process.stdin not receiving data after pause/resume (#23362)
## Summary

Fixed a race condition where calling `pause()` followed by `resume()` on
`process.stdin` would prevent data from being received, causing the
process to exit immediately instead of listening for input.

## Root Cause

The issue was in the pause/resume event handling logic in
`ProcessObjectInternals.ts`:

1. When `pause()` is called, the "pause" event handler schedules a
`disown()` call for the next tick
2. When `resume()` is called immediately after, it calls `own()` to
acquire a stream reader
3. On the next tick, the scheduled `disown()` from step 1 executes and
incorrectly releases the reader that was just acquired in step 2

This race condition left the stream without a reader, so no data could
be received.

## Solution

Added a `pendingDisown` flag that:
- Gets set to `true` when scheduling a disown operation
- Gets cleared to `false` when `own()` is called (during resume)
- Prevents the scheduled disown from executing if it has been cancelled
by a subsequent `own()` call

## Test Plan

- [x] Added regression tests in
`test/regression/issue/stdin-pause-resume.test.ts`
- [x] Verified fix with original reproduction case
- [x] Existing stdin/tty tests still pass
(`tty-readstream-ref-unref.test.ts`,
`tty-reopen-after-stdin-eof.test.ts`)

## Reproduction

Before this fix, the following code would exit immediately:
```ts
process.stdin.on("data", chunk => {
  process.stdout.write(chunk);
});
process.stdin.pause();
process.stdin.resume();
```

After the fix, it correctly waits for and processes input.

🤖 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>
2025-10-07 22:04:40 -07:00
Dylan Conway
3143c9216c Update security scanner test snapshots (#23361)
### What does this PR do?

### How did you verify your code works?
2025-10-07 20:11:07 -07:00
Jarred Sumner
c0660674fb Fix outdated doc 2025-10-07 20:08:57 -07:00
robobun
5f1ca176cd fix(windows): prevent data loss in pipe reads after libuv 1.51.0 upgrade (#23340)
### What does this PR do?

Fixes data loss when reading large amounts of data from subprocess pipes
on Windows, a regression introduced by the libuv 1.51.0 upgrade in
commit e3783c244f.

### The Problem

When piping large data through a subprocess on Windows (e.g.,
`process.stdin.pipe(process.stdout)`), Bun randomly loses ~73KB of data
out of 1MB, receiving only ~974KB instead of the full 1048576 bytes.

The subprocess correctly receives all 1MB on stdin, but the parent
process loses data when reading from the subprocess stdout.

### Root Cause Analysis

#### libuv 1.51.0 Change

The libuv 1.51.0 upgrade (commit
[libuv/libuv@727ee723](727ee7237e))
changed Windows pipe reading behavior:

**Before:** libuv would call `PeekNamedPipe` to check available bytes,
then read exactly that amount.

**After:** libuv attempts immediate non-blocking reads (up to 65536
bytes) before falling back to async reads. If less data is available
than requested, it returns what's available and signals `more=0`,
causing the read loop to break.

This optimization introduces **0-byte reads** when data isn't
immediately available, which are delivered to Bun's read callback.

#### The Race Condition

When Bun's `WindowsBufferedReader` called `onRead(.drained)` for these
0-byte reads, it created a race condition. Debug logs clearly show the
issue:

**Error case (log.txt):**
```
Line 79-80: onStreamRead = 0 (drained)
Line 81:    filesink closes (stdin closes)
Line 85:    onStreamRead = 6024        ← Should be 74468!
Line 89:    onStreamRead = -4095 (EOF)
```

**Success case (success.log.txt):**
```
Line 79-80: onStreamRead = 0 (drained)
Line 81:    filesink closes (stdin closes)
Line 85:    onStreamRead = 74468       ← Full chunk!
Line 89-90: onStreamRead = 0 (drained)
Line 91:    onStreamRead = 6024
Line 95:    onStreamRead = -4095 (EOF)
```

When stdin closes while a 0-byte drained read is pending, the next read
returns truncated data (6024 bytes instead of 74468 bytes).

### The Fix

Two changes to `WindowsBufferedReader` in `src/io/PipeReader.zig`:

#### 1. Ignore 0-byte reads (line 937-940)

Don't call `onRead(.drained)` for 0-byte reads. Just return and let
libuv queue the next read. This prevents the race condition that causes
truncated reads.

```zig
0 => {
    // With libuv 1.51.0+, calling onRead(.drained) here causes a race condition
    // where subsequent reads return truncated data. Just ignore 0-byte reads.
    return;
},
```

#### 2. Defer `has_inflight_read` flag clearing (line 827-839)

Clear the flag **after** the read callback completes, not before. This
prevents libuv from starting a new overlapped read operation while we're
still processing the current data buffer, which could cause memory
corruption per the libuv commit message:

> "Starting a new read after uv_read_cb returns causes memory corruption
on the OVERLAPPED read_req if uv_read_stop+uv_read_start was called
during the callback"

```zig
const result = onReadChunkFn(this.parent, buf, hasMore);
// Clear has_inflight_read after the callback completes
this.flags.has_inflight_read = false;
return result;
```

### How to Test

Run the modified test in
`test/js/bun/spawn/spawn-stdin-readable-stream.test.ts`:

```js
test("ReadableStream with very large chunked data", async () => {
  const chunkSize = 64 * 1024; // 64KB chunks
  const numChunks = 16; // 1MB total
  const chunk = Buffer.alloc(chunkSize, "x");

  const stream = new ReadableStream({
    pull(controller) {
      if (pushedChunks < numChunks) {
        controller.enqueue(chunk);
        pushedChunks++;
      } else {
        controller.close();
      }
    },
  });

  await using proc = spawn({
    cmd: [bunExe(), "-e", `
      let length = 0;
      process.stdin.on('data', (data) => length += data.length);
      process.once('beforeExit', () => console.error(length));
      process.stdin.pipe(process.stdout)
    `],
    stdin: stream,
    stdout: "pipe",
    env: bunEnv,
  });

  const text = await proc.stdout.text();
  expect(text.length).toBe(chunkSize * numChunks); // Should be 1048576
});
```

**Before fix:** Randomly fails with ~974KB instead of 1MB  
**After fix:** Consistently passes with full 1MB

Run ~100 times to verify the race condition is fixed.

### Related Issues

This may also fix #23071 (Windows scripts hanging), though that issue
needs separate verification.

### Why Draft?

Marking as draft for Windows testing by the team. The fix is based on
detailed debug log analysis showing the exact race condition, but needs
verification on Windows CI.

🤖 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>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-07 18:33:34 -07:00
Alistair Smith
de6ea7375a types: Add (passing) regression test for #5396 2025-10-07 16:32:42 -07:00
robobun
ed0d932a6d test: show received value in snapshot CI error message (#23352)
## Summary

When a snapshot is created in CI without `--update-snapshots`, the error
message now displays the received value that was attempting to be
snapshotted. This helps developers understand what value triggered the
error.

## Changes

- Modified the `SnapshotCreationNotAllowedInCI` error message in
`src/bun.js/test/expect.zig` to include the received value using the
same formatting pattern as other expect error messages

## Before

```
Snapshot creation is not allowed in CI environments unless --update-snapshots is used
If this is not a CI environment, set the environment variable CI=false to force allow.
```

## After

```
Snapshot creation is not allowed in CI environments unless --update-snapshots is used
If this is not a CI environment, set the environment variable CI=false to force allow.

Received: <formatted value>
```

🤖 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>
2025-10-07 16:27:32 -07:00
Alistair Smith
95ebe828fa types: slight simplification of test.each def 2025-10-07 16:24:10 -07:00
Alistair Smith
b289828de2 [@types/bun]: Flatten non-wide types in test.each() (#23354) 2025-10-07 16:13:12 -07:00
robobun
92ec83a92a fix(windows): handle UV_ENOTCONN gracefully when spawning with long cwd (#23344) 2025-10-07 15:32:31 -07:00
pfg
5e8feca98b Enable breaking_changes_1_3 (#23308)
Breaking changes:

- bun:test: disallow creating snapshots or using .only() in ci
- for users: hopefully this should only reveal existing bugs in tests,
not cause failures.
- general: enable calling unhandled rejection handlers for
ErrorBuilder.reject()
- for users: this might reveal some unhandled rejections that were not
visible before.
2025-10-07 12:07:29 -07:00
Ciro Spaciari
bcbba97807 refactor(Response) isolate body usage (#23313) 2025-10-07 08:17:31 -07:00
robobun
6c6849cbf5 fix: prevent crash when workspace includes "./" or ".\" (#23337) 2025-10-07 08:17:13 -07:00
robobun
420d51985b fix(test): prevent AGENTS env var from affecting claudecode-flag test (#23331)
## Summary

- Clone `bunEnv` and delete `AGENTS` property in `beforeAll`
- Replace all `bunEnv` references with `testEnv` in test spawns
- Prevents parent process's `AGENTS` env var from leaking into tests

## Problem

The `claudecode-flag` test was using `bunEnv` directly, which includes
`...process.env`. When running in environments like Claude Code where
`AGENTS` may be set, this variable would leak into the test child
processes and potentially affect test behavior.

## Solution

Created a `testEnv` clone in `beforeAll` that explicitly deletes
`AGENTS`, ensuring consistent test behavior regardless of the parent
process's environment.

## Test plan

- [x] Test passes without `AGENTS` set
- [x] Test passes with `AGENTS=1` set in parent environment

🤖 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>
2025-10-07 03:35:36 -07:00
shadcn
3077081646 feat: upgrade react-shadcn (#23328)
### What does this PR do?

This PR upgrades the `react-shadcn` template:
- Upgrades to the new Tailwind v4 styles and components
- Updates the example components to use the new ones.
- Removed unused form component
- Fixed some a11y issues with the example component.

### How did you verify your code works?

- Ran `bun build` to test if the template builds with no errors.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-07 01:49:19 -07:00
robobun
0b7aed1d0d fix(test): remove quotes from string variables in test.each (#23244)
## Summary
Fixes #23206

When using `test.each` with object syntax and `$variable` interpolation,
string values were being quoted (e.g., `"apple"` instead of `apple`).
This didn't match the behavior of `%s` formatting or Jest's behavior.

## Changes
- Modified `formatLabel` in `src/bun.js/test/jest.zig` to check if the
value is a primitive string and use `toString()` instead of the
formatter with `quote_strings=true`
- Added regression test in `test/regression/issue/23206.test.ts`

## Example

**Before:**
```
test.each([
  { name: "apple" },
  { name: "banana" }
])("fruit #%# is $name", fruit => {
  // Test names were:
  // "fruit #0 is "apple""
  // "fruit #1 is "banana""
});
```

**After:**
```
test.each([
  { name: "apple" },
  { name: "banana" }
])("fruit #%# is $name", fruit => {
  // Test names are now:
  // "fruit #0 is apple"
  // "fruit #1 is banana"
});
```

## Test plan
- [x] Added regression test that verifies both `%s` and `$name` syntax
produce consistent output
- [x] Tested with `AGENT=0` - all tests pass
- [x] Verified other primitive types (numbers, booleans) still format
correctly
- [x] Verified complex objects still use proper formatting

This matches Jest's behavior after their fix:
https://github.com/jestjs/jest/issues/7689

🤖 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: pfg <pfg@pfg.pw>
2025-10-06 20:19:25 -07:00
Jarred Sumner
680e668efd Update CLAUDE.md 2025-10-06 20:03:46 -07:00
robobun
d273f7fdde fix: zstd decompression with async-compressed data (#23314) (#23317)
### What does this PR do?

Fixes #23314 where `zlib.zstdCompress()` created data that caused an
out-of-memory error when decompressed with `Bun.zstdDecompressSync()`.

#### 1. `zlib.zstdCompress()` now sets `pledgedSrcSize`

The async convenience method now automatically sets the `pledgedSrcSize`
option to the input buffer size. This ensures the compressed frame
includes the content size in the header, making sync and async
compression produce identical output.

**Node.js compatibility**: `pledgedSrcSize` is a documented Node.js
option:
-
[`vendor/node/doc/api/zlib.md:754-758`](https://github.com/oven-sh/bun/blob/main/vendor/node/doc/api/zlib.md#L754-L758)
-
[`vendor/node/lib/zlib.js:893`](https://github.com/oven-sh/bun/blob/main/vendor/node/lib/zlib.js#L893)
-
[`vendor/node/src/node_zlib.cc:890-904`](https://github.com/oven-sh/bun/blob/main/vendor/node/src/node_zlib.cc#L890-L904)

#### 2. Added `bun.zstd.decompressAlloc()` - centralized safe
decompression

Created a new function in `src/deps/zstd.zig` that handles decompression
in one place with automatic safety features:

- **Handles unknown content sizes**: Automatically switches to streaming
decompression when the zstd frame doesn't include content size (e.g.,
from streams without `pledgedSrcSize`)
- **16MB safety limit**: For security, if the reported decompressed size
exceeds 16MB, streaming decompression is used instead of blindly
trusting the header
- **Fast path for small files**: Still uses efficient pre-allocation for
files < 16MB with known sizes

This centralized fix automatically protects:
- `Bun.zstdDecompressSync()` / `Bun.zstdDecompress()`
- `StandaloneModuleGraph` source map decompression
- Any other code using `bun.zstd` decompression

### How did you verify your code works?

**Before:**
```typescript
const input = "hello world";

// Async compression
const compressed = await new Promise((resolve, reject) => {
  zlib.zstdCompress(input, (err, result) => {
    if (err) reject(err);
    else resolve(result);
  });
});

// This would fail with "Out of memory"
const decompressed = Bun.zstdDecompressSync(compressed);
```
**Error**: `RangeError: Out of memory` (tried to allocate UINT64_MAX
bytes)

**After:**
```typescript
const input = "hello world";

// Async compression (now includes content size)
const compressed = await new Promise((resolve, reject) => {
  zlib.zstdCompress(input, (err, result) => {
    if (err) reject(err);
    else resolve(result);
  });
});

//  Works! Falls back to streaming decompression if needed
const decompressed = Bun.zstdDecompressSync(compressed);
console.log(decompressed.toString()); // "hello world"
```

**Tests:**
-  All existing tests pass
-  New regression tests for async/sync compression compatibility
(`test/regression/issue/23314/zstd-async-compress.test.ts`)
-  Test for large (>16MB) decompression using streaming
(`test/regression/issue/23314/zstd-large-decompression.test.ts`)
-  Test for various input sizes and types
(`test/regression/issue/23314/zstd-large-input.test.ts`)

**Security:**
The 16MB safety limit protects against malicious zstd frames that claim
huge decompressed sizes in the header, preventing potential OOM attacks.

🤖 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>
2025-10-06 19:56:40 -07:00
robobun
d92d2e5770 Add bunfig.toml support for test randomize, seed, and rerunEach options (#23286)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Alistair Smith <hi@alistair.sh>
2025-10-06 19:48:16 -07:00
robobun
85f89a100e fix(test): lcov reporter now counts only executable lines (#23320)
Fixes #12095

Manually confirmed to fix the case, but it would be better to have an
automated test to compare default reporter output with lcov reporter
output.

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pfg <pfg@pfg.pw>
2025-10-06 19:47:24 -07:00
Dylan Conway
5b51d421da fix(node:path): reverse iterate path.resolve arguments, and stop on absolute (#23293)
### What does this PR do?
Matches node behavior.

Fixes #20975
### How did you verify your code works?
Manually and added a test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-06 19:47:05 -07:00
robobun
5fca74a979 fix(sourcemap): escape tab characters in filenames for JSON (#23298)
## What does this PR do?

Fixes #22003 by escaping tab characters in filenames when generating
sourcemap JSON.

When a filename contained a tab character (e.g., `file\ttab.js`), the
sourcemap JSON would contain a **literal tab byte** instead of the
escaped `\t`, producing invalid JSON that caused `error:
InvalidSourceMap`.

The root cause was in `src/bun.js/bindings/highway_strings.cpp` where
the scalar fallback path had:
```cpp
if (char_ >= 127 || (char_ < 0x20 && char_ != 0x09) || ...)
```

This **exempted tab characters** (0x09) from being detected as needing
escape, while the SIMD path correctly detected them. The fix removes the
`&& char_ != 0x09` exemption so both paths consistently escape tabs.

## How did you verify your code works?

Added regression test in `test/regression/issue/22003.test.ts` that:
- Creates a file with a tab character in its filename
- Builds it with sourcemap generation
- Verifies the sourcemap is valid JSON
- Checks that the tab is escaped as `\t` (not a literal byte)

The test **fails on system bun** (produces invalid JSON with literal
tab):
```bash
USE_SYSTEM_BUN=1 bun test test/regression/issue/22003.test.ts
# error: JSON Parse error: Unterminated string
```

The test **passes with the fix** (tab properly escaped):
```bash
bun bd test test/regression/issue/22003.test.ts
# ✓ 1 pass
```

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-06 19:28:48 -07:00
Dylan Conway
79ac412323 fix(vm): potential crash with codeGeneration.strings = false (#23310)
### What does this PR do?
Sets the `reportViolationForUnsafeEval` global object method table
function pointer. JSC does not check if the pointer is null before
calling.

Fixes #23048
Fixes #22000
### How did you verify your code works?
Manually, and added a test for codeGenerationOptions.
2025-10-06 19:28:05 -07:00
Meghan Denny
13c6a945e4 js: update process.binding("natives") list (#23123) 2025-10-06 17:47:04 -07:00
Marko Vejnovic
90c0c72212 test(valkey): Add a failing subscriber test without IPC (#23253)
### What does this PR do?

Adds a new test which mirrors the _callback errors don't crash the
client_ test but doesn't rely on IPC.

### How did you verify your code works?

Hopefully, CI
2025-10-06 17:03:39 -07:00
robobun
fc9db832dc Fix bindings package compatibility by preventing empty stack trace filenames (#22106) 2025-10-06 16:22:24 -07:00
Alistair Smith
b22e19baed [1.3] Bun.serve({ websocket }) types (#20918)
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>
2025-10-06 16:07:36 -07:00
Alistair Smith
3c232b0fb4 fix: Fix incompatibility with latest @types/node (#23307) 2025-10-06 15:29:25 -07:00
Dylan Conway
166c8ff4f0 fix loaders used by Module._extensions (#23291)
### What does this PR do?
Three things:
- JSCommonJSExtensions.cpp `onAssign` was returning out of sync numbers
instead of `BunLoaderTypeJS`/`BunLoaderTypeNAPI`/...
- `bun.schema.api.Loader._none` was 255 instead of 254 like
`BunLoaderTypeNone`
- `Bun__transpileFile` used `bun.options.Loader.Optional` instead of
`bun.schema.api.Loader`. `bun.options.Loader` does not have a type kept
in sync in C++.
### How did you verify your code works?
Added tests that make sure the correct loader is used for modules
required with custom _extensions functions
2025-10-06 06:40:15 -07:00
robobun
639d998055 fix: handle Darwin accept() bug with socklen=0 in uSockets (#21791)
## Summary

Fixes a macOS kernel (XNU) bug where `accept()` can return a valid
socket descriptor but with `addrlen=0`, indicating an already-dead
socket.

This occurs when an IPv4 connection to an IPv6 dual-stack listener is
immediately aborted (RST packet). The fix detects this condition on
Darwin and handles it intelligently - preserving buffered data when
present, discarding truly dead sockets when not.

## Background

This implements the equivalent of the bugfix from capnproto:
https://github.com/capnproto/capnproto/pull/2365

The issue manifests as:
1. IPv4 connection made to IPv6 dual-stack listener
2. Connection immediately aborted (sends RST packet)  
3. `accept()` returns valid socket descriptor but `addrlen=0`
4. Socket may have buffered data from `connectx()` or be truly dead

## Enhanced Data-Preserving Solution

Unlike simple "close immediately" approaches, this fix **prevents data
loss** from the `connectx()` edge case:

**Race Condition Scenario:**
1. Client uses `connectx()` to send data immediately during connection
2. Network abort (RST) occurs after data is buffered but before full
connection establishment
3. Darwin kernel returns `socklen=0` but socket has buffered data
4. **Our fix preserves this data instead of losing it**

**Logic:**
```c
if (addr->len == 0) {
    /* Check if there's any pending data before discarding the socket */
    char peek_buf[1];
    ssize_t has_data = recv(accepted_fd, peek_buf, 1, MSG_PEEK | MSG_DONTWAIT);
    
    if (has_data <= 0) {
        /* No data available, socket is truly dead - discard it */
        bsd_close_socket(accepted_fd);
        continue; /* Try to accept the next connection */
    }
    /* If has_data > 0, let the socket through - there's buffered data to read */
}
```

## XNU Kernel Source Analysis

After investigating the Darwin XNU kernel source code, I found this bug
affects **multiple system calls**, not just `accept()`. The bug is
rooted in the kernel's socket layer when protocol-specific functions
return NULL socket addresses.

### Affected System Calls

#### 1. accept() and accept_nocancel()  FIXED
**Location:**
[`/bsd/kern/uipc_syscalls.c:596-605`](https://github.com/apple/darwin-xnu/blob/main/bsd/kern/uipc_syscalls.c#L596-L605)

```c
(void) soacceptlock(so, &sa, 0);
socket_unlock(head, 1);
if (sa == NULL) {
    namelen = 0;  // ← BUG: Returns socklen=0
    if (uap->name) {
        goto gotnoname;
    }
    error = 0;
    goto releasefd;
}
```

#### 2. getsockname() ⚠️ ALSO AFFECTED
**Location:**
[`/bsd/kern/uipc_syscalls.c:2601-2603`](https://github.com/apple/darwin-xnu/blob/main/bsd/kern/uipc_syscalls.c#L2601-L2603)

```c
if (sa == 0) {
    len = 0;  // ← SAME BUG: Returns socklen=0
    goto gotnothing;
}
```

#### 3. getpeername() ⚠️ ALSO AFFECTED  
**Location:**
[`/bsd/kern/uipc_syscalls.c:2689-2691`](https://github.com/apple/darwin-xnu/blob/main/bsd/kern/uipc_syscalls.c#L2689-L2691)

```c
if (sa == 0) {
    len = 0;  // ← SAME BUG: Returns socklen=0
    goto gotnothing;
}
```

### System Calls NOT Affected

#### connect() and connectx()  SAFE
**Locations:** 
-
[`/bsd/kern/uipc_syscalls.c:686-744`](https://github.com/apple/darwin-xnu/blob/main/bsd/kern/uipc_syscalls.c#L686-L744)
(connect)
-
[`/bsd/kern/uipc_syscalls.c:747+`](https://github.com/apple/darwin-xnu/blob/main/bsd/kern/uipc_syscalls.c#L747)
(connectx)

**Why they're safe:** These functions read socket addresses from
userspace via `getsockaddr()` and pass them to the protocol layer. They
don't receive socket addresses from the network stack, so they can't
encounter the `socklen=0` condition.

### Root Cause

The bug occurs when protocol layer functions (`pru_accept`,
`pru_sockaddr`, `pru_peeraddr`) return NULL socket addresses during
IPv4→IPv6 dual-stack connection race conditions. The kernel returns
`socklen=0` instead of treating it as an error case.

**Key XNU source reference:**
[`/bsd/kern/uipc_socket.c:1544`](https://github.com/apple/darwin-xnu/blob/main/bsd/kern/uipc_socket.c#L1544)
```c
error = (*so->so_proto->pr_usrreqs->pru_accept)(so, nam);
```

**Socket state vs buffered data:** From
[`/bsd/kern/uipc_socket2.c:2227`](https://github.com/apple/darwin-xnu/blob/main/bsd/kern/uipc_socket2.c#L2227):
```c
// Even with SS_CANTRCVMORE set, data can be buffered in so->so_rcv.sb_cc
return so->so_rcv.sb_cc >= so->so_rcv.sb_lowat ||
       ((so->so_state & SS_CANTRCVMORE) && cfil_sock_data_pending(&so->so_rcv) == 0)
```

## Changes

- Added Darwin-specific check in `bsd_accept_socket()` in
`packages/bun-usockets/src/bsd.c:708-720`
- When `addr->len == 0` after successful `accept()`:
  1. Check for buffered data with `recv(MSG_PEEK | MSG_DONTWAIT)`
  2. If data exists, let socket through normally (prevents data loss)
  3. If no data, close socket and continue accepting
- Only applies to `__APPLE__` builds to avoid affecting other platforms

## Test plan

- [x] Debug build compiles successfully
- [x] Basic HTTP server operations work correctly (exercises accept
path)
- [x] Regression test covers IPv4→IPv6 dual-stack connection abort
scenarios
- [x] Test verifies server doesn't crash/hang when encountering
socklen=0 condition
- [x] Enhanced fix preserves buffered data from connectx() edge cases

The regression test
(`test/regression/issue/darwin-accept-socklen-zero.test.ts`) creates the
exact conditions that trigger this kernel bug:
1. IPv6 dual-stack server (`hostname: "::"`)  
2. IPv4 connections (`127.0.0.1`) with immediate abort (RST packets)
3. Concurrent connection attempts to maximize race condition probability
4. Verification that server remains stable and responsive

## Impact Assessment

### For Bun's uSockets Implementation
- **accept() path:**  FIXED with data loss prevention - This PR handles
the primary case affecting network servers
- **connect() path:**  NOT VULNERABLE - connect() doesn't receive
kernel sockaddrs
- **connectx() path:**  NOT VULNERABLE - connectx() doesn't receive
kernel sockaddrs
- **connectx() data:**  PRESERVED - Enhanced fix prevents losing
buffered data from immediate sends

### Additional Considerations
While `getsockname()` and `getpeername()` have the same kernel bug,
they're less critical for server stability since servers primarily use
`accept()` for incoming connections.

🤖 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>
2025-10-06 06:29:13 -07:00
Jarred Sumner
ec050e6d6e Fix windows memory leak in error case for opening tty & pipe (#23235)
### What does this PR do?

### How did you verify your code works?
2025-10-06 06:16:47 -07:00
Jarred Sumner
08cee69ff4 fix streaming issue (#23289)
### What does this PR do?

### How did you verify your code works?
2025-10-06 05:39:22 -07:00
Dylan Conway
b81018707d fix(parser): unused arrays with no side effects (#23288)
### What does this PR do?
Fixes a bug since Bun v1.0.15: `var f = ([1, 2], "hi");`
Fixes a regression since Bun v1.2.22: `var f = (new Array([1, 2]),
"hi");`

Fixes #23287
### How did you verify your code works?
Added a test
2025-10-06 04:44:05 -07:00
Michael H
f7da0ac6fd bun install: support for minimumReleaseAge (#22801)
### What does this PR do?

fixes #22679

* includes a better error if a package cant be met because of the age
(but would normally)
* logs the resolved one in --verbose (which can be helpful in debugging
to show it does know latest but couldn't use)
* makes bun outdated show in the table when the package isn't true
latest
* includes a rudimentary "stability" check if a later version is in
blacked out time (but only up to 7 days as it goes back to latest with
min age)


For extended security we could also Last-Modified header of the tgz
download and then abort if too new (just like the hash)


| install error with no recent version | bun outdated respecting the
rule |
| --- | --- |
<img width="838" height="119" alt="image"
src="https://github.com/user-attachments/assets/b60916a8-27f6-4405-bfb6-57f9fa8bb0d6"
/> | <img width="609" height="314" alt="image"
src="https://github.com/user-attachments/assets/d8869ff4-8e16-492c-8e4c-9ac1dfa302ba"
/> |

For stable release we will make it use `3d` type syntax instead of magic
second numbers.


### How did you verify your code works?

tests & manual

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2025-10-06 02:58:04 -07:00
Dylan Conway
1c363f0ad0 fix(parser): typeof minification regression (#23280)
### What does this PR do?
In Bun v1.2.22 a minification for `typeof x === "undefined"` → `typeof x
> "u"` was added. This introduced a regression causing `return (typeof x
!== "undefined", false)` to minify to invalid syntax when
`--minify-syntax` is enabled (this is also enabled for transpilation at
runtime).

This pr fixes the regression making sure `return (typeof x !==
"undefined", false);` minifies correctly to `return !1;`.

fixes #21137
### How did you verify your code works?
Added a regression test.
2025-10-06 00:39:08 -07:00
Dylan Conway
d292dcad26 fix(parser): typescript module parsing bug (#23284)
### What does this PR do?
A bug in our typescript parser was causing `module.foo = foo` to parse
as a typescript namespace. If it didn't end with a semicolon and there's
a statement on the next line it would cause a syntax error. Example:

```ts
module.foo = foo
foo.foo = foo
```

fixes #22929 
fixes #22883

### How did you verify your code works?
Added a regression test
2025-10-06 00:37:29 -07:00
Meghan Denny
a9c0ec63e8 node:net: removed explicit ebaf from writing to detached socket (#23278)
supersedes https://github.com/oven-sh/bun/pull/23030
partial revert of
354391a263
likely fixes https://github.com/oven-sh/bun/issues/21982
2025-10-05 20:28:32 -07:00
Dylan Conway
dd08a707e2 update yaml-test-suite test generator script (#23277)
### What does this PR do?
Adds `expect().toBe()` checks for anchors/aliases. Also adds git commit
the tests were translated from.
### How did you verify your code works?
Manually
2025-10-05 18:58:26 -07:00
Meghan Denny
bf26d725ab scripts/runner: pass TEST_SERIAL_ID for proper parallelism handling (#23031)
adds environment variable for proper tmpdir setup
actual fix for
d2a4fb8124
(which was reverted)
this fixes flakyness in node:fs and node:cluster when using
scripts/runner.node.mjs locally with the --parallel flag
2025-10-05 18:22:55 -07:00
Dylan Conway
fcbd57ac48 Bring Bun.YAML to 90% passing yaml-test-suite (#23265)
### What does this PR do?
Fixes bugs in the parser bringing it to 90% passing the official
[yaml-test-suite](https://github.com/yaml/yaml-test-suite) (362/400
passing tests)

Still missing from our parser: |- and |+ (about 5%), and cyclic
references.

Translates the yaml-test-suite to our tests.

fixes #22659
fixes #22392
fixes #22286
### How did you verify your code works?
Added tests for yaml-test-suite and each of the linked issues

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-05 17:23:59 -07:00
robobun
f0295ce0a5 Fix bunfig.toml parsing with UTF-8 BOM (#23276)
Fixes #23275

### What does this PR do?

This PR fixes a bug where `bunfig.toml` files starting with a UTF-8 BOM
(byte order mark, `U+FEFF` or bytes `0xEF 0xBB 0xBF`) would fail to
parse with an "Unexpected" error.

The fix uses Bun's existing `File.toSource()` function with
`convert_bom: true` option when loading config files. This properly
detects and strips the BOM before parsing, matching the behavior of
other file readers in Bun (like the JavaScript lexer which treats
`0xFEFF` as whitespace).

**Changes:**
- Modified `src/cli/Arguments.zig` to use `bun.sys.File.toSource()` with
BOM conversion instead of manually reading the file
- Simplified the config loading code by removing intermediate file
handle and buffer logic

### How did you verify your code works?

Added comprehensive regression tests in
`test/regression/issue/23275.test.ts` that verify:
1.  `bunfig.toml` with UTF-8 BOM parses correctly without errors
2.  `bunfig.toml` without BOM still works (regression test)
3.  `bunfig.toml` with BOM and actual config content parses the content
correctly

All three tests pass with the debug build:
```
 3 pass
 0 fail
 11 expect() calls
Ran 3 tests across 1 file. [6.41s]
```

🤖 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>
2025-10-05 17:22:37 -07:00
Marko Vejnovic
67647c3522 test(valkey): Improvements to valkey IPC interlock (#23252)
### What does this PR do?

Adds a stronger IPC interlock in the failing subscriber test.

### How did you verify your code works?

Hopefully CI.
2025-10-05 05:07:59 -07:00
Jarred Sumner
83060e4b3e Update .gitignore 2025-10-05 04:28:25 -07:00
Jarred Sumner
f0eb0472e6 Allow --splitting and --compile together (#23017)
### What does this PR do?

### How did you verify your code works?
2025-10-04 06:52:20 -07:00
robobun
624911180f fix(outdated): show catalog info without requiring --filter or -r (#23039)
## Summary

The `bun outdated` command now displays catalog dependencies with their
workspace grouping even when run without the `--filter` or `-r` flags.

## What changed

- Added detection for catalog dependencies in the outdated packages list
- The workspace column is now shown when:
  - Using `--filter` or `-r` flags (existing behavior) 
  - OR when there are catalog dependencies to display (new behavior)
- When there are no catalog dependencies and no filtering, the workspace
column remains hidden as before

## Why

Previously, running `bun outdated` without any flags would not show
which workspaces were using catalog dependencies, making it unclear
where catalog entries were being used. This fix ensures catalog
dependencies are properly grouped and displayed with their workspace
information.

## Test

```bash
# Create a workspace project with catalog dependencies
mkdir test-catalog && cd test-catalog
cat > package.json << 'JSON'
{
  "name": "test-catalog",
  "workspaces": ["packages/*"],
  "catalog": {
    "react": "^17.0.0"
  }
}
JSON

mkdir -p packages/{app1,app2}
echo '{"name":"app1","dependencies":{"react":"catalog:"}}' > packages/app1/package.json
echo '{"name":"app2","dependencies":{"react":"catalog:"}}' > packages/app2/package.json

bun install
bun outdated  # Should now show catalog grouping without needing --filter
```

🤖 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: Jarred Sumner <jarred@jarredsumner.com>
2025-10-04 06:51:21 -07:00
Jarred Sumner
db37c36d31 Update post-edit-zig-format.js 2025-10-04 06:07:38 -07:00
robobun
13a3c4de60 fix(install): fetch os/cpu metadata during yarn.lock migration (#23143)
## Summary

During `yarn.lock` migration, OS/CPU package metadata was not being
fetched from the npm registry when missing from `yarn.lock`. This caused
packages with platform-specific requirements to not be properly marked,
potentially leading to incorrect package installation behavior.

## Changes

Updated `fetchNecessaryPackageMetadataAfterYarnOrPnpmMigration` to
conditionally fetch OS/CPU metadata:

- **For yarn.lock migration**: Fetches OS/CPU metadata from npm registry
when not present in yarn.lock (`update_os_cpu = true`)
- **For pnpm-lock.yaml migration**: Skips OS/CPU fetching since
pnpm-lock.yaml already includes this data (`update_os_cpu = false`)

### Files Modified

- `src/install/lockfile.zig` - Added comptime `update_os_cpu` parameter
and conditional logic to fetch OS/CPU metadata
- `src/install/yarn.zig` - Pass `true` to enable OS/CPU fetching for
yarn migrations
- `src/install/pnpm.zig` - Pass `false` to skip OS/CPU fetching for pnpm
migrations (already parsed from lockfile)

## Why This Approach

- `yarn.lock` format often doesn't include OS/CPU constraints, requiring
us to fetch from npm registry
- `pnpm-lock.yaml` already parses OS/CPU during migration (lines 618-621
in pnpm.zig), making additional fetching redundant
- Using a comptime parameter allows the compiler to optimize away the
unused code path

## Testing

-  Debug build compiles successfully
- Tested that the function correctly updates `pkg_meta.os` and
`pkg_meta.arch` only when:
  - `update_os_cpu` is `true` (yarn migration)
  - Current values are `.all` (not already set)
  - Package metadata is available from npm registry

🤖 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>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-04 05:56:21 -07:00
robobun
3c96c8a63d Add Claude Code hooks to prevent common development mistakes (#23241)
## Summary

Added Claude Code hooks to prevent common development mistakes when
working on the Bun codebase.

## Changes

- Created `.claude/hooks/pre-bash-zig-build.js` - A pre-bash hook that
validates commands
- Created `.claude/settings.json` - Hook configuration

## Prevented Mistakes

1. **Running `zig build obj` directly** → Redirects to use `bun bd`
2. **Using `bun test` in development** → Must use `bun bd test` (or set
`USE_SYSTEM_BUN=1`)
3. **Combining snapshot updates with test filters** → Prevents
`-u`/`--update-snapshots` with `-t`/`--test-name-pattern`
4. **Running `bun bd` with timeout** → Build needs time to complete
without timeout
5. **Running `bun bd test` from repo root** → Must specify a test file
path to avoid running all tests

## Test plan

- [x] Tested all validation rules with various command combinations
- [x] Verified USE_SYSTEM_BUN=1 bypass works
- [x] Verified file path detection works correctly

🤖 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>
2025-10-04 05:25:30 -07:00
robobun
46e7a3b3c5 Implement birthtime support on Linux using statx syscall (#23209)
## Summary

- Adds birthtime (file creation time) support on Linux using the `statx`
syscall
- Stores birthtime in architecture-specific unused fields of the kernel
Stat struct (x86_64 and aarch64)
- Falls back to traditional `stat` on kernels < 4.11 that don't support
`statx`
- Includes comprehensive tests validating birthtime behavior

Fixes #6585

## Implementation Details

**src/sys.zig:**
- Added `StatxField` enum for field selection
- Implemented `statxImpl()`, `fstatx()`, `statx()`, and `lstatx()`
functions
- Stores birthtime in unused padding fields (architecture-specific for
x86_64 and aarch64)
- Graceful fallback to traditional stat if statx is not supported

**src/bun.js/node/node_fs.zig:**
- Updated `stat()`, `fstat()`, and `lstat()` to use statx functions on
Linux

**src/bun.js/node/Stat.zig:**
- Added `getBirthtime()` helper to extract birthtime from
architecture-specific storage

**test/js/node/fs/fs-birthtime-linux.test.ts:**
- Tests non-zero birthtime values
- Verifies birthtime immutability across file modifications
- Validates consistency across stat/lstat/fstat
- Tests BigInt stats with nanosecond precision
- Verifies birthtime ordering relative to other timestamps

## Test Plan

- [x] Run `bun bd test test/js/node/fs/fs-birthtime-linux.test.ts` - all
5 tests pass
- [x] Compare behavior with Node.js - identical behavior
- [x] Compare with system Bun - system Bun returns epoch, new
implementation returns real birthtime

🤖 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>
2025-10-04 04:57:29 -07:00
Dylan Conway
6c8635da63 fix(install): isolated installs with transitive self dependencies (#23222)
### What does this PR do?
Packages with self dependencies at a different version were colliding
with the current version in the store node_modules. This pr nests them
in another node_modules

Example:
self-dep@1.0.2 has a dependency on self-dep@1.0.1.

self-dep@1.0.2 is placed here in:
`./node_modules/.bun/self-dep@1.0.2/node_modules/self-dep`

and it's self-dep dependency symlink is now placed in:

`./node_modules/.bun/self-dep@1.0.2/node_modules/self-dep/node_modules/self-dep`

fixes #22681
### How did you verify your code works?
Manually tested the linked issue is working, and added a test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-04 02:59:47 -07:00
Jarred Sumner
2e86f74764 Update no-validate-leaksan.txt 2025-10-04 02:51:45 -07:00
Ciro Spaciari
3c9433f9af fix(sqlite) enable order by and limit in delete/update statements on windows (#23227)
### What does this PR do?

Enable compiler flags
Update SQLite amalgamation using https://www.sqlite.org/download.html
source code
[sqlite-src-3500400.zip](https://www.sqlite.org/2025/sqlite-src-3500400.zip)
with:

```bash
./configure CFLAGS="-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
make sqlite3.c
```

This is the same version that before just with this adicional flag that
must be enabled when generating the amalgamation so we are actually able
to use this option. You can also see that without this the build will
happen but the feature will not be enable
https://buildkite.com/bun/bun/builds/27940, as informed in
https://www.sqlite.org/howtocompile.html topic 5.

### How did you verify your code works?
Add in CI two tests that check if the feature is enabled on windows

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-04 02:48:50 -07:00
Jarred Sumner
4424c5ed08 Update CLAUDE.md 2025-10-04 02:20:59 -07:00
Jarred Sumner
9cab1fbfe0 update CLAUDE.md 2025-10-04 02:17:55 -07:00
SUZUKI Sosuke
578a47ce4a Fix segmentation fault during building stack traces string (#22902)
### What does this PR do?

Bun sometimes crashes with a segmentation fault while generating stack
traces.

the following might be happening in `remapZigException`:

1. The first populateStackTrace (OnlyPosition) sets `frames_len` (e.g.,
frames_len = 5)
613aea1787/src/bun.js/bindings/bindings.cpp (L4793)
```
[frame1, frame2, frame3, frame4, frame5]
```

2. Frame filtering in remapZigException reduces `frames_len` (e.g.,
frames_len = 3)
613aea1787/src/bun.js/VirtualMachine.zig (L2686-L2704)
```
[frame1, frame4, frame5, (frame4, frame5)] 
// frame2 and frame3 are removed by filtering; frames_len is set to 3 here, but frame4 and frame5 remain in their original positions
```

3. The second populateStackTrace (OnlySourceLine) increases `frames_len`
(e.g., frames_len = 5)
613aea1787/src/bun.js/bindings/bindings.cpp (L4793)
```
[frame1, frame4, frame5, frame4, frame5]
```

When deinit is executed on these frames, the ref count is excessively
decremented (for frame4 and frame5), resulting in a UAF.

### How did you verify your code works?

WIP. I'm working on creating minimal reproduction code.

However, I've confirmed that `twenty-server` tests passes with this PR.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-04 01:56:42 -07:00
pfg
9993e12050 Unify timer enum (#23228)
### What does this PR do?

Unify EventLoopTimer.Tag to one enum instead of two

### How did you verify your code works?

Build & CI
2025-10-04 01:50:09 -07:00
robobun
02d0586da5 Increase crash report stack trace buffer from 10 to 20 frames (#23225)
## Summary

Increase the stack trace buffer size in the crash handler from 10 to 20
frames to ensure more useful frames are included in crash reports sent
to bun.report.

## Motivation

Currently, we capture up to 10 stack frames when generating crash
reports. However, many of these frames get filtered out when
`StackLine.fromAddress()` returns `null` for invalid/empty frames. This
results in only a small number of frames (sometimes as few as 5)
actually being sent to the server.

## Changes

- Increased `addr_buf` array size from `[10]usize` to `[20]usize` in
`src/crash_handler.zig:307`

## Impact

By capturing more frames initially, we ensure that after filtering we
still have a meaningful number of frames in the crash report. This will
help with debugging crashes by providing more context about the call
stack.

The encoding function `encodeTraceString()` has no hardcoded limits and
will encode all available frames, so this change directly translates to
more frames being sent to bun.report.

🤖 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>
2025-10-04 00:54:24 -07:00
Dylan Conway
46d6e0885b fix(pnpm migration): fix "lockfileVersion" number parsing (#23232)
### What does this PR do?
Parsing would fail because the lockfile version might be parsing as a
non-whole float instead of a string (`5.4` vs `'5.4'`) and the migration
would have the wrong error.
### How did you verify your code works?
Added a test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-04 00:53:15 -07:00
Dylan Conway
8d28289407 fix(install): make negative workspace patterns work (#23229)
### What does this PR do?
It's common for monorepos to exclude portions of a large glob

```json
"workspaces": [
  "packages/**",
  "!packages/**/test/**",
  "!packages/**/template/**"
],
```

closes #4621 (note: patterns like `"packages/!(*-standalone)"` will need
to be written `"!packages/*-standalone"`)
### How did you verify your code works?
Manually tested https://github.com/opentiny/tiny-engine, and added a new
workspace test.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-04 00:31:47 -07:00
taylor.fish
d8350c2c59 Add jsc.DecodedJSValue; make jsc.Strong more efficient (#23218)
Add `jsc.DecodedJSValue`, an extern struct which is ABI-compatible with
`JSC::JSValue`. (By contrast, `jsc.JSValue` is ABI-compatible with
`JSC::EncodedJSValue`.) This enables `jsc.Strong.get` to be more
efficient: it no longer has to call into C⁠+⁠+.

(For internal tracking: fixes ENG-20748)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-03 22:05:29 -07:00
Ciro Spaciari
e3bd03628a fix(Bun.SQL) fix command detection on sqlite (#23221)
### What does this PR do?
Returning clause should work with insert now
### How did you verify your code works?
Tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-03 17:50:47 -07:00
pfg
f1204ea2fd bun test dots reporter (#22919)
Adds a simple dots reporter for bun test

<img width="911" height="323" alt="image"
src="https://github.com/user-attachments/assets/45cfe7c8-dc8c-47d6-84dc-e1e0232a0633"
/>

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-03 17:13:22 -07:00
robobun
2aa373ab63 Refactor: Split JSNodeHTTPServerSocket into separate files (#23203)
## Summary

Split `JSNodeHTTPServerSocket` and `JSNodeHTTPServerSocketPrototype`
from `NodeHTTP.cpp` into dedicated files, following the same pattern as
`JSDiffieHellman` in the crypto module.

## Changes

- **Created 4 new files:**
  - `JSNodeHTTPServerSocket.h` - Class declaration
  - `JSNodeHTTPServerSocket.cpp` - Class implementation and methods
  - `JSNodeHTTPServerSocketPrototype.h` - Prototype declaration  
- `JSNodeHTTPServerSocketPrototype.cpp` - Prototype methods and property
table

- **Moved from NodeHTTP.cpp:**
  - All custom getters/setters (onclose, ondrain, ondata, etc.)
  - All host functions (close, write, end)
  - Event handlers (onClose, onDrain, onData)
  - Helper functions and templates
  
- **Preserved:**
  - All extern C bindings for Zig interop
  - All existing functionality
  - Proper namespace and include structure

- **Merged changes from main:**
  - Added `upgraded` flag for websocket support (from #23150)
  - Updated `clearSocketData` to handle WebSocketData
  - Added `onSocketUpgraded` callback handler

## Impact

- Reduced `NodeHTTP.cpp` from ~1766 lines to 1010 lines (43% reduction)
- Better code organization and maintainability
- No functional changes

## Test plan

- [x] Build compiles successfully
- [x] `test/js/node/http/node-http.test.ts` passes (72/74 tests pass,
same as before)
- [x] `test/js/node/http/node-http-with-ws.test.ts` passes (websocket
upgrade test)

🤖 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>
2025-10-03 17:13:06 -07:00
taylor.fish
f14f3b03bb Add new bindings generator; port SSLConfig (#23169)
Add a new generator for JS → Zig bindings. The bulk of the conversion is
done in C++, after which the data is transformed into an FFI-safe
representation, passed to Zig, and then finally transformed into
idiomatic Zig types.

In its current form, the new bindings generator supports:

* Signed and unsigned integers
* Floats (plus a “finite” variant that disallows NaN and infinities)
* Strings
* ArrayBuffer (accepts ArrayBuffer, TypedArray, or DataView)
* Blob
* Optional types
* Nullable types (allows null, whereas Optional only allows undefined)
* Arrays
* User-defined string enumerations
* User-defined unions (fields can optionally be named to provide a
better experience in Zig)
* Null and undefined, for use in unions (can more efficiently represent
optional/nullable unions than wrapping a union in an optional)
* User-defined dictionaries (arbitrary key-value pairs; expects a JS
object and parses it into a struct)
* Default values for dictionary members
* Alternative names for dictionary members (e.g., to support both
`serverName` and `servername` without taking up twice the space)
* Descriptive error messages
* Automatic `fromJS` functions in Zig for dictionaries
* Automatic `deinit` functions for the generated Zig types

Although this bindings generator has many features not present in
`bindgen.ts`, it does not yet implement all of `bindgen.ts`'s
functionality, so for the time being, it has been named `bindgenv2`, and
its configuration is specified in `.bindv2.ts` files. Once all
`bindgen.ts`'s functionality has been incorporated, it will be renamed.

This PR ports `SSLConfig` to use the new bindings generator; see
`SSLConfig.bindv2.ts`.

(For internal tracking: fixes STAB-1319, STAB-1322, STAB-1323,
STAB-1324)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Alistair Smith <hi@alistair.sh>
2025-10-03 17:10:28 -07:00
pfg
ddfc3f7fbc Add .cloneUpgrade() to fix clone-upgrade (#23201)
### What does this PR do?

Replaces '.upgrade()' with '.cloneUpgrade()'. '.upgrade()' is confusing
and `.clone().upgrade()` was causing a leak. Caught by
https://github.com/oven-sh/bun/pull/23199#discussion_r2400667320

### How did you verify your code works?
2025-10-03 16:13:06 -07:00
robobun
a9b383bac5 fix(crypto): hkdf callback should pass null (not undefined) on success (#23216)
## Summary
- Fixed crypto.hkdf callback to pass `null` instead of `undefined` for
the error parameter on success
- Added regression test to verify the fix

## Details

Fixes #23211

Node.js convention requires crypto callbacks to receive `null` as the
error parameter on success, but Bun was passing `undefined`. This caused
compatibility issues with code that relies on strict null checks (e.g.,
[matter.js](fdbec2cf88/packages/general/src/crypto/NodeJsStyleCrypto.ts (L169))).

### Changes
- Updated `CryptoHkdf.cpp` to pass `jsNull()` instead of `jsUndefined()`
for the error parameter in the success callback
- Added regression test in `test/regression/issue/23211.test.ts`

## Test plan
- [x] Added regression test that verifies callback receives `null` on
success
- [x] Test passes with the fix
- [x] Ran existing crypto tests (no failures)

🤖 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: Dylan Conway <dylan.conway567@gmail.com>
2025-10-03 15:55:57 -07:00
1412 changed files with 94941 additions and 41892 deletions

View File

@@ -48,6 +48,14 @@ RUN --mount=type=tmpfs,target=/tmp \
wget -O /tmp/cmake.sh "$cmake_url" && \
sh /tmp/cmake.sh --skip-license --prefix=/usr
RUN --mount=type=tmpfs,target=/tmp \
sccache_version="0.12.0" && \
arch=$(uname -m) && \
sccache_url="https://github.com/mozilla/sccache/releases/download/v${sccache_version}/sccache-v${sccache_version}-${arch}-unknown-linux-musl.tar.gz" && \
wget -O /tmp/sccache.tar.gz "$sccache_url" && \
tar -xzf /tmp/sccache.tar.gz -C /tmp && \
install -m755 /tmp/sccache-v${sccache_version}-${arch}-unknown-linux-musl/sccache /usr/local/bin
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 130 \
--slave /usr/bin/g++ g++ /usr/bin/g++-13 \
--slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-13 \
@@ -110,14 +118,14 @@ ARG BUILDKITE_AGENT_TAGS
# Install Rust nightly
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
&& export PATH=$HOME/.cargo/bin:$PATH \
&& rustup install nightly \
&& rustup default nightly
RUN ARCH=$(if [ "$TARGETARCH" = "arm64" ]; then echo "arm64"; else echo "amd64"; fi) && \
echo "Downloading buildkite" && \
echo "Downloading buildkite" && \
curl -fsSL "https://github.com/buildkite/agent/releases/download/v3.87.0/buildkite-agent-linux-${ARCH}-3.87.0.tar.gz" -o /tmp/buildkite-agent.tar.gz && \
mkdir -p /tmp/buildkite-agent && \
tar -xzf /tmp/buildkite-agent.tar.gz -C /tmp/buildkite-agent && \
@@ -147,7 +155,7 @@ COPY . /workspace/bun
# Install Rust nightly
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
&& export PATH=$HOME/.cargo/bin:$PATH \
&& rustup install nightly \
&& rustup default nightly
@@ -161,4 +169,4 @@ RUN --mount=type=tmpfs,target=/workspace/bun/build \
ls -la \
&& bun run build:release \
&& mkdir -p /target \
&& cp -r /workspace/bun/build/release/bun /target/bun
&& cp -r /workspace/bun/build/release/bun /target/bun

View File

@@ -16,6 +16,7 @@ import {
getEmoji,
getEnv,
getLastSuccessfulBuild,
getSecret,
isBuildkite,
isBuildManual,
isFork,
@@ -108,9 +109,9 @@ const buildPlatforms = [
{ os: "linux", arch: "x64", distro: "amazonlinux", release: "2023", features: ["docker"] },
{ os: "linux", arch: "x64", baseline: true, distro: "amazonlinux", release: "2023", features: ["docker"] },
{ os: "linux", arch: "x64", profile: "asan", distro: "amazonlinux", release: "2023", features: ["docker"] },
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.21" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.21" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.21" },
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.22" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.22" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.22" },
{ os: "windows", arch: "x64", release: "2019" },
{ os: "windows", arch: "x64", baseline: true, release: "2019" },
];
@@ -133,9 +134,9 @@ const testPlatforms = [
{ os: "linux", arch: "x64", distro: "ubuntu", release: "24.04", tier: "latest" },
{ os: "linux", arch: "x64", baseline: true, distro: "ubuntu", release: "25.04", tier: "latest" },
{ os: "linux", arch: "x64", baseline: true, distro: "ubuntu", release: "24.04", tier: "latest" },
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.21", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.21", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.21", tier: "latest" },
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.22", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.22", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.22", tier: "latest" },
{ os: "windows", arch: "x64", release: "2019", tier: "oldest" },
{ os: "windows", arch: "x64", release: "2019", baseline: true, tier: "oldest" },
];
@@ -223,7 +224,7 @@ function getImageName(platform, options) {
* @param {number} [limit]
* @link https://buildkite.com/docs/pipelines/command-step#retry-attributes
*/
function getRetry(limit = 0) {
function getRetry() {
return {
manual: {
permit_on_passed: true,
@@ -292,7 +293,7 @@ function getEc2Agent(platform, options, ec2Options) {
* @returns {string}
*/
function getCppAgent(platform, options) {
const { os, arch, distro } = platform;
const { os, arch } = platform;
if (os === "darwin") {
return {
@@ -313,7 +314,7 @@ function getCppAgent(platform, options) {
* @returns {string}
*/
function getLinkBunAgent(platform, options) {
const { os, arch, distro } = platform;
const { os, arch } = platform;
if (os === "darwin") {
return {
@@ -343,7 +344,7 @@ function getZigPlatform() {
arch: "aarch64",
abi: "musl",
distro: "alpine",
release: "3.21",
release: "3.22",
};
}
@@ -352,14 +353,7 @@ function getZigPlatform() {
* @param {PipelineOptions} options
* @returns {Agent}
*/
function getZigAgent(platform, options) {
const { arch } = platform;
// Uncomment to restore to using macOS on-prem for Zig.
// return {
// queue: "build-zig",
// };
function getZigAgent(_platform, options) {
return getEc2Agent(getZigPlatform(), options, {
instanceType: "r8g.large",
});
@@ -461,23 +455,6 @@ function getBuildCommand(target, options, label) {
return `bun run build:${buildProfile}`;
}
/**
* @param {Platform} platform
* @param {PipelineOptions} options
* @returns {Step}
*/
function getBuildVendorStep(platform, options) {
return {
key: `${getTargetKey(platform)}-build-vendor`,
label: `${getTargetLabel(platform)} - build-vendor`,
agents: getCppAgent(platform, options),
retry: getRetry(),
cancel_on_build_failing: isMergeQueue(),
env: getBuildEnv(platform, options),
command: `${getBuildCommand(platform, options)} --target dependencies`,
};
}
/**
* @param {Platform} platform
* @param {PipelineOptions} options
@@ -527,9 +504,9 @@ function getBuildZigStep(platform, options) {
const toolchain = getBuildToolchain(platform);
return {
key: `${getTargetKey(platform)}-build-zig`,
retry: getRetry(),
label: `${getTargetLabel(platform)} - build-zig`,
agents: getZigAgent(platform, options),
retry: getRetry(),
cancel_on_build_failing: isMergeQueue(),
env: getBuildEnv(platform, options),
command: `${getBuildCommand(platform, options)} --target bun-zig --toolchain ${toolchain}`,
@@ -1227,6 +1204,43 @@ async function main() {
console.log("Generated options:", options);
}
startGroup("Querying GitHub for files...");
if (options && isBuildkite && !isMainBranch()) {
/** @type {string[]} */
let allFiles = [];
/** @type {string[]} */
let newFiles = [];
let prFileCount = 0;
try {
console.log("on buildkite: collecting new files from PR");
const per_page = 50;
const { BUILDKITE_PULL_REQUEST } = process.env;
for (let i = 1; i <= 10; i++) {
const res = await fetch(
`https://api.github.com/repos/oven-sh/bun/pulls/${BUILDKITE_PULL_REQUEST}/files?per_page=${per_page}&page=${i}`,
{ headers: { Authorization: `Bearer ${getSecret("GITHUB_TOKEN")}` } },
);
const doc = await res.json();
console.log(`-> page ${i}, found ${doc.length} items`);
if (doc.length === 0) break;
for (const { filename, status } of doc) {
prFileCount += 1;
allFiles.push(filename);
if (status !== "added") continue;
newFiles.push(filename);
}
if (doc.length < per_page) break;
}
console.log(`- PR ${BUILDKITE_PULL_REQUEST}, ${prFileCount} files, ${newFiles.length} new files`);
} catch (e) {
console.error(e);
}
if (allFiles.every(filename => filename.startsWith("docs/"))) {
console.log(`- PR is only docs, skipping tests!`);
return;
}
}
startGroup("Generating pipeline...");
const pipeline = await getPipeline(options);
if (!pipeline) {

View File

@@ -0,0 +1,43 @@
---
allowed-tools: Bash(gh issue view:*), Bash(gh search:*), Bash(gh issue list:*), Bash(gh api:*), Bash(gh issue comment:*)
description: Find duplicate GitHub issues
---
# Issue deduplication command
Find up to 3 likely duplicate issues for a given GitHub issue.
To do this, follow these steps precisely:
1. Use an agent to check if the GitHub issue (a) is closed, (b) does not need to be deduped (eg. because it is broad product feedback without a specific solution, or positive feedback), or (c) already has a duplicate detection comment (check for the exact HTML marker `<!-- dedupe-bot:marker -->` in the issue comments - ignore other bot comments). If so, do not proceed.
2. Use an agent to view a GitHub issue, and ask the agent to return a summary of the issue
3. Then, launch 5 parallel agents to search GitHub for duplicates of this issue, using diverse keywords and search approaches, using the summary from Step 2. **IMPORTANT**: Always scope searches with `repo:owner/repo` to constrain results to the current repository only.
4. Next, feed the results from Steps 2 and 3 into another agent, so that it can filter out false positives, that are likely not actually duplicates of the original issue. If there are no duplicates remaining, do not proceed.
5. Finally, comment back on the issue with a list of up to three duplicate issues (or zero, if there are no likely duplicates)
Notes (be sure to tell this to your agents, too):
- Use `gh` to interact with GitHub, rather than web fetch
- Do not use other tools, beyond `gh` (eg. don't use other MCP servers, file edit, etc.)
- Make a todo list first
- Always scope searches with `repo:owner/repo` to prevent cross-repo false positives
- For your comment, follow the following format precisely (assuming for this example that you found 3 suspected duplicates):
---
Found 3 possible duplicate issues:
1. <link to issue>
2. <link to issue>
3. <link to issue>
This issue will be automatically closed as a duplicate in 3 days.
- If your issue is a duplicate, please close it and 👍 the existing issue instead
- To prevent auto-closure, add a comment or 👎 this comment
🤖 Generated with [Claude Code](https://claude.ai/code)
<!-- dedupe-bot:marker -->
---

View File

@@ -0,0 +1,88 @@
#!/usr/bin/env bun
import { extname } from "path";
import { spawnSync } from "child_process";
const input = await Bun.stdin.json();
const toolName = input.tool_name;
const toolInput = input.tool_input || {};
const filePath = toolInput.file_path;
// Only process Write, Edit, and MultiEdit tools
if (!["Write", "Edit", "MultiEdit"].includes(toolName)) {
process.exit(0);
}
const ext = extname(filePath);
// Only format known files
if (!filePath) {
process.exit(0);
}
function formatZigFile() {
try {
// Format the Zig file
const result = spawnSync("vendor/zig/zig.exe", ["fmt", filePath], {
cwd: process.env.CLAUDE_PROJECT_DIR || process.cwd(),
encoding: "utf-8",
});
if (result.error) {
console.error(`Failed to format ${filePath}: ${result.error.message}`);
process.exit(0);
}
if (result.status !== 0) {
console.error(`zig fmt failed for ${filePath}:`);
if (result.stderr) {
console.error(result.stderr);
}
process.exit(0);
}
} catch (error) {}
}
function formatTypeScriptFile() {
try {
// Format the TypeScript file
const result = spawnSync(
"./node_modules/.bin/prettier",
["--plugin=prettier-plugin-organize-imports", "--config", ".prettierrc", "--write", filePath],
{
cwd: process.env.CLAUDE_PROJECT_DIR || process.cwd(),
encoding: "utf-8",
},
);
} catch (error) {}
}
if (ext === ".zig") {
formatZigFile();
} else if (
[
".cjs",
".css",
".html",
".js",
".json",
".jsonc",
".jsx",
".less",
".mjs",
".pcss",
".postcss",
".sass",
".scss",
".styl",
".stylus",
".toml",
".ts",
".tsx",
".yaml",
].includes(ext)
) {
formatTypeScriptFile();
}
process.exit(0);

View File

@@ -0,0 +1,207 @@
#!/usr/bin/env bun
import { basename, extname } from "path";
const input = await Bun.stdin.json();
const toolName = input.tool_name;
const toolInput = input.tool_input || {};
const command = toolInput.command || "";
const timeout = toolInput.timeout;
const cwd = input.cwd || "";
// Get environment variables from the hook context
// Note: We check process.env directly as env vars are inherited
let useSystemBun = process.env.USE_SYSTEM_BUN;
if (toolName !== "Bash" || !command) {
process.exit(0);
}
function denyWithReason(reason) {
const output = {
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: reason,
},
};
console.log(JSON.stringify(output));
process.exit(0);
}
// Parse the command to extract argv0 and positional args
let tokens;
try {
// Simple shell parsing - split on spaces but respect quotes (both single and double)
tokens = command.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g)?.map(t => t.replace(/^['"]|['"]$/g, "")) || [];
} catch {
process.exit(0);
}
if (tokens.length === 0) {
process.exit(0);
}
// Strip inline environment variable assignments (e.g., FOO=1 bun test)
const inlineEnv = new Map();
let commandStart = 0;
while (
commandStart < tokens.length &&
/^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[commandStart]) &&
!tokens[commandStart].includes("/")
) {
const [name, value = ""] = tokens[commandStart].split("=", 2);
inlineEnv.set(name, value);
commandStart++;
}
if (commandStart >= tokens.length) {
process.exit(0);
}
tokens = tokens.slice(commandStart);
useSystemBun = inlineEnv.get("USE_SYSTEM_BUN") ?? useSystemBun;
// Get the executable name (argv0)
const argv0 = basename(tokens[0], extname(tokens[0]));
// Check if it's zig or zig.exe
if (argv0 === "zig") {
// Filter out flags (starting with -) to get positional arguments
const positionalArgs = tokens.slice(1).filter(arg => !arg.startsWith("-"));
// Check if the positional args contain "build" followed by "obj"
if (positionalArgs.length >= 2 && positionalArgs[0] === "build" && positionalArgs[1] === "obj") {
denyWithReason("error: Use `bun bd` to build Bun and wait patiently");
}
}
// Check if argv0 is timeout and the command is "bun bd"
if (argv0 === "timeout") {
// Find the actual command after timeout and its arguments
const timeoutArgEndIndex = tokens.slice(1).findIndex(t => !t.startsWith("-") && !/^\d/.test(t));
if (timeoutArgEndIndex === -1) {
process.exit(0);
}
const actualCommandIndex = timeoutArgEndIndex + 1;
if (actualCommandIndex >= tokens.length) {
process.exit(0);
}
const actualCommand = basename(tokens[actualCommandIndex]);
const restArgs = tokens.slice(actualCommandIndex + 1);
// Check if it's "bun bd" or "bun-debug bd" without other positional args
if (actualCommand === "bun" || actualCommand.includes("bun-debug")) {
// Claude is a sneaky fucker
let positionalArgs = restArgs.filter(arg => !arg.startsWith("-"));
const redirectStderrToStdoutIndex = positionalArgs.findIndex(arg => arg === "2>&1");
if (redirectStderrToStdoutIndex !== -1) {
positionalArgs.splice(redirectStderrToStdoutIndex, 1);
}
const redirectStdoutToStderrIndex = positionalArgs.findIndex(arg => arg === "1>&2");
if (redirectStdoutToStderrIndex !== -1) {
positionalArgs.splice(redirectStdoutToStderrIndex, 1);
}
const redirectToFileIndex = positionalArgs.findIndex(arg => arg === ">");
if (redirectToFileIndex !== -1) {
positionalArgs.splice(redirectToFileIndex, 2);
}
const redirectToFileAppendIndex = positionalArgs.findIndex(arg => arg === ">>");
if (redirectToFileAppendIndex !== -1) {
positionalArgs.splice(redirectToFileAppendIndex, 2);
}
const redirectTOFileInlineIndex = positionalArgs.findIndex(arg => arg.startsWith(">"));
if (redirectTOFileInlineIndex !== -1) {
positionalArgs.splice(redirectTOFileInlineIndex, 1);
}
const pipeIndex = positionalArgs.findIndex(arg => arg === "|");
if (pipeIndex !== -1) {
positionalArgs = positionalArgs.slice(0, pipeIndex);
}
positionalArgs = positionalArgs.map(arg => arg.trim()).filter(Boolean);
if (positionalArgs.length === 1 && positionalArgs[0] === "bd") {
denyWithReason("error: Run `bun bd` without a timeout");
}
}
}
// Check if command is "bun .* test" or "bun-debug test" with -u/--update-snapshots AND -t/--test-name-pattern
if (argv0 === "bun" || argv0.includes("bun-debug")) {
const allArgs = tokens.slice(1);
// Check if "test" is in positional args or "bd" followed by "test"
const positionalArgs = allArgs.filter(arg => !arg.startsWith("-"));
const hasTest = positionalArgs.includes("test") || (positionalArgs[0] === "bd" && positionalArgs[1] === "test");
if (hasTest) {
const hasUpdateSnapshots = allArgs.some(arg => arg === "-u" || arg === "--update-snapshots");
const hasTestNamePattern = allArgs.some(arg => arg === "-t" || arg === "--test-name-pattern");
if (hasUpdateSnapshots && hasTestNamePattern) {
denyWithReason("error: Cannot use -u/--update-snapshots with -t/--test-name-pattern");
}
}
}
// Check if timeout option is set for "bun bd" command
if (timeout !== undefined && (argv0 === "bun" || argv0.includes("bun-debug"))) {
const positionalArgs = tokens.slice(1).filter(arg => !arg.startsWith("-"));
if (positionalArgs.length === 1 && positionalArgs[0] === "bd") {
denyWithReason("error: Run `bun bd` without a timeout");
}
}
// Check if running "bun test <file>" without USE_SYSTEM_BUN=1
if ((argv0 === "bun" || argv0.includes("bun-debug")) && useSystemBun !== "1") {
const allArgs = tokens.slice(1);
const positionalArgs = allArgs.filter(arg => !arg.startsWith("-"));
// Check if it's "test" (not "bd test")
if (positionalArgs.length >= 1 && positionalArgs[0] === "test" && positionalArgs[0] !== "bd") {
denyWithReason(
"error: In development, use `bun bd test <file>` to test your changes. If you meant to use a release version, set USE_SYSTEM_BUN=1",
);
}
}
// Check if running "bun bd test" from bun repo root or test folder without a file path
if (argv0 === "bun" || argv0.includes("bun-debug")) {
const allArgs = tokens.slice(1);
const positionalArgs = allArgs.filter(arg => !arg.startsWith("-"));
// Check if it's "bd test"
if (positionalArgs.length >= 2 && positionalArgs[0] === "bd" && positionalArgs[1] === "test") {
// Check if cwd is the bun repo root or test folder
const isBunRepoRoot = cwd === "/workspace/bun" || cwd.endsWith("/bun");
const isTestFolder = cwd.endsWith("/bun/test");
if (isBunRepoRoot || isTestFolder) {
// Check if there's a file path argument (looks like a path: contains / or has test extension)
const hasFilePath = positionalArgs
.slice(2)
.some(
arg =>
arg.includes("/") ||
arg.endsWith(".test.ts") ||
arg.endsWith(".test.js") ||
arg.endsWith(".test.tsx") ||
arg.endsWith(".test.jsx"),
);
if (!hasFilePath) {
denyWithReason(
"error: `bun bd test` from repo root or test folder will run all tests. Use `bun bd test <path>` with a specific test file.",
);
}
}
}
}
// Allow the command to proceed
process.exit(0);

26
.claude/settings.json Normal file
View File

@@ -0,0 +1,26 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/pre-bash-zig-build.js"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/post-edit-zig-format.js"
}
]
}
]
}
}

143
.coderabbit.yaml Normal file
View File

@@ -0,0 +1,143 @@
language: en-US
reviews:
profile: assertive
request_changes_workflow: false
high_level_summary: false
high_level_summary_placeholder: "@coderabbitai summary"
high_level_summary_in_walkthrough: true
auto_title_placeholder: "@coderabbitai"
review_status: false
commit_status: false
fail_commit_status: false
collapse_walkthrough: false
changed_files_summary: true
sequence_diagrams: false
estimate_code_review_effort: false
assess_linked_issues: true
related_issues: true
related_prs: true
suggested_labels: false
suggested_reviewers: true
in_progress_fortune: false
poem: false
abort_on_close: true
path_filters:
- "!test/js/node/test/"
auto_review:
enabled: true
auto_incremental_review: true
drafts: false
finishing_touches:
docstrings:
enabled: false
unit_tests:
enabled: false
pre_merge_checks:
docstrings:
mode: off
title:
mode: warning
description:
mode: warning
issue_assessment:
mode: warning
tools:
shellcheck:
enabled: true
ruff:
enabled: true
markdownlint:
enabled: true
github-checks:
enabled: true
timeout_ms: 90000
languagetool:
enabled: true
enabled_only: false
level: default
biome:
enabled: true
hadolint:
enabled: true
swiftlint:
enabled: true
phpstan:
enabled: true
level: default
phpmd:
enabled: true
phpcs:
enabled: true
golangci-lint:
enabled: true
yamllint:
enabled: true
gitleaks:
enabled: true
checkov:
enabled: true
detekt:
enabled: true
eslint:
enabled: true
flake8:
enabled: true
rubocop:
enabled: true
buf:
enabled: true
regal:
enabled: true
actionlint:
enabled: true
pmd:
enabled: true
clang:
enabled: true
cppcheck:
enabled: true
semgrep:
enabled: true
circleci:
enabled: true
clippy:
enabled: true
sqlfluff:
enabled: true
prismaLint:
enabled: true
pylint:
enabled: true
oxc:
enabled: true
shopifyThemeCheck:
enabled: true
luacheck:
enabled: true
brakeman:
enabled: true
dotenvLint:
enabled: true
htmlhint:
enabled: true
checkmake:
enabled: true
osvScanner:
enabled: true
chat:
auto_reply: true
knowledge_base:
opt_out: false
code_guidelines:
enabled: true
filePatterns:
- "**/.cursor/rules/*.mdc"
- "**/CLAUDE.md"

View File

@@ -30,7 +30,7 @@ bun bd <file> <...args>
Debug logs look like this:
```zig
const log = bun.Output.scoped(.${SCOPE}, false);
const log = bun.Output.scoped(.${SCOPE}, .hidden);
// ...later
log("MY DEBUG LOG", .{})

1
.gitattributes vendored
View File

@@ -16,6 +16,7 @@
*.map text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.md text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.mdc text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.mdx text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.mjs text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.mts text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2

View File

@@ -0,0 +1,29 @@
name: Auto-close duplicate issues
on:
schedule:
- cron: "0 9 * * *"
workflow_dispatch:
jobs:
auto-close-duplicates:
runs-on: ubuntu-latest
timeout-minutes: 10
concurrency:
group: auto-close-duplicates-${{ github.repository }}
cancel-in-progress: true
permissions:
contents: read
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Auto-close duplicate issues
run: bun run scripts/auto-close-duplicates.ts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}

View File

@@ -0,0 +1,34 @@
name: Claude Issue Dedupe
on:
issues:
types: [opened]
workflow_dispatch:
inputs:
issue_number:
description: 'Issue number to process for duplicate detection'
required: true
type: string
jobs:
claude-dedupe-issues:
runs-on: ubuntu-latest
timeout-minutes: 10
concurrency:
group: claude-dedupe-issues-${{ github.event.issue.number || inputs.issue_number }}
cancel-in-progress: true
permissions:
contents: read
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Run Claude Code slash command
uses: anthropics/claude-code-base-action@beta
with:
prompt: "/dedupe ${{ github.repository }}/issues/${{ github.event.issue.number || inputs.issue_number }}"
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_args: "--model claude-sonnet-4-5-20250929"
claude_env: |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -57,8 +57,7 @@ jobs:
git reset --hard origin/${{ github.event.pull_request.head.ref }}
- name: Run Claude Code
id: claude
# TODO: switch this out once they merge their v1
uses: km-anthropic/claude-code-action@v1-dev
uses: anthropics/claude-code-action@v1
with:
timeout_minutes: "180"
claude_args: |

View File

@@ -1,24 +0,0 @@
name: Docs
on:
push:
paths:
- "docs/**"
- "packages/bun-types/**.d.ts"
- "CONTRIBUTING.md"
- "src/cli/install.sh"
- "src/cli/install.ps1"
branches:
- main
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'oven-sh' }}
steps:
# redeploy Vercel site when a file in `docs` changes
# using VERCEL_DEPLOY_HOOK environment variable
- name: Trigger Webhook
run: |
curl -v ${{ secrets.VERCEL_DEPLOY_HOOK }}

View File

@@ -142,8 +142,8 @@ jobs:
uses: actions/github-script@v7
with:
script: |
const closeAction = JSON.parse('${{ steps.add-labels.outputs.close-action }}');
const closeAction = ${{ fromJson(steps.add-labels.outputs.close-action) }};
// Comment with the reason
await github.rest.issues.createComment({
owner: context.repo.owner,
@@ -151,7 +151,7 @@ jobs:
issue_number: context.issue.number,
body: closeAction.comment
});
// Close the issue
await github.rest.issues.update({
owner: context.repo.owner,

View File

@@ -1,19 +0,0 @@
name: Typos
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Spellcheck
uses: crate-ci/typos@v1.29.4
with:
files: docs/**/*

View File

@@ -70,24 +70,7 @@ jobs:
- name: Update SQLite if needed
if: success() && steps.check-version.outputs.current_num < steps.check-version.outputs.latest_num
run: |
set -euo pipefail
TEMP_DIR=$(mktemp -d)
cd $TEMP_DIR
echo "Downloading from: https://sqlite.org/${{ steps.check-version.outputs.latest_year }}/sqlite-amalgamation-${{ steps.check-version.outputs.latest_num }}.zip"
# Download and extract latest version
wget "https://sqlite.org/${{ steps.check-version.outputs.latest_year }}/sqlite-amalgamation-${{ steps.check-version.outputs.latest_num }}.zip"
unzip "sqlite-amalgamation-${{ steps.check-version.outputs.latest_num }}.zip"
cd "sqlite-amalgamation-${{ steps.check-version.outputs.latest_num }}"
# Add header comment and copy files
echo "// clang-format off" > $GITHUB_WORKSPACE/src/bun.js/bindings/sqlite/sqlite3.c
cat sqlite3.c >> $GITHUB_WORKSPACE/src/bun.js/bindings/sqlite/sqlite3.c
echo "// clang-format off" > $GITHUB_WORKSPACE/src/bun.js/bindings/sqlite/sqlite3_local.h
cat sqlite3.h >> $GITHUB_WORKSPACE/src/bun.js/bindings/sqlite/sqlite3_local.h
./scripts/update-sqlite-amalgamation.sh ${{ steps.check-version.outputs.latest_num }} ${{ steps.check-version.outputs.latest_year }}
- name: Create Pull Request
if: success() && steps.check-version.outputs.current_num < steps.check-version.outputs.latest_num

4
.gitignore vendored
View File

@@ -1,7 +1,9 @@
.claude/settings.local.json
.DS_Store
.env
.envrc
.eslintcache
.gdb_history
.idea
.next
.ninja_deps
@@ -189,4 +191,4 @@ scratch*.{js,ts,tsx,cjs,mjs}
scripts/lldb-inline
# We regenerate these in all the build scripts
cmake/sources/*.txt
cmake/sources/*.txt

View File

@@ -7,4 +7,5 @@ src/react-refresh.js
*.min.js
test/snippets
test/js/node/test
test/napi/node-napi-tests
bun.lock

View File

@@ -19,6 +19,12 @@
"options": {
"printWidth": 80
}
},
{
"files": ["src/codegen/bindgenv2/**/*.ts", "*.bindv2.ts"],
"options": {
"printWidth": 100
}
}
]
}

112
CLAUDE.md
View File

@@ -23,28 +23,51 @@ Tip: Bun is already installed and in $PATH. The `bd` subcommand is a package.jso
### Test Organization
If a test is for a specific numbered GitHub Issue, it should be placed in `test/regression/issue/${issueNumber}.test.ts`. Ensure the issue number is **REAL** and not a placeholder!
If no valid issue number is provided, find the best existing file to modify instead, such as;
- `test/js/bun/` - Bun-specific API tests (http, crypto, ffi, shell, etc.)
- `test/js/node/` - Node.js compatibility tests
- `test/js/web/` - Web API tests (fetch, WebSocket, streams, etc.)
- `test/cli/` - CLI command tests (install, run, test, etc.)
- `test/regression/issue/` - Regression tests (create one per bug fix)
- `test/bundler/` - Bundler and transpiler tests
- `test/bundler/` - Bundler and transpiler tests. Use `itBundled` helper.
- `test/integration/` - End-to-end integration tests
- `test/napi/` - N-API compatibility tests
- `test/v8/` - V8 C++ API compatibility tests
### Writing Tests
Tests use Bun's Jest-compatible test runner with proper test fixtures:
Tests use Bun's Jest-compatible test runner with proper test fixtures.
- For **single-file tests**, prefer `-e` over `tempDir`.
- For **multi-file tests**, prefer `tempDir` and `Bun.spawn`.
```typescript
import { test, expect } from "bun:test";
import { bunEnv, bunExe, normalizeBunSnapshot, tempDir } from "harness";
test("my feature", async () => {
test("(single-file test) my feature", async () => {
await using proc = Bun.spawn({
cmd: [bunExe(), "-e", "console.log('Hello, world!')"],
env: bunEnv,
});
const [stdout, stderr, exitCode] = await Promise.all([
proc.stdout.text(),
proc.stderr.text(),
proc.exited,
]);
expect(normalizeBunSnapshot(stdout)).toMatchInlineSnapshot(`"Hello, world!"`);
expect(exitCode).toBe(0);
});
test("(multi-file test) my feature", async () => {
// Create temp directory with test files
using dir = tempDir("test-prefix", {
"index.js": `console.log("hello");`,
"index.js": `import { foo } from "./foo.ts"; foo();`,
"foo.ts": `export function foo() { console.log("foo"); }`,
});
// Spawn Bun process
@@ -61,15 +84,21 @@ test("my feature", async () => {
proc.exited,
]);
expect(exitCode).toBe(0);
// Prefer snapshot tests over expect(stdout).toBe("hello\n");
expect(normalizeBunSnapshot(stdout, dir)).toMatchInlineSnapshot(`"hello"`);
// Assert the exit code last. This gives you a more useful error message on test failure.
expect(exitCode).toBe(0);
});
```
- Always use `port: 0`. Do not hardcode ports. Do not use your own random port number function.
- Use `normalizeBunSnapshot` to normalize snapshot output of the test.
- NEVER write tests that check for no "panic" or "uncaught exception" or similar in the test output. That is NOT a valid test.
- Use `tempDir` from `"harness"` to create a temporary directory. **Do not** use `tmpdirSync` or `fs.mkdtempSync` to create temporary directories.
- When spawning processes, tests should expect(stdout).toBe(...) BEFORE expect(exitCode).toBe(0). This gives you a more useful error message on test failure.
- **CRITICAL**: Do not write flaky tests. Do not use `setTimeout` in tests. Instead, `await` the condition to be met. You are not testing the TIME PASSING, you are testing the CONDITION.
- **CRITICAL**: Verify your test fails with `USE_SYSTEM_BUN=1 bun test <file>` and passes with `bun bd test <file>`. Your test is NOT VALID if it passes with `USE_SYSTEM_BUN=1`.
## Code Architecture
@@ -78,7 +107,7 @@ test("my feature", async () => {
- **Zig code** (`src/*.zig`): Core runtime, JavaScript bindings, package manager
- **C++ code** (`src/bun.js/bindings/*.cpp`): JavaScriptCore bindings, Web APIs
- **TypeScript** (`src/js/`): Built-in JavaScript modules with special syntax (see JavaScript Modules section)
- **Generated code**: Many files are auto-generated from `.classes.ts` and other sources
- **Generated code**: Many files are auto-generated from `.classes.ts` and other sources. Bun will automatically rebuild these files when you make changes to them.
### Core Source Organization
@@ -143,19 +172,6 @@ When implementing JavaScript classes in C++:
3. Add iso subspaces for classes with C++ fields
4. Cache structures in ZigGlobalObject
## Development Workflow
### Code Formatting
- `bun run prettier` - Format JS/TS files
- `bun run zig-format` - Format Zig files
- `bun run clang-format` - Format C++ files
### Watching for Changes
- `bun run watch` - Incremental Zig compilation with error checking
- `bun run watch-windows` - Windows-specific watch mode
### Code Generation
Code generation happens automatically as part of the build process. The main scripts are:
@@ -177,47 +193,6 @@ Built-in JavaScript modules use special syntax and are organized as:
- `internal/` - Internal modules not exposed to users
- `builtins/` - Core JavaScript builtins (streams, console, etc.)
### Special Syntax in Built-in Modules
1. **`$` prefix** - Access to private properties and JSC intrinsics:
```js
const arr = $Array.from(...); // Private global
map.$set(...); // Private method
const arr2 = $newArrayWithSize(5); // JSC intrinsic
```
2. **`require()`** - Must use string literals, resolved at compile time:
```js
const fs = require("fs"); // Directly loads by numeric ID
```
3. **Debug helpers**:
- `$debug()` - Like console.log but stripped in release builds
- `$assert()` - Assertions stripped in release builds
- `if($debug) {}` - Check if debug env var is set
4. **Platform detection**: `process.platform` and `process.arch` are inlined and dead-code eliminated
5. **Export syntax**: Use `export default` which gets converted to a return statement:
```js
export default {
readFile,
writeFile,
};
```
Note: These are NOT ES modules. The preprocessor converts `$` to `@` (JSC's actual syntax) and handles the special functions.
## CI
Bun uses BuildKite for CI. To get the status of a PR, you can use the following command:
```bash
bun ci
```
## Important Development Notes
1. **Never use `bun test` or `bun <file>` directly** - always use `bun bd test` or `bun bd <command>`. `bun bd` compiles & runs the debug build.
@@ -229,19 +204,8 @@ bun ci
7. **Avoid shell commands** - Don't use `find` or `grep` in tests; use Bun's Glob and built-in tools
8. **Memory management** - In Zig code, be careful with allocators and use defer for cleanup
9. **Cross-platform** - Run `bun run zig:check-all` to compile the Zig code on all platforms when making platform-specific changes
10. **Debug builds** - Use `BUN_DEBUG_QUIET_LOGS=1` to disable debug logging, or `BUN_DEBUG_<scope>=1` to enable specific scopes
10. **Debug builds** - Use `BUN_DEBUG_QUIET_LOGS=1` to disable debug logging, or `BUN_DEBUG_<scopeName>=1` to enable specific `Output.scoped(.${scopeName}, .visible)`s
11. **Be humble & honest** - NEVER overstate what you got done or what actually works in commits, PRs or in messages to the user.
12. **Branch names must start with `claude/`** - This is a requirement for the CI to work.
## Key APIs and Features
### Bun-Specific APIs
- **Bun.serve()** - High-performance HTTP server
- **Bun.spawn()** - Process spawning with better performance than Node.js
- **Bun.file()** - Fast file I/O operations
- **Bun.write()** - Unified API for writing to files, stdout, etc.
- **Bun.$ (Shell)** - Cross-platform shell scripting
- **Bun.SQLite** - Native SQLite integration
- **Bun.FFI** - Call native libraries from JavaScript
- **Bun.Glob** - Fast file pattern matching
**ONLY** push up changes after running `bun bd test <file>` and ensuring your tests pass.

View File

@@ -24,7 +24,16 @@ if(CMAKE_HOST_APPLE)
include(SetupMacSDK)
endif()
include(SetupLLVM)
include(SetupCcache)
find_program(SCCACHE_PROGRAM sccache)
if(SCCACHE_PROGRAM AND NOT DEFINED ENV{NO_SCCACHE})
include(SetupSccache)
else()
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
include(SetupCcache)
endif()
endif()
# --- Project ---

View File

@@ -2,26 +2,40 @@ Configuring a development environment for Bun can take 10-30 minutes depending o
If you are using Windows, please refer to [this guide](https://bun.com/docs/project/building-windows)
## Install Dependencies
## Using Nix (Alternative)
A Nix flake is provided as an alternative to manual dependency installation:
```bash
nix develop
# or explicitly use the pure shell
# nix develop .#pure
export CMAKE_SYSTEM_PROCESSOR=$(uname -m)
bun bd
```
This provides all dependencies in an isolated, reproducible environment without requiring sudo.
## Install Dependencies (Manual)
Using your system's package manager, install Bun's dependencies:
{% codetabs group="os" %}
```bash#macOS (Homebrew)
$ brew install automake ccache cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rust ruby
$ brew install automake cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rust ruby sccache
```
```bash#Ubuntu/Debian
$ sudo apt install curl wget lsb-release software-properties-common cargo ccache cmake git golang libtool ninja-build pkg-config rustc ruby-full xz-utils
$ sudo apt install curl wget lsb-release software-properties-common cargo cmake git golang libtool ninja-build pkg-config rustc ruby-full xz-utils
```
```bash#Arch
$ sudo pacman -S base-devel ccache cmake git go libiconv libtool make ninja pkg-config python rust sed unzip ruby
$ sudo pacman -S base-devel cmake git go libiconv libtool make ninja pkg-config python rust sed unzip ruby
```
```bash#Fedora
$ sudo dnf install cargo clang19 llvm19 lld19 ccache cmake git golang libtool ninja-build pkg-config rustc ruby libatomic-static libstdc++-static sed unzip which libicu-devel 'perl(Math::BigInt)'
$ sudo dnf install cargo clang19 llvm19 lld19 cmake git golang libtool ninja-build pkg-config rustc ruby libatomic-static libstdc++-static sed unzip which libicu-devel 'perl(Math::BigInt)'
```
```bash#openSUSE Tumbleweed
@@ -51,6 +65,44 @@ $ brew install bun
{% /codetabs %}
### Optional: Install `sccache`
sccache is used to cache compilation artifacts, significantly speeding up builds. It must be installed with S3 support:
```bash
# For macOS
$ brew install sccache
# For Linux. Note that the version in your package manager may not have S3 support.
$ cargo install sccache --features=s3
```
This will install `sccache` with S3 support. Our build scripts will automatically detect and use `sccache` with our shared S3 cache. **Note**: Not all versions of `sccache` are compiled with S3 support, hence we recommend installing it via `cargo`.
#### Registering AWS Credentials for `sccache` (Core Developers Only)
Core developers have write access to the shared S3 cache. To enable write access, you must log in with AWS credentials. The easiest way to do this is to use the [`aws` CLI](https://aws.amazon.com/cli/) and invoke [`aws configure` to provide your AWS security info](https://docs.aws.amazon.com/cli/latest/reference/configure/).
The `cmake` scripts should automatically detect your AWS credentials from the environment or the `~/.aws/credentials` file.
<details>
<summary>Logging in to the `aws` CLI</summary>
1. Install the AWS CLI by following [the official guide](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html).
2. Log in to your AWS account console. A team member should provide you with your credentials.
3. Click your name in the top right > Security credentials.
4. Scroll to "Access keys" and create a new access key.
5. Run `aws configure` in your terminal and provide the access key ID and secret access key when prompted.
</details>
<details>
<summary>Common Issues You May Encounter</summary>
- To confirm that the cache is being used, you can use the `sccache --show-stats` command right after a build. This will expose very useful statistics, including cache hits/misses.
- If you have multiple AWS profiles configured, ensure that the correct profile is set in the `AWS_PROFILE` environment variable.
- `sccache` follows a server-client model. If you run into weird issues where `sccache` refuses to use S3, even though you have AWS credentials configured, try killing any running `sccache` servers with `sccache --stop-server` and then re-running the build.
</details>
## Install LLVM
Bun requires LLVM 19 (`clang` is part of LLVM). This version requirement is to match WebKit (precompiled), as mismatching versions will cause memory allocation failures at runtime. In most cases, you can install LLVM through your system package manager:
@@ -149,7 +201,7 @@ Bun generally takes about 2.5 minutes to compile a debug build when there are Zi
- Batch up your changes
- Ensure zls is running with incremental watching for LSP errors (if you use VSCode and install Zig and run `bun run build` once to download Zig, this should just work)
- Prefer using the debugger ("CodeLLDB" in VSCode) to step through the code.
- Use debug logs. `BUN_DEBUG_<scope>=1` will enable debug logging for the corresponding `Output.scoped(.<scope>, false)` logs. You can also set `BUN_DEBUG_QUIET_LOGS=1` to disable all debug logging that isn't explicitly enabled. To dump debug lgos into a file, `BUN_DEBUG=<path-to-file>.log`. Debug logs are aggressively removed in release builds.
- Use debug logs. `BUN_DEBUG_<scope>=1` will enable debug logging for the corresponding `Output.scoped(.<scope>, .hidden)` logs. You can also set `BUN_DEBUG_QUIET_LOGS=1` to disable all debug logging that isn't explicitly enabled. To dump debug lgos into a file, `BUN_DEBUG=<path-to-file>.log`. Debug logs are aggressively removed in release builds.
- src/js/\*\*.ts changes are pretty much instant to rebuild. C++ changes are a bit slower, but still much faster than the Zig code (Zig is one compilation unit, C++ is many).
## Code generation scripts
@@ -317,15 +369,6 @@ $ bun run build -DUSE_STATIC_LIBATOMIC=OFF
The built version of Bun may not work on other systems if compiled this way.
### ccache conflicts with building TinyCC on macOS
If you run into issues with `ccache` when building TinyCC, try reinstalling ccache
```bash
brew uninstall ccache
brew install ccache
```
## Using bun-debug
- Disable logging: `BUN_DEBUG_QUIET_LOGS=1 bun-debug ...` (to disable all debug logging)

2
LATEST
View File

@@ -1 +1 @@
1.2.23
1.3.2

View File

@@ -1,40 +1,29 @@
# `install` benchmark
# Create T3 App
Requires [`hyperfine`](https://github.com/sharkdp/hyperfine). The goal of this benchmark is to compare installation performance of Bun with other package managers _when caches are hot_.
This is a [T3 Stack](https://create.t3.gg/) project bootstrapped with `create-t3-app`.
### With lockfile, online mode
## What's next? How do I make an app with this?
To run the benchmark with the standard "install" command for each package manager:
We try to keep this project as simple as possible, so you can start with just the scaffolding we set up for you, and add additional things later when they become necessary.
```sh
$ hyperfine --prepare 'rm -rf node_modules' --warmup 1 --runs 3 'bun install' 'pnpm install' 'yarn' 'npm install'
```
If you are not familiar with the different technologies used in this project, please refer to the respective docs. If you still are in the wind, please join our [Discord](https://t3.gg/discord) and ask for help.
### With lockfile, offline mode
- [Next.js](https://nextjs.org)
- [NextAuth.js](https://next-auth.js.org)
- [Prisma](https://prisma.io)
- [Drizzle](https://orm.drizzle.team)
- [Tailwind CSS](https://tailwindcss.com)
- [tRPC](https://trpc.io)
Even though all packages are cached, some tools may hit the npm API during the version resolution step. (This is not the same as re-downloading a package.) To entirely avoid network calls, the other package managers require `--prefer-offline/--offline` flag. To run the benchmark using "offline" mode:
## Learn More
```sh
$ hyperfine --prepare 'rm -rf node_modules' --runs 1 'bun install' 'pnpm install --prefer-offline' 'yarn --offline' 'npm install --prefer-offline'
```
To learn more about the [T3 Stack](https://create.t3.gg/), take a look at the following resources:
### Without lockfile, offline mode
- [Documentation](https://create.t3.gg/)
- [Learn the T3 Stack](https://create.t3.gg/en/faq#what-learning-resources-are-currently-available) — Check out these awesome tutorials
To run the benchmark with offline mode but without lockfiles:
You can check out the [create-t3-app GitHub repository](https://github.com/t3-oss/create-t3-app) — your feedback and contributions are welcome!
```sh
$ hyperfine --prepare 'rm -rf node_modules' --warmup 1 'rm bun.lock && bun install' 'rm pnpm-lock.yaml && pnpm install --prefer-offline' 'rm yarn.lock && yarn --offline' 'rm package-lock.json && npm install --prefer-offline'
```
## How do I deploy this?
##
To check that the app is working as expected:
```
$ bun run dev
$ npm run dev
$ yarn dev
$ pnpm dev
```
Then visit [http://localhost:3000](http://localhost:3000).
Follow our deployment guides for [Vercel](https://create.t3.gg/en/deployment/vercel), [Netlify](https://create.t3.gg/en/deployment/netlify) and [Docker](https://create.t3.gg/en/deployment/docker) for more information.

View File

@@ -1,18 +0,0 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/docs/en/main/file-conventions/entry.client
*/
import { RemixBrowser } from "@remix-run/react";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>,
);
});

View File

@@ -1,101 +0,0 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/docs/en/main/file-conventions/entry.server
*/
import type { EntryContext } from "@remix-run/node";
import { Response } from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import isbot from "isbot";
import { PassThrough } from "node:stream";
import { renderToPipeableStream } from "react-dom/server";
const ABORT_DELAY = 5_000;
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return isbot(request.headers.get("user-agent"))
? handleBotRequest(request, responseStatusCode, responseHeaders, remixContext)
: handleBrowserRequest(request, responseStatusCode, responseHeaders, remixContext);
}
function handleBotRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return new Promise((resolve, reject) => {
const { pipe, abort } = renderToPipeableStream(
<RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
{
onAllReady() {
const body = new PassThrough();
responseHeaders.set("Content-Type", "text/html");
resolve(
new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
}),
);
pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
console.error(error);
},
},
);
setTimeout(abort, ABORT_DELAY);
});
}
function handleBrowserRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return new Promise((resolve, reject) => {
const { pipe, abort } = renderToPipeableStream(
<RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
{
onShellReady() {
const body = new PassThrough();
responseHeaders.set("Content-Type", "text/html");
resolve(
new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
}),
);
pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
console.error(error);
responseStatusCode = 500;
},
},
);
setTimeout(abort, ABORT_DELAY);
});
}

View File

@@ -1,20 +0,0 @@
import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration } from "@remix-run/react";
export default function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}

View File

@@ -1,30 +0,0 @@
import type { V2_MetaFunction } from "@remix-run/node";
export const meta: V2_MetaFunction = () => {
return [{ title: "New Remix App" }];
};
export default function Index() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Welcome to Remix</h1>
<ul>
<li>
<a target="_blank" href="https://remix.run/tutorials/blog" rel="noreferrer">
15m Quickstart Blog Tutorial
</a>
</li>
<li>
<a target="_blank" href="https://remix.run/tutorials/jokes" rel="noreferrer">
Deep Dive Jokes App Tutorial
</a>
</li>
<li>
<a target="_blank" href="https://remix.run/docs" rel="noreferrer">
Remix Docs
</a>
</li>
</ul>
</div>
);
}

488
bench/install/bun.lock Normal file
View File

@@ -0,0 +1,488 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "installbench",
"dependencies": {
"@auth/drizzle-adapter": "^1.7.2",
"@t3-oss/env-nextjs": "^0.12.0",
"@tanstack/react-query": "^5.69.0",
"@trpc/client": "^11.0.0",
"@trpc/react-query": "^11.0.0",
"@trpc/server": "^11.0.0",
"drizzle-orm": "^0.41.0",
"esbuild": "^0.25.11",
"next": "^15.2.3",
"next-auth": "5.0.0-beta.25",
"postgres": "^3.4.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"server-only": "^0.0.1",
"superjson": "^2.2.1",
"zod": "^3.24.2",
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@tailwindcss/postcss": "^4.0.15",
"@types/node": "^20.14.10",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"drizzle-kit": "^0.30.5",
"postcss": "^8.5.3",
"tailwindcss": "^4.0.15",
"typescript": "^5.8.2",
},
},
},
"packages": {
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
"@auth/core": ["@auth/core@0.41.1", "", { "dependencies": { "@panva/hkdf": "1.2.1", "jose": "6.1.0", "oauth4webapi": "3.8.2", "preact": "10.24.3", "preact-render-to-string": "6.5.11" } }, "sha512-t9cJ2zNYAdWMacGRMT6+r4xr1uybIdmYa49calBPeTqwgAFPV/88ac9TEvCR85pvATiSPt8VaNf+Gt24JIT/uw=="],
"@auth/drizzle-adapter": ["@auth/drizzle-adapter@1.11.1", "", { "dependencies": { "@auth/core": "0.41.1" } }, "sha512-cQTvDZqsyF7RPhDm/B6SvqdVP9EzQhy3oM4Muu7fjjmSYFLbSR203E6dH631ZHSKDn2b4WZkfMnjPDzRsPSAeA=="],
"@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="],
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="],
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="],
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="],
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="],
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="],
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="],
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="],
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="],
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="],
"@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="],
"@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "0.18.20", "source-map-support": "0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="],
"@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "3.3.2", "get-tsconfig": "4.13.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.11", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.11", "", { "os": "android", "cpu": "arm" }, "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.11", "", { "os": "android", "cpu": "arm64" }, "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.11", "", { "os": "android", "cpu": "x64" }, "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.11", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.11", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.11", "", { "os": "linux", "cpu": "arm" }, "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.11", "", { "os": "linux", "cpu": "ia32" }, "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.11", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.11", "", { "os": "linux", "cpu": "s390x" }, "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.11", "", { "os": "linux", "cpu": "x64" }, "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.11", "", { "os": "none", "cpu": "x64" }, "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.11", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.11", "", { "os": "openbsd", "cpu": "x64" }, "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.11", "", { "os": "sunos", "cpu": "x64" }, "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.11", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.11", "", { "os": "win32", "cpu": "x64" }, "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA=="],
"@img/colour": ["@img/colour@1.0.0", "", {}, "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw=="],
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.3" }, "os": "darwin", "cpu": "arm64" }, "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA=="],
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.3" }, "os": "darwin", "cpu": "x64" }, "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg=="],
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw=="],
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA=="],
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.3", "", { "os": "linux", "cpu": "arm" }, "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA=="],
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ=="],
"@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg=="],
"@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w=="],
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.3", "", { "os": "linux", "cpu": "x64" }, "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg=="],
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw=="],
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.3", "", { "os": "linux", "cpu": "x64" }, "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g=="],
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.3" }, "os": "linux", "cpu": "arm" }, "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA=="],
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.3" }, "os": "linux", "cpu": "arm64" }, "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ=="],
"@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.3" }, "os": "linux", "cpu": "ppc64" }, "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ=="],
"@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.3" }, "os": "linux", "cpu": "s390x" }, "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw=="],
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.3" }, "os": "linux", "cpu": "x64" }, "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A=="],
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.3" }, "os": "linux", "cpu": "arm64" }, "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA=="],
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.3" }, "os": "linux", "cpu": "x64" }, "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg=="],
"@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.4", "", { "dependencies": { "@emnapi/runtime": "1.6.0" }, "cpu": "none" }, "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA=="],
"@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA=="],
"@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw=="],
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.4", "", { "os": "win32", "cpu": "x64" }, "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "3.1.2", "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
"@next/env": ["@next/env@15.5.6", "", {}, "sha512-3qBGRW+sCGzgbpc5TS1a0p7eNxnOarGVQhZxfvTdnV0gFI61lX7QNtQ4V1TSREctXzYn5NetbUsLvyqwLFJM6Q=="],
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.5.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ES3nRz7N+L5Umz4KoGfZ4XX6gwHplwPhioVRc25+QNsDa7RtUF/z8wJcbuQ2Tffm5RZwuN2A063eapoJ1u4nPg=="],
"@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.5.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-JIGcytAyk9LQp2/nuVZPAtj8uaJ/zZhsKOASTjxDug0SPU9LAM3wy6nPU735M1OqacR4U20LHVF5v5Wnl9ptTA=="],
"@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-qvz4SVKQ0P3/Im9zcS2RmfFL/UCQnsJKJwQSkissbngnB/12c6bZTCB0gHTexz1s6d/mD0+egPKXAIRFVS7hQg=="],
"@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-FsbGVw3SJz1hZlvnWD+T6GFgV9/NYDeLTNQB2MXoPN5u9VA9OEDy6fJEfePfsUKAhJufFbZLgp0cPxMuV6SV0w=="],
"@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-3QnHGFWlnvAgyxFxt2Ny8PTpXtQD7kVEeaFat5oPAHHI192WKYB+VIKZijtHLGdBBvc16tiAkPTDmQNOQ0dyrA=="],
"@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-OsGX148sL+TqMK9YFaPFPoIaJKbFJJxFzkXZljIgA9hjMjdruKht6xDCEv1HLtlLNfkx3c5w2GLKhj7veBQizQ=="],
"@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.5.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-ONOMrqWxdzXDJNh2n60H6gGyKed42Ieu6UTVPZteXpuKbLZTH4G4eBMsr5qWgOBA+s7F+uB4OJbZnrkEDnZ5Fg=="],
"@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-pxK4VIjFRx1MY92UycLOOw7dTdvccWsNETQ0kDHkBlcFH1GrTLUjSiHU1ohrznnux6TqRHgv5oflhfIWZwVROQ=="],
"@panva/hkdf": ["@panva/hkdf@1.2.1", "", {}, "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw=="],
"@petamoriken/float16": ["@petamoriken/float16@3.9.3", "", {}, "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g=="],
"@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="],
"@t3-oss/env-core": ["@t3-oss/env-core@0.12.0", "", { "optionalDependencies": { "typescript": "5.9.3", "zod": "3.25.76" } }, "sha512-lOPj8d9nJJTt81mMuN9GMk8x5veOt7q9m11OSnCBJhwp1QrL/qR+M8Y467ULBSm9SunosryWNbmQQbgoiMgcdw=="],
"@t3-oss/env-nextjs": ["@t3-oss/env-nextjs@0.12.0", "", { "dependencies": { "@t3-oss/env-core": "0.12.0" }, "optionalDependencies": { "typescript": "5.9.3", "zod": "3.25.76" } }, "sha512-rFnvYk1049RnNVUPvY8iQ55AuQh1Rr+qZzQBh3t++RttCGK4COpXGNxS4+45afuQq02lu+QAOy/5955aU8hRKw=="],
"@tailwindcss/node": ["@tailwindcss/node@4.1.16", "", { "dependencies": { "@jridgewell/remapping": "2.3.5", "enhanced-resolve": "5.18.3", "jiti": "2.6.1", "lightningcss": "1.30.2", "magic-string": "0.30.21", "source-map-js": "1.2.1", "tailwindcss": "4.1.16" } }, "sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw=="],
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.16", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.16", "@tailwindcss/oxide-darwin-arm64": "4.1.16", "@tailwindcss/oxide-darwin-x64": "4.1.16", "@tailwindcss/oxide-freebsd-x64": "4.1.16", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.16", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.16", "@tailwindcss/oxide-linux-arm64-musl": "4.1.16", "@tailwindcss/oxide-linux-x64-gnu": "4.1.16", "@tailwindcss/oxide-linux-x64-musl": "4.1.16", "@tailwindcss/oxide-wasm32-wasi": "4.1.16", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.16", "@tailwindcss/oxide-win32-x64-msvc": "4.1.16" } }, "sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg=="],
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.16", "", { "os": "android", "cpu": "arm64" }, "sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA=="],
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.16", "", { "os": "darwin", "cpu": "arm64" }, "sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA=="],
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.16", "", { "os": "darwin", "cpu": "x64" }, "sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg=="],
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.16", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg=="],
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16", "", { "os": "linux", "cpu": "arm" }, "sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw=="],
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w=="],
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ=="],
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.16", "", { "os": "linux", "cpu": "x64" }, "sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew=="],
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.16", "", { "os": "linux", "cpu": "x64" }, "sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw=="],
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.16", "", { "cpu": "none" }, "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q=="],
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.16", "", { "os": "win32", "cpu": "arm64" }, "sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A=="],
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.16", "", { "os": "win32", "cpu": "x64" }, "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg=="],
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.16", "", { "dependencies": { "@alloc/quick-lru": "5.2.0", "@tailwindcss/node": "4.1.16", "@tailwindcss/oxide": "4.1.16", "postcss": "8.5.6", "tailwindcss": "4.1.16" } }, "sha512-Qn3SFGPXYQMKR/UtqS+dqvPrzEeBZHrFA92maT4zijCVggdsXnDBMsPFJo1eArX3J+O+Gi+8pV4PkqjLCNBk3A=="],
"@tanstack/query-core": ["@tanstack/query-core@5.90.5", "", {}, "sha512-wLamYp7FaDq6ZnNehypKI5fNvxHPfTYylE0m/ZpuuzJfJqhR5Pxg9gvGBHZx4n7J+V5Rg5mZxHHTlv25Zt5u+w=="],
"@tanstack/react-query": ["@tanstack/react-query@5.90.5", "", { "dependencies": { "@tanstack/query-core": "5.90.5" }, "peerDependencies": { "react": "19.2.0" } }, "sha512-pN+8UWpxZkEJ/Rnnj2v2Sxpx1WFlaa9L6a4UO89p6tTQbeo+m0MS8oYDjbggrR8QcTyjKoYWKS3xJQGr3ExT8Q=="],
"@trpc/client": ["@trpc/client@11.7.1", "", { "peerDependencies": { "@trpc/server": "11.7.1", "typescript": "5.9.3" } }, "sha512-uOnAjElKI892/U6aQMcBHYs3x7mme3Cvv1F87ytBL56rBvs7+DyK7r43zgaXKf13+GtPEI6ex5xjVUfyDW8XcQ=="],
"@trpc/react-query": ["@trpc/react-query@11.7.1", "", { "peerDependencies": { "@tanstack/react-query": "5.90.5", "@trpc/client": "11.7.1", "@trpc/server": "11.7.1", "react": "19.2.0", "react-dom": "19.2.0", "typescript": "5.9.3" } }, "sha512-dEHDjIqSTzO8nLlCbtiFBMBwhbSkK1QP7aYVo3nP3sYBna0b+iCtrPXdxVPCSopr9/aIqDTEh+dMRZa7yBgjfQ=="],
"@trpc/server": ["@trpc/server@11.7.1", "", { "peerDependencies": { "typescript": "5.9.3" } }, "sha512-N3U8LNLIP4g9C7LJ/sLkjuPHwqlvE3bnspzC4DEFVdvx2+usbn70P80E3wj5cjOTLhmhRiwJCSXhlB+MHfGeCw=="],
"@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="],
"@types/node": ["@types/node@20.19.24", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-FE5u0ezmi6y9OZEzlJfg37mqqf6ZDSF2V/NLjUyGrR9uTZ7Sb9F7bLNZ03S4XVUNRWGA7Ck4c1kK+YnuWjl+DA=="],
"@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "3.1.3" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
"@types/react-dom": ["@types/react-dom@19.2.2", "", { "peerDependencies": { "@types/react": "19.2.2" } }, "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw=="],
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
"caniuse-lite": ["caniuse-lite@1.0.30001752", "", {}, "sha512-vKUk7beoukxE47P5gcVNKkDRzXdVofotshHwfR9vmpeFKxmI5PBpgOMC18LUJUA/DvJ70Y7RveasIBraqsyO/g=="],
"client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="],
"cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="],
"copy-anything": ["copy-anything@4.0.5", "", { "dependencies": { "is-what": "5.5.0" } }, "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"drizzle-kit": ["drizzle-kit@0.30.6", "", { "dependencies": { "@drizzle-team/brocli": "0.10.2", "@esbuild-kit/esm-loader": "2.6.5", "esbuild": "0.19.12", "esbuild-register": "3.6.0", "gel": "2.1.1" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-U4wWit0fyZuGuP7iNmRleQyK2V8wCuv57vf5l3MnG4z4fzNTjY/U13M8owyQ5RavqvqxBifWORaR3wIUzlN64g=="],
"drizzle-orm": ["drizzle-orm@0.41.0", "", { "optionalDependencies": { "gel": "2.1.1", "postgres": "3.4.7" } }, "sha512-7A4ZxhHk9gdlXmTdPj/lREtP+3u8KvZ4yEN6MYVxBzZGex5Wtdc+CWSbu7btgF6TB0N+MNPrvW7RKBbxJchs/Q=="],
"enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "4.2.11", "tapable": "2.3.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="],
"env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="],
"esbuild": ["esbuild@0.25.11", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.11", "@esbuild/android-arm": "0.25.11", "@esbuild/android-arm64": "0.25.11", "@esbuild/android-x64": "0.25.11", "@esbuild/darwin-arm64": "0.25.11", "@esbuild/darwin-x64": "0.25.11", "@esbuild/freebsd-arm64": "0.25.11", "@esbuild/freebsd-x64": "0.25.11", "@esbuild/linux-arm": "0.25.11", "@esbuild/linux-arm64": "0.25.11", "@esbuild/linux-ia32": "0.25.11", "@esbuild/linux-loong64": "0.25.11", "@esbuild/linux-mips64el": "0.25.11", "@esbuild/linux-ppc64": "0.25.11", "@esbuild/linux-riscv64": "0.25.11", "@esbuild/linux-s390x": "0.25.11", "@esbuild/linux-x64": "0.25.11", "@esbuild/netbsd-arm64": "0.25.11", "@esbuild/netbsd-x64": "0.25.11", "@esbuild/openbsd-arm64": "0.25.11", "@esbuild/openbsd-x64": "0.25.11", "@esbuild/openharmony-arm64": "0.25.11", "@esbuild/sunos-x64": "0.25.11", "@esbuild/win32-arm64": "0.25.11", "@esbuild/win32-ia32": "0.25.11", "@esbuild/win32-x64": "0.25.11" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q=="],
"esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "4.4.3" }, "peerDependencies": { "esbuild": "0.19.12" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="],
"gel": ["gel@2.1.1", "", { "dependencies": { "@petamoriken/float16": "3.9.3", "debug": "4.4.3", "env-paths": "3.0.0", "semver": "7.7.3", "shell-quote": "1.8.3", "which": "4.0.0" }, "bin": { "gel": "dist/cli.mjs" } }, "sha512-Newg9X7mRYskoBjSw70l1YnJ/ZGbq64VPyR821H5WVkTGpHG2O0mQILxCeUhxdYERLFY9B4tUyKLyf3uMTjtKw=="],
"get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="],
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
"is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="],
"isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="],
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"jose": ["jose@6.1.0", "", {}, "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA=="],
"lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "2.1.2" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"next": ["next@15.5.6", "", { "dependencies": { "@next/env": "15.5.6", "@swc/helpers": "0.5.15", "caniuse-lite": "1.0.30001752", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.5.6", "@next/swc-darwin-x64": "15.5.6", "@next/swc-linux-arm64-gnu": "15.5.6", "@next/swc-linux-arm64-musl": "15.5.6", "@next/swc-linux-x64-gnu": "15.5.6", "@next/swc-linux-x64-musl": "15.5.6", "@next/swc-win32-arm64-msvc": "15.5.6", "@next/swc-win32-x64-msvc": "15.5.6", "sharp": "0.34.4" }, "peerDependencies": { "react": "19.2.0", "react-dom": "19.2.0" }, "bin": { "next": "dist/bin/next" } }, "sha512-zTxsnI3LQo3c9HSdSf91O1jMNsEzIXDShXd4wVdg9y5shwLqBXi4ZtUUJyB86KGVSJLZx0PFONvO54aheGX8QQ=="],
"next-auth": ["next-auth@5.0.0-beta.25", "", { "dependencies": { "@auth/core": "0.37.2" }, "peerDependencies": { "next": "15.5.6", "react": "19.2.0" } }, "sha512-2dJJw1sHQl2qxCrRk+KTQbeH+izFbGFPuJj5eGgBZFYyiYYtvlrBeUw1E/OJJxTRjuxbSYGnCTkUIRsIIW0bog=="],
"oauth4webapi": ["oauth4webapi@3.8.2", "", {}, "sha512-FzZZ+bht5X0FKe7Mwz3DAVAmlH1BV5blSak/lHMBKz0/EBMhX6B10GlQYI51+oRp8ObJaX0g6pXrAxZh5s8rjw=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "3.3.11", "picocolors": "1.1.1", "source-map-js": "1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
"postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="],
"preact": ["preact@10.24.3", "", {}, "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA=="],
"preact-render-to-string": ["preact-render-to-string@6.5.11", "", { "peerDependencies": { "preact": "10.24.3" } }, "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw=="],
"pretty-format": ["pretty-format@3.8.0", "", {}, "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="],
"react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
"react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "0.27.0" }, "peerDependencies": { "react": "19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
"semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"server-only": ["server-only@0.0.1", "", {}, "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA=="],
"sharp": ["sharp@0.34.4", "", { "dependencies": { "@img/colour": "1.0.0", "detect-libc": "2.1.2", "semver": "7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.4", "@img/sharp-darwin-x64": "0.34.4", "@img/sharp-libvips-darwin-arm64": "1.2.3", "@img/sharp-libvips-darwin-x64": "1.2.3", "@img/sharp-libvips-linux-arm": "1.2.3", "@img/sharp-libvips-linux-arm64": "1.2.3", "@img/sharp-libvips-linux-ppc64": "1.2.3", "@img/sharp-libvips-linux-s390x": "1.2.3", "@img/sharp-libvips-linux-x64": "1.2.3", "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", "@img/sharp-libvips-linuxmusl-x64": "1.2.3", "@img/sharp-linux-arm": "0.34.4", "@img/sharp-linux-arm64": "0.34.4", "@img/sharp-linux-ppc64": "0.34.4", "@img/sharp-linux-s390x": "0.34.4", "@img/sharp-linux-x64": "0.34.4", "@img/sharp-linuxmusl-arm64": "0.34.4", "@img/sharp-linuxmusl-x64": "0.34.4", "@img/sharp-wasm32": "0.34.4", "@img/sharp-win32-arm64": "0.34.4", "@img/sharp-win32-ia32": "0.34.4", "@img/sharp-win32-x64": "0.34.4" } }, "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA=="],
"shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "1.1.2", "source-map": "0.6.1" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
"styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": "19.2.0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="],
"superjson": ["superjson@2.2.5", "", { "dependencies": { "copy-anything": "4.0.5" } }, "sha512-zWPTX96LVsA/eVYnqOM2+ofcdPqdS1dAF1LN4TS2/MWuUpfitd9ctTa87wt4xrYnZnkLtS69xpBdSxVBP5Rm6w=="],
"tailwindcss": ["tailwindcss@4.1.16", "", {}, "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA=="],
"tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
"which": ["which@4.0.0", "", { "dependencies": { "isexe": "3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
"drizzle-kit/esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="],
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "3.3.11", "picocolors": "1.1.1", "source-map-js": "1.2.1" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
"next-auth/@auth/core": ["@auth/core@0.37.2", "", { "dependencies": { "@panva/hkdf": "1.2.1", "@types/cookie": "0.6.0", "cookie": "0.7.1", "jose": "5.10.0", "oauth4webapi": "3.8.2", "preact": "10.11.3", "preact-render-to-string": "5.2.3" } }, "sha512-kUvzyvkcd6h1vpeMAojK2y7+PAV5H+0Cc9+ZlKYDFhDY31AlvsB+GW5vNO4qE3Y07KeQgvNO9U0QUx/fN62kBw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
"drizzle-kit/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="],
"drizzle-kit/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.19.12", "", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="],
"drizzle-kit/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.19.12", "", { "os": "android", "cpu": "arm64" }, "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA=="],
"drizzle-kit/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.19.12", "", { "os": "android", "cpu": "x64" }, "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew=="],
"drizzle-kit/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.19.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g=="],
"drizzle-kit/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.19.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A=="],
"drizzle-kit/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.19.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA=="],
"drizzle-kit/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.19.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg=="],
"drizzle-kit/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.19.12", "", { "os": "linux", "cpu": "arm" }, "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w=="],
"drizzle-kit/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.19.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA=="],
"drizzle-kit/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.19.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA=="],
"drizzle-kit/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA=="],
"drizzle-kit/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w=="],
"drizzle-kit/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.19.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg=="],
"drizzle-kit/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg=="],
"drizzle-kit/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.19.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg=="],
"drizzle-kit/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.19.12", "", { "os": "linux", "cpu": "x64" }, "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg=="],
"drizzle-kit/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.19.12", "", { "os": "none", "cpu": "x64" }, "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA=="],
"drizzle-kit/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.19.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw=="],
"drizzle-kit/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.19.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA=="],
"drizzle-kit/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.19.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A=="],
"drizzle-kit/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.19.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ=="],
"drizzle-kit/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="],
"next-auth/@auth/core/jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="],
"next-auth/@auth/core/preact": ["preact@10.11.3", "", {}, "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg=="],
"next-auth/@auth/core/preact-render-to-string": ["preact-render-to-string@5.2.3", "", { "dependencies": { "pretty-format": "3.8.0" }, "peerDependencies": { "preact": "10.11.3" } }, "sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA=="],
}
}

5
bench/install/next-env.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@@ -0,0 +1,10 @@
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
*/
import "./src/env.js";
/** @type {import("next").NextConfig} */
const config = {};
export default config;

View File

@@ -1,31 +1,52 @@
{
"name": "installbench",
"version": "0.1.0",
"private": true,
"sideEffects": false,
"type": "module",
"scripts": {
"build": "remix build",
"dev": "remix dev",
"start": "remix-serve build",
"typecheck": "tsc",
"clean": "rm -rf node_modules",
"bench": "hyperfine --prepare 'rm -rf node_modules' --warmup 1 --runs 3 'bun install' 'pnpm install' 'yarn' 'npm install'"
"build": "next build",
"check": "biome check .",
"check:unsafe": "biome check --write --unsafe .",
"check:write": "biome check --write .",
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:push": "drizzle-kit push",
"db:studio": "drizzle-kit studio",
"dev": "next dev --turbo",
"preview": "next build && next start",
"start": "next start",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@remix-run/node": "^1.15.0",
"@remix-run/react": "^1.15.0",
"@remix-run/serve": "^1.15.0",
"isbot": "^3.6.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"@auth/drizzle-adapter": "^1.7.2",
"@t3-oss/env-nextjs": "^0.12.0",
"@tanstack/react-query": "^5.69.0",
"@trpc/client": "^11.0.0",
"@trpc/react-query": "^11.0.0",
"@trpc/server": "^11.0.0",
"drizzle-orm": "^0.41.0",
"esbuild": "^0.25.11",
"next": "^15.2.3",
"next-auth": "5.0.0-beta.25",
"postgres": "^3.4.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"server-only": "^0.0.1",
"superjson": "^2.2.1",
"zod": "^3.24.2"
},
"devDependencies": {
"@remix-run/dev": "^1.15.0",
"@remix-run/eslint-config": "^1.15.0",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.8",
"eslint": "^8.27.0",
"typescript": "^4.8.4"
"@biomejs/biome": "1.9.4",
"@tailwindcss/postcss": "^4.0.15",
"@types/node": "^20.14.10",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"drizzle-kit": "^0.30.5",
"postcss": "^8.5.3",
"tailwindcss": "^4.0.15",
"typescript": "^5.8.2"
},
"engines": {
"node": ">=14"
"ct3aMetadata": {
"initVersion": "7.39.3"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,14 +0,0 @@
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
ignoredRouteFiles: ["**/.*"],
// appDirectory: "app",
// assetsBuildDirectory: "public/build",
// serverBuildPath: "build/index.js",
// publicPath: "/build/",
future: {
v2_errorBoundary: true,
v2_meta: true,
v2_normalizeFormMethod: true,
v2_routeConvention: true,
},
};

View File

@@ -1,2 +0,0 @@
/// <reference types="@remix-run/dev" />
/// <reference types="@remix-run/node" />

View File

@@ -1,22 +0,0 @@
{
"include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2019"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"resolveJsonModule": true,
"target": "ES2019",
"strict": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
// Remix takes care of building everything in `remix build`.
"noEmit": true
}
}

View File

@@ -4,20 +4,16 @@
"": {
"name": "react-hello-world",
"dependencies": {
"react": "next",
"react-dom": "next",
"react": "^19.2.0",
"react-dom": "^19.2.0",
},
},
},
"packages": {
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
"react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
"react": ["react@18.3.0-next-b72ed698f-20230303", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-l6RbwXa9Peerh9pQEq62DDypxSQfavbybY0wV1vwZ63X0P5VaaEesZAz1KPpnVvXjTtQaOMQsIPvnQwmaVqzTQ=="],
"react-dom": ["react-dom@18.3.0-next-b72ed698f-20230303", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "0.24.0-next-b72ed698f-20230303" }, "peerDependencies": { "react": "18.3.0-next-b72ed698f-20230303" } }, "sha512-0Gh/gmTT6H8KxswIQB/8shdTTfs6QIu86nNqZf3Y0RBqIwgTVxRaQVz14/Fw4/Nt81nK/Jt6KT4bx3yvOxZDGQ=="],
"scheduler": ["scheduler@0.24.0-next-b72ed698f-20230303", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-ct4DMMFbc2kFxCdvbG+i/Jn1S1oqrIFSn2VX/mam+Ya0iuNy+lb8rgT7A+YBUqrQNDaNEqABYI2sOQgqoRxp7w=="],
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
}
}

View File

@@ -4,13 +4,14 @@
"description": "",
"main": "react-hello-world.node.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"build:workerd": "bun build react-hello-world.workerd.jsx --outfile=react-hello-world.workerd.js --format=esm --production && (echo '// MessageChannel polyfill for workerd'; echo 'if (typeof MessageChannel === \"undefined\") {'; echo ' globalThis.MessageChannel = class MessageChannel {'; echo ' constructor() {'; echo ' this.port1 = { onmessage: null, postMessage: () => {} };'; echo ' this.port2 = {'; echo ' postMessage: (msg) => {'; echo ' if (this.port1.onmessage) {'; echo ' queueMicrotask(() => this.port1.onmessage({ data: msg }));'; echo ' }'; echo ' }'; echo ' };'; echo ' }'; echo ' };'; echo '}'; cat react-hello-world.workerd.js) > temp.js && mv temp.js react-hello-world.workerd.js"
},
"keywords": [],
"author": "Colin McDonnell",
"license": "ISC",
"dependencies": {
"react": "next",
"react-dom": "next"
"react": "^19.2.0",
"react-dom": "^19.2.0"
}
}

View File

@@ -0,0 +1,23 @@
using Workerd = import "/workerd/workerd.capnp";
const config :Workerd.Config = (
services = [
(name = "main", worker = .mainWorker),
],
sockets = [
( name = "http",
address = "*:3001",
http = (),
service = "main"
),
]
);
const mainWorker :Workerd.Worker = (
modules = [
(name = "worker", esModule = embed "react-hello-world.workerd.js"),
],
compatibilityDate = "2025-01-01",
compatibilityFlags = ["nodejs_compat_v2"],
);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,40 @@
// Cloudflare Workers version with export default fetch
// Run with: workerd serve react-hello-world.workerd.config.capnp
// Polyfill MessageChannel for workerd
if (typeof MessageChannel === 'undefined') {
globalThis.MessageChannel = class MessageChannel {
constructor() {
this.port1 = { onmessage: null, postMessage: () => {} };
this.port2 = {
postMessage: (msg) => {
if (this.port1.onmessage) {
queueMicrotask(() => this.port1.onmessage({ data: msg }));
}
}
};
}
};
}
import React from "react";
import { renderToReadableStream } from "react-dom/server";
const headers = {
"Content-Type": "text/html",
};
const App = () => (
<html>
<body>
<h1>Hello World</h1>
<p>This is an example.</p>
</body>
</html>
);
export default {
async fetch(request) {
return new Response(await renderToReadableStream(<App />), { headers });
},
};

View File

@@ -11,10 +11,10 @@ const builtin = ${JSON.stringify(builtin)};
const now = performance.now();
require(builtin);
const end = performance.now();
process.stdout.write(JSON.stringify({builtin, time: end - now}) + "\\n");
process.stdout.write(JSON.stringify({ builtin, time: end - now }) + "\\n");
`,
);
const result = spawnSync(typeof Bun !== "undefined" ? "bun" : "node", [path], {
spawnSync(process.execPath, [path], {
stdio: ["inherit", "inherit", "inherit"],
env: {
...process.env,

View File

@@ -49,6 +49,7 @@ const BunBuildOptions = struct {
enable_logs: bool = false,
enable_asan: bool,
enable_valgrind: bool,
use_mimalloc: bool,
tracy_callstack_depth: u16,
reported_nodejs_version: Version,
/// To make iterating on some '@embedFile's faster, we load them at runtime
@@ -97,6 +98,7 @@ const BunBuildOptions = struct {
opts.addOption(bool, "enable_logs", this.enable_logs);
opts.addOption(bool, "enable_asan", this.enable_asan);
opts.addOption(bool, "enable_valgrind", this.enable_valgrind);
opts.addOption(bool, "use_mimalloc", this.use_mimalloc);
opts.addOption([]const u8, "reported_nodejs_version", b.fmt("{}", .{this.reported_nodejs_version}));
opts.addOption(bool, "zig_self_hosted_backend", this.no_llvm);
opts.addOption(bool, "override_no_export_cpp_apis", this.override_no_export_cpp_apis);
@@ -270,6 +272,7 @@ pub fn build(b: *Build) !void {
.enable_logs = b.option(bool, "enable_logs", "Enable logs in release") orelse false,
.enable_asan = b.option(bool, "enable_asan", "Enable asan") orelse false,
.enable_valgrind = b.option(bool, "enable_valgrind", "Enable valgrind") orelse false,
.use_mimalloc = b.option(bool, "use_mimalloc", "Use mimalloc as default allocator") orelse false,
.llvm_codegen_threads = b.option(u32, "llvm_codegen_threads", "Number of threads to use for LLVM codegen") orelse 1,
};
@@ -500,6 +503,7 @@ fn addMultiCheck(
.no_llvm = root_build_options.no_llvm,
.enable_asan = root_build_options.enable_asan,
.enable_valgrind = root_build_options.enable_valgrind,
.use_mimalloc = root_build_options.use_mimalloc,
.override_no_export_cpp_apis = root_build_options.override_no_export_cpp_apis,
};
@@ -720,6 +724,7 @@ fn addInternalImports(b: *Build, mod: *Module, opts: *BunBuildOptions) void {
// Generated code exposed as individual modules.
inline for (.{
.{ .file = "ZigGeneratedClasses.zig", .import = "ZigGeneratedClasses" },
.{ .file = "bindgen_generated.zig", .import = "bindgen_generated" },
.{ .file = "ResolvedSourceTag.zig", .import = "ResolvedSourceTag" },
.{ .file = "ErrorCode.zig", .import = "ErrorCode" },
.{ .file = "runtime.out.js", .enable = opts.shouldEmbedCode() },

View File

@@ -8,14 +8,14 @@
"@lezer/cpp": "^1.1.3",
"@types/bun": "workspace:*",
"bun-tracestrings": "github:oven-sh/bun.report#912ca63e26c51429d3e6799aa2a6ab079b188fd8",
"esbuild": "^0.21.4",
"mitata": "^0.1.11",
"esbuild": "^0.21.5",
"mitata": "^0.1.14",
"peechy": "0.4.34",
"prettier": "^3.5.3",
"prettier-plugin-organize-imports": "^4.0.0",
"prettier": "^3.6.2",
"prettier-plugin-organize-imports": "^4.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"source-map-js": "^1.2.0",
"source-map-js": "^1.2.1",
"typescript": "5.9.2",
},
},
@@ -284,7 +284,7 @@
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
"prettier-plugin-organize-imports": ["prettier-plugin-organize-imports@4.2.0", "", { "peerDependencies": { "prettier": ">=2.0", "typescript": ">=2.9", "vue-tsc": "^2.1.0 || 3" }, "optionalPeers": ["vue-tsc"] }, "sha512-Zdy27UhlmyvATZi67BTnLcKTo8fm6Oik59Sz6H64PgZJVs6NJpPD1mT240mmJn62c98/QaL+r3kx9Q3gRpDajg=="],
"prettier-plugin-organize-imports": ["prettier-plugin-organize-imports@4.3.0", "", { "peerDependencies": { "prettier": ">=2.0", "typescript": ">=2.9", "vue-tsc": "^2.1.0 || 3" }, "optionalPeers": ["vue-tsc"] }, "sha512-FxFz0qFhyBsGdIsb697f/EkvHzi5SZOhWAjxcx2dLt+Q532bAlhswcXGYB1yzjZ69kW8UoadFBw7TyNwlq96Iw=="],
"react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],

View File

@@ -10,3 +10,4 @@ preload = "./test/preload.ts"
[install]
linker = "isolated"
minimumReleaseAge = 1

View File

@@ -86,11 +86,20 @@ elseif(APPLE)
endif()
if(UNIX)
register_compiler_flags(
DESCRIPTION "Enable debug symbols"
-g3 -gz=zstd ${DEBUG}
-g1 ${RELEASE}
)
# Nix LLVM doesn't support zstd compression, use zlib instead
if(DEFINED ENV{NIX_CC})
register_compiler_flags(
DESCRIPTION "Enable debug symbols (zlib-compressed for Nix)"
-g3 -gz=zlib ${DEBUG}
-g1 ${RELEASE}
)
else()
register_compiler_flags(
DESCRIPTION "Enable debug symbols (zstd-compressed)"
-g3 -gz=zstd ${DEBUG}
-g1 ${RELEASE}
)
endif()
register_compiler_flags(
DESCRIPTION "Optimize debug symbols for LLDB"
@@ -206,43 +215,6 @@ if(ENABLE_ASSERTIONS)
DESCRIPTION "Do not eliminate null-pointer checks"
-fno-delete-null-pointer-checks
)
register_compiler_definitions(
DESCRIPTION "Enable libc++ assertions"
_LIBCPP_ENABLE_ASSERTIONS=1
_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE ${RELEASE}
_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG ${DEBUG}
)
register_compiler_definitions(
DESCRIPTION "Enable fortified sources"
_FORTIFY_SOURCE=3
)
if(LINUX)
register_compiler_definitions(
DESCRIPTION "Enable glibc++ assertions"
_GLIBCXX_ASSERTIONS=1
)
endif()
else()
register_compiler_definitions(
DESCRIPTION "Disable debug assertions"
NDEBUG=1
)
register_compiler_definitions(
DESCRIPTION "Disable libc++ assertions"
_LIBCPP_ENABLE_ASSERTIONS=0
_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE
)
if(LINUX)
register_compiler_definitions(
DESCRIPTION "Disable glibc++ assertions"
_GLIBCXX_ASSERTIONS=0
)
endif()
endif()
# --- Diagnostics ---
@@ -293,14 +265,6 @@ if(UNIX AND CI)
)
endif()
# --- Features ---
# Valgrind cannot handle SSE4.2 instructions
# This is needed for picohttpparser
if(ENABLE_VALGRIND AND ARCH STREQUAL "x64")
register_compiler_definitions(__SSE4_2__=0)
endif()
# --- Other ---
# Workaround for CMake and clang-cl bug.

View File

@@ -125,7 +125,7 @@ setx(CWD ${CMAKE_SOURCE_DIR})
setx(BUILD_PATH ${CMAKE_BINARY_DIR})
optionx(CACHE_PATH FILEPATH "The path to the cache directory" DEFAULT ${BUILD_PATH}/cache)
optionx(CACHE_STRATEGY "read-write|read-only|write-only|none" "The strategy to use for caching" DEFAULT "read-write")
optionx(CACHE_STRATEGY "read-write|read-only|none" "The strategy to use for caching" DEFAULT "read-write")
optionx(CI BOOL "If CI is enabled" DEFAULT OFF)
optionx(ENABLE_ANALYSIS BOOL "If static analysis targets should be enabled" DEFAULT OFF)
@@ -136,13 +136,6 @@ else()
set(WARNING WARNING)
endif()
# TODO: This causes flaky zig builds in CI, so temporarily disable it.
# if(CI)
# set(DEFAULT_VENDOR_PATH ${CACHE_PATH}/vendor)
# else()
# set(DEFAULT_VENDOR_PATH ${CWD}/vendor)
# endif()
optionx(VENDOR_PATH FILEPATH "The path to the vendor directory" DEFAULT ${CWD}/vendor)
optionx(TMP_PATH FILEPATH "The path to the temporary directory" DEFAULT ${BUILD_PATH}/tmp)
@@ -317,7 +310,7 @@ function(find_command)
${FIND_VALIDATOR}
)
if(NOT FIND_REQUIRED STREQUAL "OFF" AND ${FIND_VARIABLE} MATCHES "NOTFOUND")
if(FIND_REQUIRED AND ${FIND_VARIABLE} MATCHES "NOTFOUND")
set(error "Command not found: \"${FIND_NAME}\"")
if(FIND_VERSION)
@@ -917,10 +910,6 @@ function(register_compiler_flags)
endforeach()
endfunction()
function(register_compiler_definitions)
endfunction()
# register_linker_flags()
# Description:
# Registers a linker flag, similar to `add_link_options()`.

View File

@@ -140,11 +140,6 @@ if(ENABLE_ASAN AND ENABLE_LTO)
setx(ENABLE_LTO OFF)
endif()
if(USE_VALGRIND AND NOT USE_BASELINE)
message(WARNING "If valgrind is enabled, baseline must also be enabled")
setx(USE_BASELINE ON)
endif()
if(BUILDKITE_COMMIT)
set(DEFAULT_REVISION ${BUILDKITE_COMMIT})
else()
@@ -202,4 +197,9 @@ optionx(USE_WEBKIT_ICU BOOL "Use the ICU libraries from WebKit" DEFAULT ${DEFAUL
optionx(ERROR_LIMIT STRING "Maximum number of errors to show when compiling C++ code" DEFAULT "100")
# This is not an `option` because setting this variable to OFF is experimental
# and unsupported. This replaces the `use_mimalloc` variable previously in
# bun.zig, and enables C++ code to also be aware of the option.
set(USE_MIMALLOC_AS_DEFAULT_ALLOCATOR ON)
list(APPEND CMAKE_ARGS -DCMAKE_EXPORT_COMPILE_COMMANDS=ON)

View File

@@ -31,6 +31,14 @@
"output": "BindgenSources.txt",
"paths": ["src/**/*.bind.ts"]
},
{
"output": "BindgenV2Sources.txt",
"paths": ["src/**/*.bindv2.ts"]
},
{
"output": "BindgenV2InternalSources.txt",
"paths": ["src/codegen/bindgenv2/**/*.ts"]
},
{
"output": "ZigSources.txt",
"paths": ["src/**/*.zig"]

View File

@@ -1,33 +0,0 @@
# https://cppcheck.sourceforge.io/
find_command(
VARIABLE
CPPCHECK_EXECUTABLE
COMMAND
cppcheck
REQUIRED
OFF
)
set(CPPCHECK_COMMAND ${CPPCHECK_EXECUTABLE}
--cppcheck-build-dir=${BUILD_PATH}/cppcheck
--project=${BUILD_PATH}/compile_commands.json
--clang=${CMAKE_CXX_COMPILER}
--std=c++${CMAKE_CXX_STANDARD}
--report-progress
--showtime=summary
)
register_command(
TARGET
cppcheck
COMMENT
"Running cppcheck"
COMMAND
${CMAKE_COMMAND} -E make_directory cppcheck
&& ${CPPCHECK_COMMAND}
CWD
${BUILD_PATH}
TARGETS
${bun}
)

View File

@@ -1,22 +0,0 @@
find_command(
VARIABLE
CPPLINT_PROGRAM
COMMAND
cpplint
REQUIRED
OFF
)
register_command(
TARGET
cpplint
COMMENT
"Running cpplint"
COMMAND
${CPPLINT_PROGRAM}
${BUN_CPP_SOURCES}
CWD
${BUILD_PATH}
TARGETS
${bun}
)

View File

@@ -1,67 +0,0 @@
# IWYU = "Include What You Use"
# https://include-what-you-use.org/
setx(IWYU_SOURCE_PATH ${CACHE_PATH}/iwyu-${LLVM_VERSION})
setx(IWYU_BUILD_PATH ${IWYU_SOURCE_PATH}/build)
setx(IWYU_PROGRAM ${IWYU_BUILD_PATH}/bin/include-what-you-use)
register_repository(
NAME
iwyu
REPOSITORY
include-what-you-use/include-what-you-use
BRANCH
clang_${LLVM_VERSION}
PATH
${IWYU_SOURCE_PATH}
)
register_command(
TARGET
build-iwyu
COMMENT
"Building iwyu"
COMMAND
${CMAKE_COMMAND}
-B${IWYU_BUILD_PATH}
-G${CMAKE_GENERATOR}
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER}
-DIWYU_LLVM_ROOT_PATH=${LLVM_PREFIX}
&& ${CMAKE_COMMAND}
--build ${IWYU_BUILD_PATH}
CWD
${IWYU_SOURCE_PATH}
TARGETS
clone-iwyu
)
find_command(
VARIABLE
PYTHON_EXECUTABLE
COMMAND
python3
python
VERSION
>=3.0.0
REQUIRED
OFF
)
register_command(
TARGET
iwyu
COMMENT
"Running iwyu"
COMMAND
${CMAKE_COMMAND}
-E env IWYU_BINARY=${IWYU_PROGRAM}
${PYTHON_EXECUTABLE}
${IWYU_SOURCE_PATH}/iwyu_tool.py
-p ${BUILD_PATH}
CWD
${BUILD_PATH}
TARGETS
build-iwyu
${bun}
)

View File

@@ -45,12 +45,6 @@ else()
endif()
set(LLVM_ZIG_CODEGEN_THREADS 0)
# This makes the build slower, so we turn it off for now.
# if (DEBUG)
# include(ProcessorCount)
# ProcessorCount(CPU_COUNT)
# set(LLVM_ZIG_CODEGEN_THREADS ${CPU_COUNT})
# endif()
# --- Dependencies ---
@@ -71,9 +65,6 @@ set(BUN_DEPENDENCIES
)
include(CloneZstd)
# foreach(dependency ${BUN_DEPENDENCIES})
# include(Clone${dependency})
# endforeach()
# --- Codegen ---
@@ -395,6 +386,54 @@ register_command(
${BUN_BAKE_RUNTIME_OUTPUTS}
)
set(BUN_BINDGENV2_SCRIPT ${CWD}/src/codegen/bindgenv2/script.ts)
absolute_sources(BUN_BINDGENV2_SOURCES ${CWD}/cmake/sources/BindgenV2Sources.txt)
# These sources include the script itself.
absolute_sources(BUN_BINDGENV2_INTERNAL_SOURCES
${CWD}/cmake/sources/BindgenV2InternalSources.txt)
string(REPLACE ";" "," BUN_BINDGENV2_SOURCES_COMMA_SEPARATED
"${BUN_BINDGENV2_SOURCES}")
execute_process(
COMMAND ${BUN_EXECUTABLE} run ${BUN_BINDGENV2_SCRIPT}
--command=list-outputs
--sources=${BUN_BINDGENV2_SOURCES_COMMA_SEPARATED}
--codegen-path=${CODEGEN_PATH}
RESULT_VARIABLE bindgen_result
OUTPUT_VARIABLE bindgen_outputs
)
if(${bindgen_result})
message(FATAL_ERROR "bindgenv2/script.ts exited with non-zero status")
endif()
foreach(output IN LISTS bindgen_outputs)
if(output MATCHES "\.cpp$")
list(APPEND BUN_BINDGENV2_CPP_OUTPUTS ${output})
elseif(output MATCHES "\.zig$")
list(APPEND BUN_BINDGENV2_ZIG_OUTPUTS ${output})
else()
message(FATAL_ERROR "unexpected bindgen output: [${output}]")
endif()
endforeach()
register_command(
TARGET
bun-bindgen-v2
COMMENT
"Generating bindings (v2)"
COMMAND
${BUN_EXECUTABLE} run ${BUN_BINDGENV2_SCRIPT}
--command=generate
--codegen-path=${CODEGEN_PATH}
--sources=${BUN_BINDGENV2_SOURCES_COMMA_SEPARATED}
SOURCES
${BUN_BINDGENV2_SOURCES}
${BUN_BINDGENV2_INTERNAL_SOURCES}
OUTPUTS
${BUN_BINDGENV2_CPP_OUTPUTS}
${BUN_BINDGENV2_ZIG_OUTPUTS}
)
set(BUN_BINDGEN_SCRIPT ${CWD}/src/codegen/bindgen.ts)
absolute_sources(BUN_BINDGEN_SOURCES ${CWD}/cmake/sources/BindgenSources.txt)
@@ -573,6 +612,7 @@ set(BUN_ZIG_GENERATED_SOURCES
${BUN_ZIG_GENERATED_CLASSES_OUTPUTS}
${BUN_JAVASCRIPT_OUTPUTS}
${BUN_CPP_OUTPUTS}
${BUN_BINDGENV2_ZIG_OUTPUTS}
)
# In debug builds, these are not embedded, but rather referenced at runtime.
@@ -636,6 +676,7 @@ register_command(
-Denable_logs=$<IF:$<BOOL:${ENABLE_LOGS}>,true,false>
-Denable_asan=$<IF:$<BOOL:${ENABLE_ZIG_ASAN}>,true,false>
-Denable_valgrind=$<IF:$<BOOL:${ENABLE_VALGRIND}>,true,false>
-Duse_mimalloc=$<IF:$<BOOL:${USE_MIMALLOC_AS_DEFAULT_ALLOCATOR}>,true,false>
-Dllvm_codegen_threads=${LLVM_ZIG_CODEGEN_THREADS}
-Dversion=${VERSION}
-Dreported_nodejs_version=${NODEJS_VERSION}
@@ -712,6 +753,7 @@ list(APPEND BUN_CPP_SOURCES
${BUN_JAVASCRIPT_OUTPUTS}
${BUN_OBJECT_LUT_OUTPUTS}
${BUN_BINDGEN_CPP_OUTPUTS}
${BUN_BINDGENV2_CPP_OUTPUTS}
)
if(WIN32)
@@ -768,7 +810,7 @@ set_target_properties(${bun} PROPERTIES
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS YES
CXX_VISIBILITY_PRESET hidden
C_STANDARD 17
C_STANDARD 17 # Cannot uprev to C23 because MSVC doesn't have support.
C_STANDARD_REQUIRED YES
VISIBILITY_INLINES_HIDDEN YES
)
@@ -849,6 +891,10 @@ if(WIN32)
)
endif()
if(USE_MIMALLOC_AS_DEFAULT_ALLOCATOR)
target_compile_definitions(${bun} PRIVATE USE_MIMALLOC=1)
endif()
target_compile_definitions(${bun} PRIVATE
_HAS_EXCEPTIONS=0
LIBUS_USE_OPENSSL=1
@@ -889,7 +935,7 @@ if(NOT WIN32)
if (NOT ABI STREQUAL "musl")
target_compile_options(${bun} PUBLIC
-fsanitize=null
-fsanitize-recover=all
-fno-sanitize-recover=all
-fsanitize=bounds
-fsanitize=return
-fsanitize=nullability-arg
@@ -944,6 +990,20 @@ if(NOT WIN32)
)
if(ENABLE_ASAN)
target_compile_options(${bun} PUBLIC
-fsanitize=null
-fno-sanitize-recover=all
-fsanitize=bounds
-fsanitize=return
-fsanitize=nullability-arg
-fsanitize=nullability-assign
-fsanitize=nullability-return
-fsanitize=returns-nonnull-attribute
-fsanitize=unreachable
)
target_link_libraries(${bun} PRIVATE
-fsanitize=null
)
target_compile_options(${bun} PUBLIC -fsanitize=address)
target_link_libraries(${bun} PUBLIC -fsanitize=address)
endif()
@@ -990,7 +1050,6 @@ if(APPLE)
-Wl,-no_compact_unwind
-Wl,-stack_size,0x1200000
-fno-keep-static-consts
-Wl,-map,${bun}.linker-map
)
if(DEBUG)
@@ -1010,6 +1069,7 @@ if(APPLE)
target_link_options(${bun} PUBLIC
-dead_strip
-dead_strip_dylibs
-Wl,-map,${bun}.linker-map
)
endif()
endif()
@@ -1043,6 +1103,17 @@ if(LINUX)
)
endif()
if (ENABLE_LTO)
# We are optimizing for size at a slight debug-ability cost
target_link_options(${bun} PUBLIC
-Wl,--no-eh-frame-hdr
)
else()
target_link_options(${bun} PUBLIC
-Wl,--eh-frame-hdr
)
endif()
target_link_options(${bun} PUBLIC
--ld-path=${LLD_PROGRAM}
-fno-pic
@@ -1057,11 +1128,9 @@ if(LINUX)
# make debug info faster to load
-Wl,--gdb-index
-Wl,-z,combreloc
-Wl,--no-eh-frame-hdr
-Wl,--sort-section=name
-Wl,--hash-style=both
-Wl,--build-id=sha1 # Better for debugging than default
-Wl,-Map=${bun}.linker-map
)
# don't strip in debug, this seems to be needed so that the Zig std library
@@ -1076,6 +1145,7 @@ if(LINUX)
if (NOT DEBUG AND NOT ENABLE_ASAN AND NOT ENABLE_VALGRIND)
target_link_options(${bun} PUBLIC
-Wl,-icf=safe
-Wl,-Map=${bun}.linker-map
)
endif()
@@ -1182,15 +1252,9 @@ if(LINUX)
target_link_libraries(${bun} PUBLIC libatomic.so)
endif()
if(USE_SYSTEM_ICU)
target_link_libraries(${bun} PRIVATE libicudata.a)
target_link_libraries(${bun} PRIVATE libicui18n.a)
target_link_libraries(${bun} PRIVATE libicuuc.a)
else()
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicudata.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicui18n.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicuuc.a)
endif()
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicudata.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicui18n.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicuuc.a)
endif()
if(WIN32)
@@ -1243,32 +1307,32 @@ if(NOT BUN_CPP_ONLY)
OUTPUTS
${BUILD_PATH}/${bunStripExe}
)
# Then sign both executables on Windows
if(WIN32 AND ENABLE_WINDOWS_CODESIGNING)
set(SIGN_SCRIPT "${CMAKE_SOURCE_DIR}/.buildkite/scripts/sign-windows.ps1")
# Verify signing script exists
if(NOT EXISTS "${SIGN_SCRIPT}")
message(FATAL_ERROR "Windows signing script not found: ${SIGN_SCRIPT}")
endif()
# Use PowerShell for Windows code signing (native Windows, no path issues)
find_program(POWERSHELL_EXECUTABLE
find_program(POWERSHELL_EXECUTABLE
NAMES pwsh.exe powershell.exe
PATHS
PATHS
"C:/Program Files/PowerShell/7"
"C:/Program Files (x86)/PowerShell/7"
"C:/Windows/System32/WindowsPowerShell/v1.0"
DOC "Path to PowerShell executable"
)
if(NOT POWERSHELL_EXECUTABLE)
set(POWERSHELL_EXECUTABLE "powershell.exe")
endif()
message(STATUS "Using PowerShell executable: ${POWERSHELL_EXECUTABLE}")
# Sign both bun-profile.exe and bun.exe after stripping
register_command(
TARGET
@@ -1397,7 +1461,7 @@ if(NOT BUN_CPP_ONLY)
list(APPEND bunFiles ${bun}.dSYM)
endif()
if(APPLE OR LINUX)
if((APPLE OR LINUX) AND NOT ENABLE_ASAN)
list(APPEND bunFiles ${bun}.linker-map)
endif()

View File

@@ -4,7 +4,7 @@ register_repository(
REPOSITORY
google/highway
COMMIT
12b325bc1793dee68ab2157995a690db859fe9e0
ac0d5d297b13ab1b89f48484fc7911082d76a93f
)
set(HIGHWAY_CMAKE_ARGS

View File

@@ -4,7 +4,7 @@ register_repository(
REPOSITORY
ebiggers/libdeflate
COMMIT
96836d7d9d10e3e0d53e6edb54eb908514e336c4
c8c56a20f8f621e6a966b716b31f1dedab6a41e3
)
register_cmake_command(

View File

@@ -4,8 +4,8 @@ register_repository(
REPOSITORY
libuv/libuv
COMMIT
# Corresponds to v1.51.0
5152db2cbfeb5582e9c27c5ea1dba2cd9e10759b
# Latest HEAD (includes recursion bug fix #4784)
f3ce527ea940d926c40878ba5de219640c362811
)
if(WIN32)

View File

@@ -49,3 +49,6 @@ else()
setenv(CCACHE_MAXSIZE 100G)
setenv(CCACHE_SLOPPINESS "pch_defines,time_macros,locale,random_seed,clang_index_store,gcno_cwd")
endif()

View File

@@ -0,0 +1,90 @@
if(CACHE_STRATEGY STREQUAL "none")
return()
endif()
function(check_aws_credentials OUT_VAR)
set(HAS_CREDENTIALS FALSE)
if(DEFINED ENV{AWS_ACCESS_KEY_ID} AND DEFINED ENV{AWS_SECRET_ACCESS_KEY})
set(HAS_CREDENTIALS TRUE)
message(NOTICE
"sccache: Using AWS credentials found in environment variables")
endif()
# Check for ~/.aws directory since sccache may use that.
if(NOT HAS_CREDENTIALS)
if(WIN32)
set(AWS_CONFIG_DIR "$ENV{USERPROFILE}/.aws")
else()
set(AWS_CONFIG_DIR "$ENV{HOME}/.aws")
endif()
if(EXISTS "${AWS_CONFIG_DIR}/credentials")
set(HAS_CREDENTIALS TRUE)
message(NOTICE
"sccache: Using AWS credentials found in ${AWS_CONFIG_DIR}/credentials")
endif()
endif()
set(${OUT_VAR} ${HAS_CREDENTIALS} PARENT_SCOPE)
endfunction()
function(check_running_in_ci OUT_VAR)
set(IS_CI FALSE)
# Query EC2 instance metadata service to check if running on buildkite-agent
# The IP address 169.254.169.254 is a well-known link-local address for querying EC2 instance
# metdata:
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html
execute_process(
COMMAND curl -s -m 0.5 http://169.254.169.254/latest/meta-data/tags/instance/Service
OUTPUT_VARIABLE METADATA_OUTPUT
ERROR_VARIABLE METADATA_ERROR
RESULT_VARIABLE METADATA_RESULT
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
# Check if the request succeeded and returned exactly "buildkite-agent"
if(METADATA_RESULT EQUAL 0 AND METADATA_OUTPUT STREQUAL "buildkite-agent")
set(IS_CI TRUE)
endif()
set(${OUT_VAR} ${IS_CI} PARENT_SCOPE)
endfunction()
check_running_in_ci(IS_IN_CI)
find_command(VARIABLE SCCACHE_PROGRAM COMMAND sccache REQUIRED ${IS_IN_CI})
if(NOT SCCACHE_PROGRAM)
message(WARNING "sccache not found. Your builds will be slower.")
return()
endif()
set(SCCACHE_ARGS CMAKE_C_COMPILER_LAUNCHER CMAKE_CXX_COMPILER_LAUNCHER)
foreach(arg ${SCCACHE_ARGS})
setx(${arg} ${SCCACHE_PROGRAM})
list(APPEND CMAKE_ARGS -D${arg}=${${arg}})
endforeach()
# Configure S3 bucket for distributed caching
setenv(SCCACHE_BUCKET "bun-build-sccache-store")
setenv(SCCACHE_REGION "us-west-1")
setenv(SCCACHE_DIR "${CACHE_PATH}/sccache")
# Handle credentials based on cache strategy
if (CACHE_STRATEGY STREQUAL "read-only")
setenv(SCCACHE_S3_NO_CREDENTIALS "1")
message(STATUS "sccache configured in read-only mode.")
else()
# Check for AWS credentials and enable anonymous access if needed
check_aws_credentials(HAS_AWS_CREDENTIALS)
if(NOT IS_IN_CI AND NOT HAS_AWS_CREDENTIALS)
setenv(SCCACHE_S3_NO_CREDENTIALS "1")
message(NOTICE "sccache: No AWS credentials found, enabling anonymous S3 "
"access. Writing to the cache will be disabled.")
endif()
endif()
setenv(SCCACHE_LOG "info")
message(STATUS "sccache configured for bun-build-sccache-store (us-west-1).")

View File

@@ -1,4 +1,4 @@
FROM alpine:3.20 AS build
FROM alpine:3.22 AS build
# https://github.com/oven-sh/bun/releases
ARG BUN_VERSION=latest
@@ -44,7 +44,7 @@ RUN apk --no-cache add ca-certificates curl dirmngr gpg gpg-agent unzip \
&& rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \
&& chmod +x /usr/local/bin/bun
FROM alpine:3.20
FROM alpine:3.22
# Disable the runtime transpiler cache by default inside Docker containers.
# On ephemeral containers, the cache is not useful

28
docs/README.md Normal file
View File

@@ -0,0 +1,28 @@
<p align="center">
<a href="https://bun.com">
<img src="https://github.com/user-attachments/assets/50282090-adfd-4ddb-9e27-c30753c6b161" alt="Logo" height="170" />
</a>
</p>
<h1 align="center">Bun Documentation</h1>
Official documentation for Bun: the fast, all-in-one JavaScript runtime.
## Development
Install the [Mintlify CLI](https://www.npmjs.com/package/mint) to preview the documentation locally:
```bash
bun install -g mint
```
Run the development server:
```bash
mint dev
```
The site will be available at `http://localhost:3000`.
## Contributing
Contributions are welcome! Please open an issue or submit a pull request.

View File

@@ -1,19 +0,0 @@
Bun.js has fast paths for common use cases that make Web APIs live up to the performance demands of servers and CLIs.
`Bun.file(path)` returns a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) that represents a lazily-loaded file.
When you pass a file blob to `Bun.write`, Bun automatically uses a faster system call:
```js
const blob = Bun.file("input.txt");
await Bun.write("output.txt", blob);
```
On Linux, this uses the [`copy_file_range`](https://man7.org/linux/man-pages/man2/copy_file_range.2.html) syscall and on macOS, this becomes `clonefile` (or [`fcopyfile`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/copyfile.3.html)).
`Bun.write` also supports [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. It automatically converts to a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
```js
// Eventually, this will stream the response to disk but today it buffers
await Bun.write("index.html", await fetch("https://example.com"));
```

View File

@@ -1,387 +0,0 @@
Bun implements the following globals.
{% table %}
- Global
- Source
- Notes
---
- [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
- Web
- &nbsp;
---
- [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
- Web
- &nbsp;
---
- [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert)
- Web
- Intended for command-line tools
---
- [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
- Web
- &nbsp;
---
- [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer)
- Node.js
- See [Node.js > `Buffer`](https://bun.com/docs/runtime/nodejs-apis#node-buffer)
---
- `Bun`
- Bun
- Subject to change as additional APIs are added
---
- [`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy)
- Web
- &nbsp;
---
- [`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm)
- Web
- Intended for command-line tools
---
- [`__dirname`](https://nodejs.org/api/globals.html#__dirname)
- Node.js
- &nbsp;
---
- [`__filename`](https://nodejs.org/api/globals.html#__filename)
- Node.js
- &nbsp;
---
- [`atob()`](https://developer.mozilla.org/en-US/docs/Web/API/atob)
- Web
- &nbsp;
---
- [`btoa()`](https://developer.mozilla.org/en-US/docs/Web/API/btoa)
- Web
- &nbsp;
---
- `BuildMessage`
- Bun
- &nbsp;
---
- [`clearImmediate()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearImmediate)
- Web
- &nbsp;
---
- [`clearInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearInterval)
- Web
- &nbsp;
---
- [`clearTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearTimeout)
- Web
- &nbsp;
---
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console)
- Web
- &nbsp;
---
- [`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy)
- Web
- &nbsp;
---
- [`Crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto)
- Web
- &nbsp;
---
- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/crypto)
- Web
- &nbsp;
---
- [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
- Web
- &nbsp;
---
- [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent)
- Web
- &nbsp;
---
- [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event)
- Web
- Also [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) [`CloseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent).
---
- [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
- Web
- &nbsp;
---
- [`exports`](https://nodejs.org/api/globals.html#exports)
- Node.js
- &nbsp;
---
- [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch)
- Web
- &nbsp;
---
- [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData)
- Web
- &nbsp;
---
- [`global`](https://nodejs.org/api/globals.html#global)
- Node.js
- See [Node.js > `global`](https://bun.com/docs/runtime/nodejs-apis#global).
---
- [`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis)
- Cross-platform
- Aliases to `global`
---
- [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers)
- Web
- &nbsp;
---
- [`HTMLRewriter`](https://bun.com/docs/api/html-rewriter)
- Cloudflare
- &nbsp;
---
- [`JSON`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON)
- Web
- &nbsp;
---
- [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent)
- Web
- &nbsp;
---
- [`module`](https://nodejs.org/api/globals.html#module)
- Node.js
- &nbsp;
---
- [`performance`](https://developer.mozilla.org/en-US/docs/Web/API/performance)
- Web
- &nbsp;
---
- [`process`](https://nodejs.org/api/process.html)
- Node.js
- See [Node.js > `process`](https://bun.com/docs/runtime/nodejs-apis#node-process)
---
- [`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt)
- Web
- Intended for command-line tools
---
- [`queueMicrotask()`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask)
- Web
- &nbsp;
---
- [`ReadableByteStreamController`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableByteStreamController)
- Web
- &nbsp;
---
- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
- Web
- &nbsp;
---
- [`ReadableStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultController)
- Web
- &nbsp;
---
- [`ReadableStreamDefaultReader`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader)
- Web
- &nbsp;
---
- [`reportError`](https://developer.mozilla.org/en-US/docs/Web/API/reportError)
- Web
- &nbsp;
---
- [`require()`](https://nodejs.org/api/globals.html#require)
- Node.js
- &nbsp;
---
- `ResolveMessage`
- Bun
- &nbsp;
---
- [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
- Web
- &nbsp;
---
- [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
- Web
- &nbsp;
---
- [`setImmediate()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate)
- Web
- &nbsp;
---
- [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval)
- Web
- &nbsp;
---
- [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout)
- Web
- &nbsp;
---
- [`ShadowRealm`](https://github.com/tc39/proposal-shadowrealm)
- Web
- Stage 3 proposal
---
- [`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto)
- Web
- &nbsp;
---
- [`DOMException`](https://developer.mozilla.org/en-US/docs/Web/API/DOMException)
- Web
- &nbsp;
---
- [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder)
- Web
- &nbsp;
---
- [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder)
- Web
- &nbsp;
---
- [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream)
- Web
- &nbsp;
---
- [`TransformStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStreamDefaultController)
- Web
- &nbsp;
---
- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL)
- Web
- &nbsp;
---
- [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
- Web
- &nbsp;
---
- [`WebAssembly`](https://nodejs.org/api/globals.html#webassembly)
- Web
- &nbsp;
---
- [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream)
- Web
- &nbsp;
---
- [`WritableStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultController)
- Web
- &nbsp;
---
- [`WritableStreamDefaultWriter`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter)
- Web
- &nbsp;
{% /table %}

File diff suppressed because it is too large Load Diff

View File

@@ -1,69 +0,0 @@
The `import.meta` object is a way for a module to access information about itself. It's part of the JavaScript language, but its contents are not standardized. Each "host" (browser, runtime, etc) is free to implement any properties it wishes on the `import.meta` object.
Bun implements the following properties.
```ts#/path/to/project/file.ts
import.meta.dir; // => "/path/to/project"
import.meta.file; // => "file.ts"
import.meta.path; // => "/path/to/project/file.ts"
import.meta.url; // => "file:///path/to/project/file.ts"
import.meta.main; // `true` if this file is directly executed by `bun run`
// `false` otherwise
import.meta.resolve("zod"); // => "file:///path/to/project/node_modules/zod/index.js"
```
{% table %}
---
- `import.meta.dir`
- Absolute path to the directory containing the current file, e.g. `/path/to/project`. Equivalent to `__dirname` in CommonJS modules (and Node.js)
---
- `import.meta.dirname`
- An alias to `import.meta.dir`, for Node.js compatibility
---
- `import.meta.env`
- An alias to `process.env`.
---
- `import.meta.file`
- The name of the current file, e.g. `index.tsx`
---
- `import.meta.path`
- Absolute path to the current file, e.g. `/path/to/project/index.ts`. Equivalent to `__filename` in CommonJS modules (and Node.js)
---
- `import.meta.filename`
- An alias to `import.meta.path`, for Node.js compatibility
---
- `import.meta.main`
- Indicates whether the current file is the entrypoint to the current `bun` process. Is the file being directly executed by `bun run` or is it being imported?
---
- `import.meta.resolve`
- Resolve a module specifier (e.g. `"zod"` or `"./file.tsx"`) to a url. Equivalent to [`import.meta.resolve` in browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta#resolve)
```ts
import.meta.resolve("zod");
// => "file:///path/to/project/node_modules/zod/index.ts"
```
---
- `import.meta.url`
- A `string` url to the current file, e.g. `file:///path/to/project/index.ts`. Equivalent to [`import.meta.url` in browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta#url)
{% /table %}

View File

@@ -1,120 +0,0 @@
Bun.js focuses on performance, developer experience, and compatibility with the JavaScript ecosystem.
## HTTP Requests
```ts
// http.ts
export default {
port: 3000,
fetch(request: Request) {
return new Response("Hello World");
},
};
// bun ./http.ts
```
| Requests per second | OS | CPU | Bun version |
| ---------------------------------------------------------------------- | ----- | ------------------------------ | ----------- |
| [260,000](https://twitter.com/jarredsumner/status/1512040623200616449) | macOS | Apple Silicon M1 Max | 0.0.76 |
| [160,000](https://twitter.com/jarredsumner/status/1511988933587976192) | Linux | AMD Ryzen 5 3600 6-Core 2.2ghz | 0.0.76 |
{% details summary="See benchmark details" %}
Measured with [`http_load_test`](https://github.com/uNetworking/uSockets/blob/master/examples/http_load_test.c) by running:
```bash
$ ./http_load_test 20 127.0.0.1 3000
```
{% /details %}
## File System
`cat` clone that runs [2x faster than GNU cat](https://twitter.com/jarredsumner/status/1511707890708586496) for large files on Linux
```js
// cat.js
import { resolve } from "path";
import { write, stdout, file, argv } from "bun";
const path = resolve(argv.at(-1));
await write(
// stdout is a Blob
stdout,
// file(path) returns a Blob - https://developer.mozilla.org/en-US/docs/Web/API/Blob
file(path),
);
```
Run this with `bun cat.js /path/to/big/file`.
## Reading from standard input
```ts
for await (const line of console) {
// line of text from stdin
console.log(line);
}
```
## React SSR
```js
import { renderToReadableStream } from "react-dom/server";
const dt = new Intl.DateTimeFormat();
export default {
port: 3000,
async fetch(request: Request) {
return new Response(
await renderToReadableStream(
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello from React!</h1>
<p>The date is {dt.format(new Date())}</p>
</body>
</html>,
),
);
},
};
```
Write to stdout with `console.write`:
```js
// no trailing newline
// works with strings and typed arrays
console.write("Hello World!");
```
There are some more examples in the [examples](./examples) folder.
PRs adding more examples are very welcome!
## Fast paths for Web APIs
Bun.js has fast paths for common use cases that make Web APIs live up to the performance demands of servers and CLIs.
`Bun.file(path)` returns a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) that represents a lazily-loaded file.
When you pass a file blob to `Bun.write`, Bun automatically uses a faster system call:
```js
const blob = Bun.file("input.txt");
await Bun.write("output.txt", blob);
```
On Linux, this uses the [`copy_file_range`](https://man7.org/linux/man-pages/man2/copy_file_range.2.html) syscall and on macOS, this becomes `clonefile` (or [`fcopyfile`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/copyfile.3.html)).
`Bun.write` also supports [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. It automatically converts to a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
```js
// Eventually, this will stream the response to disk but today it buffers
await Bun.write("index.html", await fetch("https://example.com"));
```

View File

@@ -1,42 +0,0 @@
[TOML](https://toml.io/) is a minimal configuration file format designed to be easy for humans to read.
Bun implements a TOML parser with a few tweaks designed for better interoperability with INI files and with JavaScript.
### ; and # are comments
In Bun-flavored TOML, comments start with `#` or `;`
```ini
# This is a comment
; This is also a comment
```
This matches the behavior of INI files.
In TOML, comments start with `#`
```toml
# This is a comment
```
### String escape characters
Bun-flavored adds a few more escape sequences to TOML to work better with JavaScript strings.
```
# Bun-flavored TOML extras
\x{XX} - ASCII (U+00XX)
\u{x+} - unicode (U+0000000X) - (U+XXXXXXXX)
\v - vertical tab
# Regular TOML
\b - backspace (U+0008)
\t - tab (U+0009)
\n - linefeed (U+000A)
\f - form feed (U+000C)
\r - carriage return (U+000D)
\" - quote (U+0022)
\\ - backslash (U+005C)
\uXXXX - unicode (U+XXXX)
\UXXXXXXXX - unicode (U+XXXXXXXX)
```

465
docs/bundler/bytecode.mdx Normal file
View File

@@ -0,0 +1,465 @@
---
title: Bytecode Caching
description: Speed up JavaScript execution with bytecode caching in Bun's bundler
---
Bytecode caching is a build-time optimization that dramatically improves application startup time by pre-compiling your JavaScript to bytecode. For example, when compiling TypeScript's `tsc` with bytecode enabled, startup time improves by **2x**.
## Usage
### Basic usage
Enable bytecode caching with the `--bytecode` flag:
```bash terminal icon="terminal"
bun build ./index.ts --target=bun --bytecode --outdir=./dist
```
This generates two files:
- `dist/index.js` - Your bundled JavaScript
- `dist/index.jsc` - The bytecode cache file
At runtime, Bun automatically detects and uses the `.jsc` file:
```bash terminal icon="terminal"
bun ./dist/index.js # Automatically uses index.jsc
```
### With standalone executables
When creating executables with `--compile`, bytecode is embedded into the binary:
```bash terminal icon="terminal"
bun build ./cli.ts --compile --bytecode --outfile=mycli
```
The resulting executable contains both the code and bytecode, giving you maximum performance in a single file.
### Combining with other optimizations
Bytecode works great with minification and source maps:
```bash terminal icon="terminal"
bun build --compile --bytecode --minify --sourcemap ./cli.ts --outfile=mycli
```
- `--minify` reduces code size before generating bytecode (less code -> less bytecode)
- `--sourcemap` preserves error reporting (errors still point to original source)
- `--bytecode` eliminates parsing overhead
## Performance impact
The performance improvement scales with your codebase size:
| Application size | Typical startup improvement |
| ------------------------- | --------------------------- |
| Small CLI (< 100 KB) | 1.5-2x faster |
| Medium-large app (> 5 MB) | 2.5x-4x faster |
Larger applications benefit more because they have more code to parse.
## When to use bytecode
### Great for:
#### CLI tools
- Invoked frequently (linters, formatters, git hooks)
- Startup time is the entire user experience
- Users notice the difference between 90ms and 45ms startup
- Example: TypeScript compiler, Prettier, ESLint
#### Build tools and task runners
- Run hundreds or thousands of times during development
- Milliseconds saved per run compound quickly
- Developer experience improvement
- Example: Build scripts, test runners, code generators
#### Standalone executables
- Distributed to users who care about snappy performance
- Single-file distribution is convenient
- File size less important than startup time
- Example: CLIs distributed via npm or as binaries
### Skip it for:
- ❌ **Small scripts**
- ❌ **Code that runs once**
- ❌ **Development builds**
- ❌ **Size-constrained environments**
- ❌ **Code with top-level await** (not supported)
## Limitations
### CommonJS only
Bytecode caching currently works with CommonJS output format. Bun's bundler automatically converts most ESM code to CommonJS, but **top-level await** is the exception:
```js
// This prevents bytecode caching
const data = await fetch("https://api.example.com");
export default data;
```
**Why**: Top-level await requires async module evaluation, which can't be represented in CommonJS. The module graph becomes asynchronous, and the CommonJS wrapper function model breaks down.
**Workaround**: Move async initialization into a function:
```js
async function init() {
const data = await fetch("https://api.example.com");
return data;
}
export default init;
```
Now the module exports a function that the consumer can await when needed.
### Version compatibility
Bytecode is **not portable across Bun versions**. The bytecode format is tied to JavaScriptCore's internal representation, which changes between versions.
When you update Bun, you must regenerate bytecode:
```bash terminal icon="terminal"
# After updating Bun
bun build --bytecode ./index.ts --outdir=./dist
```
If bytecode doesn't match the current Bun version, it's automatically ignored and your code falls back to parsing the JavaScript source. Your app still runs - you just lose the performance optimization.
**Best practice**: Generate bytecode as part of your CI/CD build process. Don't commit `.jsc` files to git. Regenerate them whenever you update Bun.
### Source code still required
- The `.js` file (your bundled source code)
- The `.jsc` file (the bytecode cache)
At runtime:
1. Bun loads the `.js` file, sees a `@bytecode` pragma, and checks the `.jsc` file
2. Bun loads the `.jsc` file
3. Bun validates the bytecode hash matches the source
4. If valid, Bun uses the bytecode
5. If invalid, Bun falls back to parsing the source
### Bytecode is not obfuscation
Bytecode **does not obscure your source code**. It's an optimization, not a security measure.
## Production deployment
### Docker
Include bytecode generation in your Dockerfile:
```dockerfile Dockerfile icon="docker"
FROM oven/bun:1 AS builder
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
COPY . .
RUN bun build --bytecode --minify --sourcemap \
--target=bun \
--outdir=./dist \
--compile \
./src/server.ts --outfile=./dist/server
FROM oven/bun:1 AS runner
WORKDIR /app
COPY --from=builder /dist/server /app/server
CMD ["./server"]
```
The bytecode is architecture-independent.
### CI/CD
Generate bytecode during your build pipeline:
```yaml workflow.yml icon="file-code"
# GitHub Actions
- name: Build with bytecode
run: |
bun install
bun build --bytecode --minify \
--outdir=./dist \
--target=bun \
./src/index.ts
```
## Debugging
### Verify bytecode is being used
Check that the `.jsc` file exists:
```bash terminal icon="terminal"
ls -lh dist/
```
```txt
-rw-r--r-- 1 user staff 245K index.js
-rw-r--r-- 1 user staff 1.1M index.jsc
```
The `.jsc` file should be 2-8x larger than the `.js` file.
To log if bytecode is being used, set `BUN_JSC_verboseDiskCache=1` in your environment.
On success, it will log something like:
```txt
[Disk cache] cache hit for sourceCode
```
If you see a cache miss, it will log something like:
```txt
[Disk cache] cache miss for sourceCode
```
It's normal for it it to log a cache miss multiple times since Bun doesn't currently bytecode cache JavaScript code used in builtin modules.
### Common issues
**Bytecode silently ignored**: Usually caused by a Bun version update. The cache version doesn't match, so bytecode is rejected. Regenerate to fix.
**File size too large**: This is expected. Consider:
- Using `--minify` to reduce code size before bytecode generation
- Compressing `.jsc` files for network transfer (gzip/brotli)
- Evaluating if the startup performance gain is worth the size increase
**Top-level await**: Not supported. Refactor to use async initialization functions.
## What is bytecode?
When you run JavaScript, the JavaScript engine doesn't execute your source code directly. Instead, it goes through several steps:
1. **Parsing**: The engine reads your JavaScript source code and converts it into an Abstract Syntax Tree (AST)
2. **Bytecode compilation**: The AST is compiled into bytecode - a lower-level representation that's faster to execute
3. **Execution**: The bytecode is executed by the engine's interpreter or JIT compiler
Bytecode is an intermediate representation - it's lower-level than JavaScript source code, but higher-level than machine code. Think of it as assembly language for a virtual machine. Each bytecode instruction represents a single operation like "load this variable," "add two numbers," or "call this function."
This happens **every single time** you run your code. If you have a CLI tool that runs 100 times a day, your code gets parsed 100 times. If you have a serverless function with frequent cold starts, parsing happens on every cold start.
With bytecode caching, Bun moves steps 1 and 2 to the build step. At runtime, the engine loads the pre-compiled bytecode and jumps straight to execution.
### Why lazy parsing makes this even better
Modern JavaScript engines use a clever optimization called **lazy parsing**. They don't parse all your code upfront - instead, functions are only parsed when they're first called:
```js
// Without bytecode caching:
function rarely_used() {
// This 500-line function is only parsed
// when it's actually called
}
function main() {
console.log("Starting app");
// rarely_used() is never called, so it's never parsed
}
```
This means parsing overhead isn't just a startup cost - it happens throughout your application's lifetime as different code paths execute. With bytecode caching, **all functions are pre-compiled**, even the ones that are lazily parsed. The parsing work happens once at build time instead of being distributed throughout your application's execution.
## The bytecode format
### Inside a .jsc file
A `.jsc` file contains a serialized bytecode structure. Understanding what's inside helps explain both the performance benefits and the file size tradeoff.
**Header section** (validated on every load):
- **Cache version**: A hash tied to the JavaScriptCore framework version. This ensures bytecode generated with one version of Bun only runs with that exact version.
- **Code block type tag**: Identifies whether this is a Program, Module, Eval, or Function code block.
**SourceCodeKey** (validates bytecode matches source):
- **Source code hash**: A hash of the original JavaScript source code. Bun verifies this matches before using the bytecode.
- **Source code length**: The exact length of the source, for additional validation.
- **Compilation flags**: Critical compilation context like strict mode, whether it's a script vs module, eval context type, etc. The same source code compiled with different flags produces different bytecode.
**Bytecode instructions**:
- **Instruction stream**: The actual bytecode opcodes - the compiled representation of your JavaScript. This is a variable-length sequence of bytecode instructions.
- **Metadata table**: Each opcode has associated metadata - things like profiling counters, type hints, and execution counts (even if not yet populated).
- **Jump targets**: Pre-computed addresses for control flow (if/else, loops, switch statements).
- **Switch tables**: Optimized lookup tables for switch statements.
**Constants and identifiers**:
- **Constant pool**: All literal values in your code - numbers, strings, booleans, null, undefined. These are stored as actual JavaScript values (JSValues) so they don't need to be parsed from source at runtime.
- **Identifier table**: All variable and function names used in the code. Stored as deduplicated strings.
- **Source code representation markers**: Flags indicating how constants should be represented (as integers, doubles, big ints, etc.).
**Function metadata** (for each function in your code):
- **Register allocation**: How many registers (local variables) the function needs - `thisRegister`, `scopeRegister`, `numVars`, `numCalleeLocals`, `numParameters`.
- **Code features**: A bitmask of function characteristics: is it a constructor? an arrow function? does it use `super`? does it have tail calls? These affect how the function is executed.
- **Lexically scoped features**: Strict mode and other lexical context.
- **Parse mode**: The mode in which the function was parsed (normal, async, generator, async generator).
**Nested structures**:
- **Function declarations and expressions**: Each nested function gets its own bytecode block, recursively. A file with 100 functions has 100 separate bytecode blocks, all nested in the structure.
- **Exception handlers**: Try/catch/finally blocks with their boundaries and handler addresses pre-computed.
- **Expression info**: Maps bytecode positions back to source code locations for error reporting and debugging.
### What bytecode does NOT contain
Importantly, **bytecode does not embed your source code**. Instead:
- The JavaScript source is stored separately (in the `.js` file)
- The bytecode only stores a hash and length of the source
- At load time, Bun validates the bytecode matches the current source code
This is why you need to deploy both the `.js` and `.jsc` files. The `.jsc` file is useless without its corresponding `.js` file.
## The tradeoff: file size
Bytecode files are significantly larger than source code - typically 2-8x larger.
### Why is bytecode so much larger?
**Bytecode instructions are verbose**:
A single line of minified JavaScript might compile to dozens of bytecode instructions. For example:
```js
const sum = arr.reduce((a, b) => a + b, 0);
```
Compiles to bytecode that:
- Loads the `arr` variable
- Gets the `reduce` property
- Creates the arrow function (which itself has bytecode)
- Loads the initial value `0`
- Sets up the call with the right number of arguments
- Actually performs the call
- Stores the result in `sum`
Each of these steps is a separate bytecode instruction with its own metadata.
**Constant pools store everything**:
Every string literal, number, property name - everything gets stored in the constant pool. Even if your source code has `"hello"` a hundred times, the constant pool stores it once, but the identifier table and constant references add overhead.
**Per-function metadata**:
Each function - even small one-line functions - gets its own complete metadata:
- Register allocation info
- Code features bitmask
- Parse mode
- Exception handlers
- Expression info for debugging
A file with 1,000 small functions has 1,000 sets of metadata.
**Profiling data structures**:
Even though profiling data isn't populated yet, the _structures_ to hold profiling data are allocated. This includes:
- Value profile slots (tracking what types flow through each operation)
- Array profile slots (tracking array access patterns)
- Binary arithmetic profile slots (tracking number types in math operations)
- Unary arithmetic profile slots
These take up space even when empty.
**Pre-computed control flow**:
Jump targets, switch tables, and exception handler boundaries are all pre-computed and stored. This makes execution faster but increases file size.
### Mitigation strategies
**Compression**:
Bytecode compresses extremely well with gzip/brotli (60-70% compression). The repetitive structure and metadata compress efficiently.
**Minification first**:
Using `--minify` before bytecode generation helps:
- Shorter identifiers → smaller identifier table
- Dead code elimination → less bytecode generated
- Constant folding → fewer constants in the pool
**The tradeoff**:
You're trading 2-4x larger files for 2-4x faster startup. For CLIs, this is usually worth it. For long-running servers where a few megabytes of disk space don't matter, it's even less of an issue.
## Versioning and portability
### Cross-architecture portability: ✅
Bytecode is **architecture-independent**. You can:
- Build on macOS ARM64, deploy to Linux x64
- Build on Linux x64, deploy to AWS Lambda ARM64
- Build on Windows x64, deploy to macOS ARM64
The bytecode contains abstract instructions that work on any architecture. Architecture-specific optimizations happen during JIT compilation at runtime, not in the cached bytecode.
### Cross-version portability: ❌
Bytecode is **not stable across Bun versions**. Here's why:
**Bytecode format changes**:
JavaScriptCore's bytecode format evolves. New opcodes get added, old ones get removed or changed, metadata structures change. Each version of JavaScriptCore has a different bytecode format.
**Version validation**:
The cache version in the `.jsc` file header is a hash of the JavaScriptCore framework. When Bun loads bytecode:
1. It extracts the cache version from the `.jsc` file
2. It computes the current JavaScriptCore version
3. If they don't match, the bytecode is **silently rejected**
4. Bun falls back to parsing the `.js` source code
Your application still runs - you just lose the performance optimization.
**Graceful degradation**:
This design means bytecode caching "fails open" - if anything goes wrong (version mismatch, corrupted file, missing file), your code still runs normally. You might see slower startup, but you won't see errors.
## Unlinked vs. linked bytecode
JavaScriptCore makes a crucial distinction between "unlinked" and "linked" bytecode. This separation is what makes bytecode caching possible:
### Unlinked bytecode (what's cached)
The bytecode saved in `.jsc` files is **unlinked bytecode**. It contains:
- The compiled bytecode instructions
- Structural information about the code
- Constants and identifiers
- Control flow information
But it **doesn't** contain:
- Pointers to actual runtime objects
- JIT-compiled machine code
- Profiling data from previous runs
- Call link information (which functions call which)
Unlinked bytecode is **immutable and shareable**. Multiple executions of the same code can all reference the same unlinked bytecode.
### Linked bytecode (runtime execution)
When Bun runs bytecode, it "links" it - creating a runtime wrapper that adds:
- **Call link information**: As your code runs, the engine learns which functions call which and optimizes those call sites.
- **Profiling data**: The engine tracks how many times each instruction executes, what types of values flow through the code, array access patterns, etc.
- **JIT compilation state**: References to baseline JIT or optimizing JIT (DFG/FTL) compiled versions of hot code.
- **Runtime objects**: Pointers to actual JavaScript objects, prototypes, scopes, etc.
This linked representation is created fresh every time you run your code. This allows:
1. **Caching the expensive work** (parsing and compilation to unlinked bytecode)
2. **Still collecting runtime profiling data** to guide optimizations
3. **Still applying JIT optimizations** based on actual execution patterns
Bytecode caching moves expensive work (parsing and compiling to bytecode) from runtime to build time. For applications that start frequently, this can halve your startup time at the cost of larger files on disk.
For production CLIs and serverless deployments, the combination of `--bytecode --minify --sourcemap` gives you the best performance while maintaining debuggability.

View File

@@ -1,3 +1,8 @@
---
title: CSS
description: Bun's bundler has built-in support for CSS with modern features
---
Bun's bundler has built-in support for CSS with the following features:
- Transpiling modern/future features to work on all browsers (including vendor prefixing)
@@ -9,11 +14,11 @@ Bun's bundler has built-in support for CSS with the following features:
Bun's CSS bundler lets you use modern/future CSS features without having to worry about browser compatibility — all thanks to its transpiling and vendor prefixing features which are enabled by default.
Bun's CSS parser and bundler is a direct Rust → Zig port of [LightningCSS](https://lightningcss.dev/), with a bundling approach inspired by esbuild. The transpiler converts modern CSS syntax into backwards-compatible equivalents that work across browsers.
Bun's CSS parser and bundler is a direct Rust → Zig port of LightningCSS, with a bundling approach inspired by esbuild. The transpiler converts modern CSS syntax into backwards-compatible equivalents that work across browsers.
A huge thanks goes to the amazing work from the authors of [LightningCSS](https://lightningcss.dev/) and [esbuild](https://esbuild.github.io/).
<Note>A huge thanks goes to the amazing work from the authors of LightningCSS and esbuild.</Note>
### Browser Compatibility
## Browser Compatibility
By default, Bun's CSS bundler targets the following browsers:
@@ -23,13 +28,13 @@ By default, Bun's CSS bundler targets the following browsers:
- Chrome 87+
- Safari 14+
### Syntax Lowering
## Syntax Lowering
#### Nesting
### Nesting
The CSS Nesting specification allows you to write more concise and intuitive stylesheets by nesting selectors inside one another. Instead of repeating parent selectors across your CSS file, you can write child styles directly within their parent blocks.
```css
```css title="styles.css" icon="file-code"
/* With nesting */
.card {
background: white;
@@ -48,7 +53,7 @@ The CSS Nesting specification allows you to write more concise and intuitive sty
Bun's CSS bundler automatically converts this nested syntax into traditional flat CSS that works in all browsers:
```css
```css title="styles.css" icon="file-code"
/* Compiled output */
.card {
background: white;
@@ -67,7 +72,7 @@ Bun's CSS bundler automatically converts this nested syntax into traditional fla
You can also nest media queries and other at-rules inside selectors, eliminating the need to repeat selector patterns:
```css
```css title="styles.css" icon="file-code"
.responsive-element {
display: block;
@@ -79,7 +84,7 @@ You can also nest media queries and other at-rules inside selectors, eliminating
This compiles to:
```css
```css title="styles.css" icon="file-code"
.responsive-element {
display: block;
}
@@ -91,11 +96,11 @@ This compiles to:
}
```
#### Color mix
### Color mix
The `color-mix()` function gives you an easy way to blend two colors together according to a specified ratio in a chosen color space. This powerful feature lets you create color variations without manually calculating the resulting values.
```css
```css title="styles.css" icon="file-code"
.button {
/* Mix blue and red in the RGB color space with a 30/70 proportion */
background-color: color-mix(in srgb, blue 30%, red);
@@ -109,7 +114,7 @@ The `color-mix()` function gives you an easy way to blend two colors together ac
Bun's CSS bundler evaluates these color mixes at build time when all color values are known (not CSS variables), generating static color values that work in all browsers:
```css
```css title="styles.css" icon="file-code"
.button {
/* Computed to the exact resulting color */
background-color: #b31a1a;
@@ -122,11 +127,11 @@ Bun's CSS bundler evaluates these color mixes at build time when all color value
This feature is particularly useful for creating color systems with programmatically derived shades, tints, and accents without needing preprocessors or custom tooling.
#### Relative colors
### Relative colors
CSS now allows you to modify individual components of a color using relative color syntax. This powerful feature lets you create color variations by adjusting specific attributes like lightness, saturation, or individual channels without having to recalculate the entire color.
```css
```css title="styles.css" icon="file-code"
.theme-color {
/* Start with a base color and increase lightness by 15% */
--accent: lch(from purple calc(l + 15%) c h);
@@ -147,27 +152,23 @@ Bun's CSS bundler computes these relative color modifications at build time (whe
This approach is extremely useful for theme generation, creating accessible color variants, or building color scales based on mathematical relationships instead of hard-coding each value.
#### LAB colors
### LAB colors
Modern CSS supports perceptually uniform color spaces like LAB, LCH, OKLAB, and OKLCH that offer significant advantages over traditional RGB. These color spaces can represent colors outside the standard RGB gamut, resulting in more vibrant and visually consistent designs.
```css
```css title="styles.css" icon="file-code"
.vibrant-element {
/* A vibrant red that exceeds sRGB gamut boundaries */
color: lab(55% 78 35);
/* A smooth gradient using perceptual color space */
background: linear-gradient(
to right,
oklch(65% 0.25 10deg),
oklch(65% 0.25 250deg)
);
background: linear-gradient(to right, oklch(65% 0.25 10deg), oklch(65% 0.25 250deg));
}
```
Bun's CSS bundler automatically converts these advanced color formats to backwards-compatible alternatives for browsers that don't yet support them:
```css
```css title="styles.css" icon="file-code"
.vibrant-element {
/* Fallback to closest RGB approximation */
color: #ff0f52;
@@ -177,21 +178,17 @@ Bun's CSS bundler automatically converts these advanced color formats to backwar
color: lab(55% 78 35);
background: linear-gradient(to right, #cd4e15, #3887ab);
background: linear-gradient(
to right,
oklch(65% 0.25 10deg),
oklch(65% 0.25 250deg)
);
background: linear-gradient(to right, oklch(65% 0.25 10deg), oklch(65% 0.25 250deg));
}
```
This layered approach ensures optimal color rendering across all browsers while allowing you to use the latest color technologies in your designs.
#### Color function
### Color function
The `color()` function provides a standardized way to specify colors in various predefined color spaces, expanding your design options beyond the traditional RGB space. This allows you to access wider color gamuts and create more vibrant designs.
```css
```css title="styles.css" icon="file-code"
.vivid-element {
/* Using the Display P3 color space for wider gamut colors */
color: color(display-p3 1 0.1 0.3);
@@ -203,7 +200,7 @@ The `color()` function provides a standardized way to specify colors in various
For browsers that don't support these advanced color functions yet, Bun's CSS bundler provides appropriate RGB fallbacks:
```css
```css title="styles.css" icon="file-code"
.vivid-element {
/* RGB fallback first for maximum compatibility */
color: #fa1a4c;
@@ -217,11 +214,11 @@ For browsers that don't support these advanced color functions yet, Bun's CSS bu
This functionality lets you use modern color spaces immediately while ensuring your designs remain functional across all browsers, with optimal colors displayed in supporting browsers and reasonable approximations elsewhere.
#### HWB colors
### HWB colors
The HWB (Hue, Whiteness, Blackness) color model provides an intuitive way to express colors based on how much white or black is mixed with a pure hue. Many designers find this approach more natural for creating color variations compared to manipulating RGB or HSL values.
```css
```css title="styles.css" icon="file-code"
.easy-theming {
/* Pure cyan with no white or black added */
--primary: hwb(180 0% 0%);
@@ -239,7 +236,7 @@ The HWB (Hue, Whiteness, Blackness) color model provides an intuitive way to exp
Bun's CSS bundler automatically converts HWB colors to RGB for compatibility with all browsers:
```css
```css title="styles.css" icon="file-code"
.easy-theming {
--primary: #00ffff;
--primary-light: #33ffff;
@@ -250,11 +247,11 @@ Bun's CSS bundler automatically converts HWB colors to RGB for compatibility wit
The HWB model makes it particularly easy to create systematic color variations for design systems, providing a more intuitive approach to creating consistent tints and shades than working directly with RGB or HSL values.
#### Color notation
### Color notation
Modern CSS has introduced more intuitive and concise ways to express colors. Space-separated color syntax eliminates the need for commas in RGB and HSL values, while hex colors with alpha channels provide a compact way to specify transparency.
```css
```css title="styles.css" icon="file-code"
.modern-styling {
/* Space-separated RGB notation (no commas) */
color: rgb(50 100 200);
@@ -272,7 +269,7 @@ Modern CSS has introduced more intuitive and concise ways to express colors. Spa
Bun's CSS bundler automatically converts these modern color formats to ensure compatibility with older browsers:
```css
```css title="styles.css" icon="file-code"
.modern-styling {
/* Converted to comma format for older browsers */
color: rgb(50, 100, 200);
@@ -289,11 +286,11 @@ Bun's CSS bundler automatically converts these modern color formats to ensure co
This conversion process lets you write cleaner, more modern CSS while ensuring your styles work correctly across all browsers.
#### light-dark() color function
### light-dark() color function
The `light-dark()` function provides an elegant solution for implementing color schemes that respect the user's system preference without requiring complex media queries. This function accepts two color values and automatically selects the appropriate one based on the current color scheme context.
```css
```css title="styles.css" icon="file-code"
:root {
/* Define color scheme support */
color-scheme: light dark;
@@ -318,7 +315,7 @@ The `light-dark()` function provides an elegant solution for implementing color
For browsers that don't support this feature yet, Bun's CSS bundler converts it to use CSS variables with proper fallbacks:
```css
```css title="styles.css" icon="file-code"
:root {
--lightningcss-light: initial;
--lightningcss-dark: ;
@@ -345,21 +342,19 @@ For browsers that don't support this feature yet, Bun's CSS bundler converts it
}
.themed-component {
background-color: var(--lightningcss-light, #ffffff)
var(--lightningcss-dark, #121212);
background-color: var(--lightningcss-light, #ffffff) var(--lightningcss-dark, #121212);
color: var(--lightningcss-light, #333333) var(--lightningcss-dark, #eeeeee);
border-color: var(--lightningcss-light, #dddddd)
var(--lightningcss-dark, #555555);
border-color: var(--lightningcss-light, #dddddd) var(--lightningcss-dark, #555555);
}
```
This approach gives you a clean way to handle light and dark themes without duplicating styles or writing complex media queries, while maintaining compatibility with browsers that don't yet support the feature natively.
#### Logical properties
### Logical properties
CSS logical properties let you define layout, spacing, and sizing relative to the document's writing mode and text direction rather than physical screen directions. This is crucial for creating truly international layouts that automatically adapt to different writing systems.
```css
```css title="styles.css" icon="file-code"
.multilingual-component {
/* Margin that adapts to writing direction */
margin-inline-start: 1rem;
@@ -378,7 +373,7 @@ CSS logical properties let you define layout, spacing, and sizing relative to th
For browsers that don't fully support logical properties, Bun's CSS bundler compiles them to physical properties with appropriate directional adjustments:
```css
```css title="styles.css" icon="file-code"
/* For left-to-right languages */
.multilingual-component:dir(ltr) {
margin-left: 1rem;
@@ -402,11 +397,11 @@ For browsers that don't fully support logical properties, Bun's CSS bundler comp
If the `:dir()` selector isn't supported, additional fallbacks are automatically generated to ensure your layouts work properly across all browsers and writing systems. This makes creating internationalized designs much simpler while maintaining compatibility with older browsers.
#### :dir() selector
### :dir() selector
The `:dir()` pseudo-class selector allows you to style elements based on their text direction (RTL or LTR), providing a powerful way to create direction-aware designs without JavaScript. This selector matches elements based on their directionality as determined by the document or explicit direction attributes.
```css
```css title="styles.css" icon="file-code"
/* Apply different styles based on text direction */
.nav-arrow:dir(ltr) {
transform: rotate(0deg);
@@ -428,7 +423,7 @@ The `:dir()` pseudo-class selector allows you to style elements based on their t
For browsers that don't support the `:dir()` selector yet, Bun's CSS bundler converts it to the more widely supported `:lang()` selector with appropriate language mappings:
```css
```css title="styles.css" icon="file-code"
/* Converted to use language-based selectors as fallback */
.nav-arrow:lang(en, fr, de, es, it, pt, nl) {
transform: rotate(0deg);
@@ -449,11 +444,11 @@ For browsers that don't support the `:dir()` selector yet, Bun's CSS bundler con
This conversion lets you write direction-aware CSS that works reliably across browsers, even those that don't yet support the `:dir()` selector natively. If multiple arguments to `:lang()` aren't supported, further fallbacks are automatically provided.
#### :lang() selector
### :lang() selector
The `:lang()` pseudo-class selector allows you to target elements based on the language they're in, making it easy to apply language-specific styling. Modern CSS allows the `:lang()` selector to accept multiple language codes, letting you group language-specific rules more efficiently.
```css
```css title="styles.css" icon="file-code"
/* Typography adjustments for CJK languages */
:lang(zh, ja, ko) {
line-height: 1.8;
@@ -472,7 +467,7 @@ blockquote:lang(de, nl, da, sv) {
For browsers that don't support multiple arguments in the `:lang()` selector, Bun's CSS bundler converts this syntax to use the `:is()` selector to maintain the same behavior:
```css
```css title="styles.css" icon="file-code"
/* Multiple languages grouped with :is() for better browser support */
:is(:lang(zh), :lang(ja), :lang(ko)) {
line-height: 1.8;
@@ -490,11 +485,11 @@ blockquote:is(:lang(de), :lang(nl), :lang(da), :lang(sv)) {
If needed, Bun can provide additional fallbacks for `:is()` as well, ensuring your language-specific styles work across all browsers. This approach simplifies creating internationalized designs with distinct typographic and styling rules for different language groups.
#### :is() selector
### :is() selector
The `:is()` pseudo-class function (formerly `:matches()`) allows you to create more concise and readable selectors by grouping multiple selectors together. It accepts a selector list as its argument and matches if any of the selectors in that list match, significantly reducing repetition in your CSS.
```css
```css title="styles.css" icon="file-code"
/* Instead of writing these separately */
/*
.article h1,
@@ -547,13 +542,17 @@ For browsers that don't support `:is()`, Bun's CSS bundler provides fallbacks us
}
```
It's worth noting that the vendor-prefixed versions have some limitations compared to the standardized `:is()` selector, particularly with complex selectors. Bun handles these limitations intelligently, only using prefixed versions when they'll work correctly.
<Warning>
The vendor-prefixed versions have some limitations compared to the standardized `:is()` selector, particularly with
complex selectors. Bun handles these limitations intelligently, only using prefixed versions when they'll work
correctly.
</Warning>
#### :not() selector
### :not() selector
The `:not()` pseudo-class allows you to exclude elements that match a specific selector. The modern version of this selector accepts multiple arguments, letting you exclude multiple patterns with a single, concise selector.
```css
```css title="styles.css" icon="file-code"
/* Select all buttons except primary and secondary variants */
button:not(.primary, .secondary) {
background-color: #f5f5f5;
@@ -568,7 +567,7 @@ h2:not(.sidebar *, footer *) {
For browsers that don't support multiple arguments in `:not()`, Bun's CSS bundler converts this syntax to a more compatible form while preserving the same behavior:
```css
```css title="styles.css" icon="file-code"
/* Converted to use :not with :is() for compatibility */
button:not(:is(.primary, .secondary)) {
background-color: #f5f5f5;
@@ -582,7 +581,7 @@ h2:not(:is(.sidebar *, footer *)) {
And if `:is()` isn't supported, Bun can generate further fallbacks:
```css
```css title="styles.css" icon="file-code"
/* Even more fallbacks for maximum compatibility */
button:not(:-webkit-any(.primary, .secondary)) {
background-color: #f5f5f5;
@@ -602,11 +601,11 @@ button:not(:is(.primary, .secondary)) {
This conversion ensures your negative selectors work correctly across all browsers while maintaining the correct specificity and behavior of the original selector.
#### Math functions
### Math functions
CSS now includes a rich set of mathematical functions that let you perform complex calculations directly in your stylesheets. These include standard math functions (`round()`, `mod()`, `rem()`, `abs()`, `sign()`), trigonometric functions (`sin()`, `cos()`, `tan()`, `asin()`, `acos()`, `atan()`, `atan2()`), and exponential functions (`pow()`, `sqrt()`, `exp()`, `log()`, `hypot()`).
```css
```css title="styles.css" icon="file-code"
.dynamic-sizing {
/* Clamp a value between minimum and maximum */
width: clamp(200px, 50%, 800px);
@@ -625,7 +624,7 @@ CSS now includes a rich set of mathematical functions that let you perform compl
Bun's CSS bundler evaluates these mathematical expressions at build time when all values are known constants (not variables), resulting in optimized output:
```css
```css title="styles.css" icon="file-code"
.dynamic-sizing {
width: clamp(200px, 50%, 800px);
padding: 15px;
@@ -637,11 +636,11 @@ Bun's CSS bundler evaluates these mathematical expressions at build time when al
This approach lets you write more expressive and maintainable CSS with meaningful mathematical relationships, which then gets compiled to optimized values for maximum browser compatibility and performance.
#### Media query ranges
### Media query ranges
Modern CSS supports intuitive range syntax for media queries, allowing you to specify breakpoints using comparison operators like `<`, `>`, `<=`, and `>=` instead of the more verbose `min-` and `max-` prefixes. This syntax is more readable and matches how we normally think about values and ranges.
```css
```css title="styles.css" icon="file-code"
/* Modern syntax with comparison operators */
@media (width >= 768px) {
.container {
@@ -666,7 +665,7 @@ Modern CSS supports intuitive range syntax for media queries, allowing you to sp
Bun's CSS bundler converts these modern range queries to traditional media query syntax for compatibility with all browsers:
```css
```css title="styles.css" icon="file-code"
/* Converted to traditional min/max syntax */
@media (min-width: 768px) {
.container {
@@ -689,11 +688,11 @@ Bun's CSS bundler converts these modern range queries to traditional media query
This lets you write more intuitive and mathematical media queries while ensuring your stylesheets work correctly across all browsers, including those that don't support the modern range syntax.
#### Shorthands
### Shorthands
CSS has introduced several modern shorthand properties that improve code readability and maintainability. Bun's CSS bundler ensures these convenient shorthands work on all browsers by converting them to their longhand equivalents when needed.
```css
```css title="styles.css" icon="file-code"
/* Alignment shorthands */
.flex-container {
/* Shorthand for align-items and justify-items */
@@ -729,7 +728,7 @@ CSS has introduced several modern shorthand properties that improve code readabi
For browsers that don't support these modern shorthands, Bun converts them to their component longhand properties:
```css
```css title="styles.css" icon="file-code"
.flex-container {
/* Expanded alignment properties */
align-items: center;
@@ -766,11 +765,11 @@ For browsers that don't support these modern shorthands, Bun converts them to th
This conversion ensures your stylesheets remain clean and maintainable while providing the broadest possible browser compatibility.
#### Double position gradients
### Double position gradients
The double position gradient syntax is a modern CSS feature that allows you to create hard color stops in gradients by specifying the same color at two adjacent positions. This creates a sharp transition rather than a smooth fade, which is useful for creating stripes, color bands, and other multi-color designs.
```css
```css title="styles.css" icon="file-code"
.striped-background {
/* Creates a sharp transition from green to red at 30%-40% */
background: linear-gradient(
@@ -799,7 +798,7 @@ The double position gradient syntax is a modern CSS feature that allows you to c
For browsers that don't support this syntax, Bun's CSS bundler automatically converts it to the traditional format by duplicating color stops:
```css
```css title="styles.css" icon="file-code"
.striped-background {
background: linear-gradient(
to right,
@@ -830,11 +829,11 @@ For browsers that don't support this syntax, Bun's CSS bundler automatically con
This conversion lets you use the cleaner double position syntax in your source code while ensuring gradients display correctly in all browsers.
#### system-ui font
### system-ui font
The `system-ui` generic font family lets you use the device's native UI font, creating interfaces that feel more integrated with the operating system. This provides a more native look and feel without having to specify different font stacks for each platform.
```css
```css title="styles.css" icon="file-code"
.native-interface {
/* Use the system's default UI font */
font-family: system-ui;
@@ -848,7 +847,7 @@ The `system-ui` generic font family lets you use the device's native UI font, cr
For browsers that don't support `system-ui`, Bun's CSS bundler automatically expands it to a comprehensive cross-platform font stack:
```css
```css title="styles.css" icon="file-code"
.native-interface {
/* Expanded to support all major platforms */
font-family:
@@ -883,7 +882,7 @@ This approach gives you the simplicity of writing just `system-ui` in your sourc
## CSS Modules
Bun's bundler also supports bundling [CSS modules](https://css-tricks.com/css-modules-part-1-need/) in addition to [regular CSS](/docs/bundler/css) with support for the following features:
Bun's bundler also supports bundling CSS modules in addition to regular CSS with support for the following features:
- Automatically detecting CSS module files (`.module.css`) with zero configuration
- Composition (`composes` property)
@@ -894,17 +893,17 @@ A CSS module is a CSS file (with the `.module.css` extension) where are all clas
Under the hood, Bun's bundler transforms locally scoped class names into unique identifiers.
## Getting started
### Getting started
Create a CSS file with the `.module.css` extension:
```css
/* styles.module.css */
```css title="styles.module.css" icon="file-code"
.button {
color: red;
}
```
/* other-styles.module.css */
```css title="other-styles.module.css" icon="file-code"
.button {
color: blue;
}
@@ -912,7 +911,7 @@ Create a CSS file with the `.module.css` extension:
You can then import this file, for example into a TSX file:
```tsx
```tsx title="app.tsx" icon="/icons/typescript.svg"
import styles from "./styles.module.css";
import otherStyles from "./other-styles.module.css";
@@ -926,10 +925,9 @@ export default function App() {
}
```
The `styles` object from importing the CSS module file will be an object with all class names as keys and
their unique identifiers as values:
The styles object from importing the CSS module file will be an object with all class names as keys and their unique identifiers as values:
```tsx
```ts title="app.tsx" icon="/icons/typescript.svg"
import styles from "./styles.module.css";
import otherStyles from "./other-styles.module.css";
@@ -939,7 +937,7 @@ console.log(otherStyles);
This will output:
```ts
```ts title="app.tsx" icon="/icons/typescript.svg"
{
button: "button_123";
}
@@ -953,12 +951,11 @@ As you can see, the class names are unique to each file, avoiding any collisions
### Composition
CSS modules allow you to _compose_ class selectors together. This lets you reuse style rules across multiple classes.
CSS modules allow you to compose class selectors together. This lets you reuse style rules across multiple classes.
For example:
```css
/* styles.module.css */
```css title="styles.module.css" icon="file-code"
.button {
composes: background;
color: red;
@@ -971,7 +968,7 @@ For example:
Would be the same as writing:
```css
```css title="styles.module.css" icon="file-code"
.button {
background-color: blue;
color: red;
@@ -982,13 +979,14 @@ Would be the same as writing:
}
```
{% callout %}
There are a couple rules to keep in mind when using `composes`:
- A `composes` property must come before any regular CSS properties or declarations
- You can only use `composes` on a **simple selector with a single class name**:
<Info>
**Composition Rules:** - A `composes` property must come before any regular CSS properties or declarations - You can
only use `composes` on a simple selector with a single class name
</Info>
```css
```css title="styles.module.css" icon="file-code"
#button {
/* Invalid! `#button` is not a class selector */
composes: background;
@@ -1001,28 +999,26 @@ There are a couple rules to keep in mind when using `composes`:
}
```
{% /callout %}
### Composing from a separate CSS module file
You can also compose from a separate CSS module file:
```css
/* background.module.css */
```css title="background.module.css" icon="file-code"
.background {
background-color: blue;
}
```
/* styles.module.css */
```css title="styles.module.css" icon="file-code"
.button {
composes: background from "./background.module.css";
color: red;
}
```
{% callout %}
<Warning>
When composing classes from separate files, be sure that they do not contain the same properties.
The CSS module spec says that composing classes from separate files with conflicting properties is
undefined behavior, meaning that the output may differ and be unreliable.
{% /callout %}
The CSS module spec says that composing classes from separate files with conflicting properties is undefined behavior, meaning that the output may differ and be unreliable.
</Warning>

View File

@@ -1,145 +0,0 @@
# CSS Modules
Bun's bundler also supports bundling [CSS modules](https://css-tricks.com/css-modules-part-1-need/) in addition to [regular CSS](/docs/bundler/css) with support for the following features:
- Automatically detecting CSS module files (`.module.css`) with zero configuration
- Composition (`composes` property)
- Importing CSS modules into JSX/TSX
- Warnings/errors for invalid usages of CSS modules
A CSS module is a CSS file (with the `.module.css` extension) where are all class names and animations are scoped to the file. This helps you avoid class name collisions as CSS declarations are globally scoped by default.
Under the hood, Bun's bundler transforms locally scoped class names into unique identifiers.
## Getting started
Create a CSS file with the `.module.css` extension:
```css
/* styles.module.css */
.button {
color: red;
}
/* other-styles.module.css */
.button {
color: blue;
}
```
You can then import this file, for example into a TSX file:
```tsx
import styles from "./styles.module.css";
import otherStyles from "./other-styles.module.css";
export default function App() {
return (
<>
<button className={styles.button}>Red button!</button>
<button className={otherStyles.button}>Blue button!</button>
</>
);
}
```
The `styles` object from importing the CSS module file will be an object with all class names as keys and
their unique identifiers as values:
```tsx
import styles from "./styles.module.css";
import otherStyles from "./other-styles.module.css";
console.log(styles);
console.log(otherStyles);
```
This will output:
```ts
{
button: "button_123";
}
{
button: "button_456";
}
```
As you can see, the class names are unique to each file, avoiding any collisions!
### Composition
CSS modules allow you to _compose_ class selectors together. This lets you reuse style rules across multiple classes.
For example:
```css
/* styles.module.css */
.button {
composes: background;
color: red;
}
.background {
background-color: blue;
}
```
Would be the same as writing:
```css
.button {
background-color: blue;
color: red;
}
.background {
background-color: blue;
}
```
{% callout %}
There are a couple rules to keep in mind when using `composes`:
- A `composes` property must come before any regular CSS properties or declarations
- You can only use `composes` on a **simple selector with a single class name**:
```css
#button {
/* Invalid! `#button` is not a class selector */
composes: background;
}
.button,
.button-secondary {
/* Invalid! `.button, .button-secondary` is not a simple selector */
composes: background;
}
```
{% /callout %}
### Composing from a separate CSS module file
You can also compose from a separate CSS module file:
```css
/* background.module.css */
.background {
background-color: blue;
}
/* styles.module.css */
.button {
composes: background from "./background.module.css";
color: red;
}
```
{% callout %}
When composing classes from separate files, be sure that they do not contain the same properties.
The CSS module spec says that composing classes from separate files with conflicting properties is
undefined behavior, meaning that the output may differ and be unreliable.
{% /callout %}

253
docs/bundler/esbuild.mdx Normal file
View File

@@ -0,0 +1,253 @@
---
title: esbuild
description: Migration guide from esbuild to Bun's bundler
---
Bun's bundler API is inspired heavily by esbuild. Migrating to Bun's bundler from esbuild should be relatively painless. This guide will briefly explain why you might consider migrating to Bun's bundler and provide a side-by-side API comparison reference for those who are already familiar with esbuild's API.
There are a few behavioral differences to note.
<Note>
**Bundling by default.** Unlike esbuild, Bun always bundles by default. This is why the `--bundle` flag isn't
necessary in the Bun example. To transpile each file individually, use `Bun.Transpiler`.
</Note>
<Note>
**It's just a bundler.** Unlike esbuild, Bun's bundler does not include a built-in development server or file watcher.
It's just a bundler. The bundler is intended for use in conjunction with `Bun.serve` and other runtime APIs to achieve
the same effect. As such, all options relating to HTTP/file watching are not applicable.
</Note>
## Performance
With a performance-minded API coupled with the extensively optimized Zig-based JS/TS parser, Bun's bundler is 1.75x faster than esbuild on esbuild's three.js benchmark.
<Info>Bundling 10 copies of three.js from scratch, with sourcemaps and minification</Info>
## CLI API
Bun and esbuild both provide a command-line interface.
```bash terminal icon="terminal"
# esbuild
esbuild <entrypoint> --outdir=out --bundle
# bun
bun build <entrypoint> --outdir=out
```
In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Other flags like `--outdir <path>` do accept an argument; these flags can be written as `--outdir out` or `--outdir=out`. Some flags like `--define` can be specified several times: `--define foo=bar --define bar=baz`.
| esbuild | bun build | Notes |
| ---------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--bundle` | n/a | Bun always bundles, use `--no-bundle` to disable this behavior. |
| `--define:K=V` | `--define K=V` | Small syntax difference; no colon.<br/>`esbuild --define:foo=bar`<br/>`bun build --define foo=bar` |
| `--external:<pkg>` | `--external <pkg>` | Small syntax difference; no colon.<br/>`esbuild --external:react`<br/>`bun build --external react` |
| `--format` | `--format` | Bun supports `"esm"` and `"cjs"` currently, but more module formats are planned. esbuild defaults to `"iife"`. |
| `--loader:.ext=loader` | `--loader .ext:loader` | Bun supports a different set of built-in loaders than esbuild; see Bundler > Loaders for a complete reference. The esbuild loaders `dataurl`, `binary`, `base64`, `copy`, and `empty` are not yet implemented.<br/><br/>The syntax for `--loader` is slightly different.<br/>`esbuild app.ts --bundle --loader:.svg=text`<br/>`bun build app.ts --loader .svg:text` |
| `--minify` | `--minify` | No differences |
| `--outdir` | `--outdir` | No differences |
| `--outfile` | `--outfile` | No differences |
| `--packages` | `--packages` | No differences |
| `--platform` | `--target` | Renamed to `--target` for consistency with tsconfig. Does not support `neutral`. |
| `--serve` | n/a | Not applicable |
| `--sourcemap` | `--sourcemap` | No differences |
| `--splitting` | `--splitting` | No differences |
| `--target` | n/a | Not supported. Bun's bundler performs no syntactic down-leveling at this time. |
| `--watch` | `--watch` | No differences |
| `--allow-overwrite` | n/a | Overwriting is never allowed |
| `--analyze` | n/a | Not supported |
| `--asset-names` | `--asset-naming` | Renamed for consistency with naming in JS API |
| `--banner` | `--banner` | Only applies to js bundles |
| `--footer` | `--footer` | Only applies to js bundles |
| `--certfile` | n/a | Not applicable |
| `--charset=utf8` | n/a | Not supported |
| `--chunk-names` | `--chunk-naming` | Renamed for consistency with naming in JS API |
| `--color` | n/a | Always enabled |
| `--drop` | `--drop` | |
| `--entry-names` | `--entry-naming` | Renamed for consistency with naming in JS API |
| `--global-name` | n/a | Not applicable, Bun does not support `iife` output at this time |
| `--ignore-annotations` | `--ignore-dce-annotations` | |
| `--inject` | n/a | Not supported |
| `--jsx` | `--jsx-runtime <runtime>` | Supports `"automatic"` (uses jsx transform) and `"classic"` (uses `React.createElement`) |
| `--jsx-dev` | n/a | Bun reads `compilerOptions.jsx` from `tsconfig.json` to determine a default. If `compilerOptions.jsx` is `"react-jsx"`, or if `NODE_ENV=production`, Bun will use the jsx transform. Otherwise, it uses `jsxDEV`. The bundler does not support `preserve`. |
| `--jsx-factory` | `--jsx-factory` | |
| `--jsx-fragment` | `--jsx-fragment` | |
| `--jsx-import-source` | `--jsx-import-source` | |
| `--jsx-side-effects` | n/a | JSX is always assumed to be side-effect-free |
| `--keep-names` | n/a | Not supported |
| `--keyfile` | n/a | Not applicable |
| `--legal-comments` | n/a | Not supported |
| `--log-level` | n/a | Not supported. This can be set in `bunfig.toml` as `logLevel`. |
| `--log-limit` | n/a | Not supported |
| `--log-override:X=Y` | n/a | Not supported |
| `--main-fields` | n/a | Not supported |
| `--mangle-cache` | n/a | Not supported |
| `--mangle-props` | n/a | Not supported |
| `--mangle-quoted` | n/a | Not supported |
| `--metafile` | n/a | Not supported |
| `--minify-whitespace` | `--minify-whitespace` | |
| `--minify-identifiers` | `--minify-identifiers` | |
| `--minify-syntax` | `--minify-syntax` | |
| `--out-extension` | n/a | Not supported |
| `--outbase` | `--root` | |
| `--preserve-symlinks` | n/a | Not supported |
| `--public-path` | `--public-path` | |
| `--pure` | n/a | Not supported |
| `--reserve-props` | n/a | Not supported |
| `--resolve-extensions` | n/a | Not supported |
| `--servedir` | n/a | Not applicable |
| `--source-root` | n/a | Not supported |
| `--sourcefile` | n/a | Not supported. Bun does not support stdin input yet. |
| `--sourcemap` | `--sourcemap` | No differences |
| `--sources-content` | n/a | Not supported |
| `--supported` | n/a | Not supported |
| `--tree-shaking` | n/a | Always true |
| `--tsconfig` | `--tsconfig-override` | |
| `--version` | n/a | Run `bun --version` to see the version of Bun. |
## JavaScript API
| esbuild.build() | Bun.build() | Notes |
| ------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `absWorkingDir` | n/a | Always set to `process.cwd()` |
| `alias` | n/a | Not supported |
| `allowOverwrite` | n/a | Always false |
| `assetNames` | `naming.asset` | Uses same templating syntax as esbuild, but `[ext]` must be included explicitly.<br/><br/>`ts<br/>Bun.build({<br/> entrypoints: ["./index.tsx"],<br/> naming: {<br/> asset: "[name].[ext]",<br/> },<br/>});<br/>` |
| `banner` | n/a | Not supported |
| `bundle` | n/a | Always true. Use `Bun.Transpiler` to transpile without bundling. |
| `charset` | n/a | Not supported |
| `chunkNames` | `naming.chunk` | Uses same templating syntax as esbuild, but `[ext]` must be included explicitly.<br/><br/>`ts<br/>Bun.build({<br/> entrypoints: ["./index.tsx"],<br/> naming: {<br/> chunk: "[name].[ext]",<br/> },<br/>});<br/>` |
| `color` | n/a | Bun returns logs in the `logs` property of the build result. |
| `conditions` | n/a | Not supported. Export conditions priority is determined by `target`. |
| `define` | `define` | |
| `drop` | n/a | Not supported |
| `entryNames` | `naming` or `naming.entry` | Bun supports a `naming` key that can either be a string or an object. Uses same templating syntax as esbuild, but `[ext]` must be included explicitly.<br/><br/>`ts<br/>Bun.build({<br/> entrypoints: ["./index.tsx"],<br/> // when string, this is equivalent to entryNames<br/> naming: "[name].[ext]",<br/><br/> // granular naming options<br/> naming: {<br/> entry: "[name].[ext]",<br/> asset: "[name].[ext]",<br/> chunk: "[name].[ext]",<br/> },<br/>});<br/>` |
| `entryPoints` | `entrypoints` | Capitalization difference |
| `external` | `external` | No differences |
| `footer` | n/a | Not supported |
| `format` | `format` | Only supports `"esm"` currently. Support for `"cjs"` and `"iife"` is planned. |
| `globalName` | n/a | Not supported |
| `ignoreAnnotations` | n/a | Not supported |
| `inject` | n/a | Not supported |
| `jsx` | `jsx` | Not supported in JS API, configure in `tsconfig.json` |
| `jsxDev` | `jsxDev` | Not supported in JS API, configure in `tsconfig.json` |
| `jsxFactory` | `jsxFactory` | Not supported in JS API, configure in `tsconfig.json` |
| `jsxFragment` | `jsxFragment` | Not supported in JS API, configure in `tsconfig.json` |
| `jsxImportSource` | `jsxImportSource` | Not supported in JS API, configure in `tsconfig.json` |
| `jsxSideEffects` | `jsxSideEffects` | Not supported in JS API, configure in `tsconfig.json` |
| `keepNames` | n/a | Not supported |
| `legalComments` | n/a | Not supported |
| `loader` | `loader` | Bun supports a different set of built-in loaders than esbuild; see Bundler > Loaders for a complete reference. The esbuild loaders `dataurl`, `binary`, `base64`, `copy`, and `empty` are not yet implemented. |
| `logLevel` | n/a | Not supported |
| `logLimit` | n/a | Not supported |
| `logOverride` | n/a | Not supported |
| `mainFields` | n/a | Not supported |
| `mangleCache` | n/a | Not supported |
| `mangleProps` | n/a | Not supported |
| `mangleQuoted` | n/a | Not supported |
| `metafile` | n/a | Not supported |
| `minify` | `minify` | In Bun, `minify` can be a boolean or an object.<br/><br/>`ts<br/>await Bun.build({<br/> entrypoints: ['./index.tsx'],<br/> // enable all minification<br/> minify: true<br/><br/> // granular options<br/> minify: {<br/> identifiers: true,<br/> syntax: true,<br/> whitespace: true<br/> }<br/>})<br/>` |
| `minifyIdentifiers` | `minify.identifiers` | See `minify` |
| `minifySyntax` | `minify.syntax` | See `minify` |
| `minifyWhitespace` | `minify.whitespace` | See `minify` |
| `nodePaths` | n/a | Not supported |
| `outExtension` | n/a | Not supported |
| `outbase` | `root` | Different name |
| `outdir` | `outdir` | No differences |
| `outfile` | `outfile` | No differences |
| `packages` | n/a | Not supported, use `external` |
| `platform` | `target` | Supports `"bun"`, `"node"` and `"browser"` (the default). Does not support `"neutral"`. |
| `plugins` | `plugins` | Bun's plugin API is a subset of esbuild's. Some esbuild plugins will work out of the box with Bun. |
| `preserveSymlinks` | n/a | Not supported |
| `publicPath` | `publicPath` | No differences |
| `pure` | n/a | Not supported |
| `reserveProps` | n/a | Not supported |
| `resolveExtensions` | n/a | Not supported |
| `sourceRoot` | n/a | Not supported |
| `sourcemap` | `sourcemap` | Supports `"inline"`, `"external"`, and `"none"` |
| `sourcesContent` | n/a | Not supported |
| `splitting` | `splitting` | No differences |
| `stdin` | n/a | Not supported |
| `supported` | n/a | Not supported |
| `target` | n/a | No support for syntax downleveling |
| `treeShaking` | n/a | Always true |
| `tsconfig` | n/a | Not supported |
| `write` | n/a | Set to true if `outdir`/`outfile` is set, otherwise false |
## Plugin API
Bun's plugin API is designed to be esbuild compatible. Bun doesn't support esbuild's entire plugin API surface, but the core functionality is implemented. Many third-party esbuild plugins will work out of the box with Bun.
<Note>
Long term, we aim for feature parity with esbuild's API, so if something doesn't work please file an issue to help us
prioritize.
</Note>
Plugins in Bun and esbuild are defined with a builder object.
```ts title="myPlugin.ts" icon="/icons/typescript.svg"
import type { BunPlugin } from "bun";
const myPlugin: BunPlugin = {
name: "my-plugin",
setup(builder) {
// define plugin
},
};
```
The builder object provides some methods for hooking into parts of the bundling process. Bun implements `onResolve` and `onLoad`; it does not yet implement the esbuild hooks `onStart`, `onEnd`, and `onDispose`, and `resolve` utilities. `initialOptions` is partially implemented, being read-only and only having a subset of esbuild's options; use `config` (same thing but with Bun's `BuildConfig` format) instead.
```ts title="myPlugin.ts" icon="/icons/typescript.svg"
import type { BunPlugin } from "bun";
const myPlugin: BunPlugin = {
name: "my-plugin",
setup(builder) {
builder.onResolve(
{
/* onResolve.options */
},
args => {
return {
/* onResolve.results */
};
},
);
builder.onLoad(
{
/* onLoad.options */
},
args => {
return {
/* onLoad.results */
};
},
);
},
};
```
### onResolve
<Tabs>
<Tab title="options">- 🟢 `filter` - 🟢 `namespace`</Tab>
<Tab title="arguments">
- 🟢 `path` - 🟢 `importer` - 🔴 `namespace` - 🔴 `resolveDir` - 🔴 `kind` - 🔴 `pluginData`
</Tab>
<Tab title="results">
- 🟢 `namespace` - 🟢 `path` - 🔴 `errors` - 🔴 `external` - 🔴 `pluginData` - 🔴 `pluginName` - 🔴 `sideEffects` -
🔴 `suffix` - 🔴 `warnings` - 🔴 `watchDirs` - 🔴 `watchFiles`
</Tab>
</Tabs>
### onLoad
<Tabs>
<Tab title="options">- 🟢 `filter` - 🟢 `namespace`</Tab>
<Tab title="arguments">- 🟢 `path` - 🔴 `namespace` - 🔴 `suffix` - 🔴 `pluginData`</Tab>
<Tab title="results">
- 🟢 `contents` - 🟢 `loader` - 🔴 `errors` - 🔴 `pluginData` - 🔴 `pluginName` - 🔴 `resolveDir` - 🔴 `warnings` -
🔴 `watchDirs` - 🔴 `watchFiles`
</Tab>
</Tabs>

View File

@@ -1,33 +1,43 @@
---
title: "Single-file executable"
description: "Generate standalone executables from TypeScript or JavaScript files with Bun"
---
Bun's bundler implements a `--compile` flag for generating a standalone binary from a TypeScript or JavaScript file.
{% codetabs %}
<CodeGroup>
```bash
$ bun build ./cli.ts --compile --outfile mycli
```bash terminal icon="terminal"
bun build ./cli.ts --compile --outfile mycli
```
```ts#cli.ts
```ts cli.ts icon="/icons/typescript.svg"
console.log("Hello world!");
```
{% /codetabs %}
</CodeGroup>
This bundles `cli.ts` into an executable that can be executed directly:
```bash terminal icon="terminal"
./mycli
```
$ ./mycli
```txt
Hello world!
```
All imported files and packages are bundled into the executable, along with a copy of the Bun runtime. All built-in Bun and Node.js APIs are supported.
---
## Cross-compile to other platforms
The `--target` flag lets you compile your standalone executable for a different operating system, architecture, or version of Bun than the machine you're running `bun build` on.
To build for Linux x64 (most servers):
```sh
```bash icon="terminal" terminal
bun build --compile --target=bun-linux-x64 ./index.ts --outfile myapp
# To support CPUs from before 2013, use the baseline version (nehalem)
@@ -40,14 +50,14 @@ bun build --compile --target=bun-linux-x64-modern ./index.ts --outfile myapp
To build for Linux ARM64 (e.g. Graviton or Raspberry Pi):
```sh
```bash icon="terminal" terminal
# Note: the default architecture is x64 if no architecture is specified.
bun build --compile --target=bun-linux-arm64 ./index.ts --outfile myapp
```
To build for Windows x64:
```sh
```bash icon="terminal" terminal
bun build --compile --target=bun-windows-x64 ./path/to/my/app.ts --outfile myapp
# To support CPUs from before 2013, use the baseline version (nehalem)
@@ -61,17 +71,17 @@ bun build --compile --target=bun-windows-x64-modern ./path/to/my/app.ts --outfil
To build for macOS arm64:
```sh
```bash icon="terminal" terminal
bun build --compile --target=bun-darwin-arm64 ./path/to/my/app.ts --outfile myapp
```
To build for macOS x64:
```sh
```bash icon="terminal" terminal
bun build --compile --target=bun-darwin-x64 ./path/to/my/app.ts --outfile myapp
```
#### Supported targets
### Supported targets
The order of the `--target` flag does not matter, as long as they're delimited by a `-`.
@@ -86,21 +96,32 @@ The order of the `--target` flag does not matter, as long as they're delimited b
| bun-linux-x64-musl | Linux | x64 | ✅ | ✅ | musl |
| bun-linux-arm64-musl | Linux | arm64 | ✅ | N/A | musl |
On x64 platforms, Bun uses SIMD optimizations which require a modern CPU supporting AVX2 instructions. The `-baseline` build of Bun is for older CPUs that don't support these optimizations. Normally, when you install Bun we automatically detect which version to use but this can be harder to do when cross-compiling since you might not know the target CPU. You usually don't need to worry about it on Darwin x64, but it is relevant for Windows x64 and Linux x64. If you or your users see `"Illegal instruction"` errors, you might need to use the baseline version.
<Warning>
On x64 platforms, Bun uses SIMD optimizations which require a modern CPU supporting AVX2 instructions. The `-baseline`
build of Bun is for older CPUs that don't support these optimizations. Normally, when you install Bun we automatically
detect which version to use but this can be harder to do when cross-compiling since you might not know the target CPU.
You usually don't need to worry about it on Darwin x64, but it is relevant for Windows x64 and Linux x64. If you or
your users see `"Illegal instruction"` errors, you might need to use the baseline version.
</Warning>
---
## Build-time constants
Use the `--define` flag to inject build-time constants into your executable, such as version numbers, build timestamps, or configuration values:
```bash
$ bun build --compile --define BUILD_VERSION='"1.2.3"' --define BUILD_TIME='"2024-01-15T10:30:00Z"' src/cli.ts --outfile mycli
```bash icon="terminal" terminal
bun build --compile --define BUILD_VERSION='"1.2.3"' --define BUILD_TIME='"2024-01-15T10:30:00Z"' src/cli.ts --outfile mycli
```
These constants are embedded directly into your compiled binary at build time, providing zero runtime overhead and enabling dead code elimination optimizations.
{% callout type="info" %}
For comprehensive examples and advanced patterns, see the [Build-time constants guide](/guides/runtime/build-time-constants).
{% /callout %}
<Note>
For comprehensive examples and advanced patterns, see the [Build-time constants
guide](https://bun.com/guides/runtime/build-time-constants).
</Note>
---
## Deploying to production
@@ -112,7 +133,7 @@ With compiled executables, you can move that cost from runtime to build-time.
When deploying to production, we recommend the following:
```sh
```bash icon="terminal" terminal
bun build --compile --minify --sourcemap ./path/to/my/app.ts --outfile myapp
```
@@ -120,17 +141,22 @@ bun build --compile --minify --sourcemap ./path/to/my/app.ts --outfile myapp
To improve startup time, enable bytecode compilation:
```sh
```bash icon="terminal" terminal
bun build --compile --minify --sourcemap --bytecode ./path/to/my/app.ts --outfile myapp
```
Using bytecode compilation, `tsc` starts 2x faster:
{% image src="https://github.com/user-attachments/assets/dc8913db-01d2-48f8-a8ef-ac4e984f9763" width="689" /%}
<Frame>
![Bytecode performance comparison](https://github.com/user-attachments/assets/dc8913db-01d2-48f8-a8ef-ac4e984f9763)
</Frame>
Bytecode compilation moves parsing overhead for large input files from runtime to bundle time. Your app starts faster, in exchange for making the `bun build` command a little slower. It doesn't obscure source code.
**Experimental:** Bytecode compilation is an experimental feature introduced in Bun v1.1.30. Only `cjs` format is supported (which means no top-level-await). Let us know if you run into any issues!
<Warning>
**Experimental:** Bytecode compilation is an experimental feature introduced in Bun v1.1.30. Only `cjs` format is
supported (which means no top-level-await). Let us know if you run into any issues!
</Warning>
### What do these flags do?
@@ -140,68 +166,77 @@ The `--sourcemap` argument embeds a sourcemap compressed with zstd, so that erro
The `--bytecode` argument enables bytecode compilation. Every time you run JavaScript code in Bun, JavaScriptCore (the engine) will compile your source code into bytecode. We can move this parsing work from runtime to bundle time, saving you startup time.
---
## Embedding runtime arguments
**`--compile-exec-argv="args"`** - Embed runtime arguments that are available via `process.execArgv`:
```bash
```bash icon="terminal" terminal
bun build --compile --compile-exec-argv="--smol --user-agent=MyBot" ./app.ts --outfile myapp
```
```js
```ts app.ts icon="/icons/typescript.svg"
// In the compiled app
console.log(process.execArgv); // ["--smol", "--user-agent=MyBot"]
```
---
## Act as the Bun CLI
{% note %}
New in Bun v1.2.16
{% /note %}
<Note>New in Bun v1.2.16</Note>
You can run a standalone executable as if it were the `bun` CLI itself by setting the `BUN_BE_BUN=1` environment variable. When this variable is set, the executable will ignore its bundled entrypoint and instead expose all the features of Bun's CLI.
For example, consider an executable compiled from a simple script:
```sh
$ cat such-bun.js
console.log("you shouldn't see this");
```bash icon="terminal" terminal
echo "console.log(\"you shouldn't see this\");" > such-bun.js
bun build --compile ./such-bun.js
```
$ bun build --compile ./such-bun.js
[3ms] bundle 1 modules
```txt
[3ms] bundle 1 modules
[89ms] compile such-bun
```
Normally, running `./such-bun` with arguments would execute the script. However, with the `BUN_BE_BUN=1` environment variable, it acts just like the `bun` binary:
Normally, running `./such-bun` with arguments would execute the script.
```sh
```bash icon="terminal" terminal
# Executable runs its own entrypoint by default
$ ./such-bun install
you shouldn't see this
./such-bun install
```
```txt
you shouldn't see this
```
However, with the `BUN_BE_BUN=1` environment variable, it acts just like the `bun` binary:
```bash icon="terminal" terminal
# With the env var, the executable acts like the `bun` CLI
$ BUN_BE_BUN=1 ./such-bun install
bun_BE_BUN=1 ./such-bun install
```
```txt
bun install v1.2.16-canary.1 (1d1db811)
Checked 63 installs across 64 packages (no changes) [5.00ms]
```
This is useful for building CLI tools on top of Bun that may need to install packages, bundle dependencies, run different or local files and more without needing to download a separate binary or install bun.
---
## Full-stack executables
{% note %}
New in Bun v1.2.17
{% /note %}
<Note>New in Bun v1.2.17</Note>
Bun's `--compile` flag can create standalone executables that contain both server and client code, making it ideal for full-stack applications. When you import an HTML file in your server code, Bun automatically bundles all frontend assets (JavaScript, CSS, etc.) and embeds them into the executable. When Bun sees the HTML import on the server, it kicks off a frontend build process to bundle JavaScript, CSS, and other assets.
{% codetabs %}
<CodeGroup>
```ts#server.ts
```ts server.ts icon="/icons/typescript.svg"
import { serve } from "bun";
import index from "./index.html";
@@ -215,12 +250,12 @@ const server = serve({
console.log(`Server running at http://localhost:${server.port}`);
```
```html#index.html
```html index.html icon="file-code"
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
<link rel="stylesheet" href="./styles.css">
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<h1>Hello World</h1>
@@ -229,21 +264,21 @@ console.log(`Server running at http://localhost:${server.port}`);
</html>
```
```js#app.js
```ts app.js icon="file-code"
console.log("Hello from the client!");
```
```css#styles.css
```css styles.css icon="file-code"
body {
background-color: #f0f0f0;
}
```
{% /codetabs %}
</CodeGroup>
To build this into a single executable:
```sh
```bash terminal icon="terminal"
bun build --compile ./server.ts --outfile myapp
```
@@ -256,25 +291,27 @@ This creates a self-contained binary that includes:
The result is a single file that can be deployed anywhere without needing Node.js, Bun, or any dependencies installed. Just run:
```sh
```bash terminal icon="terminal"
./myapp
```
Bun automatically handles serving the frontend assets with proper MIME types and cache headers. The HTML import is replaced with a manifest object that `Bun.serve` uses to efficiently serve pre-bundled assets.
For more details on building full-stack applications with Bun, see the [full-stack guide](/docs/bundler/fullstack).
For more details on building full-stack applications with Bun, see the [full-stack guide](/bundler/fullstack).
---
## Worker
To use workers in a standalone executable, add the worker's entrypoint to the CLI arguments:
```sh
$ bun build --compile ./index.ts ./my-worker.ts --outfile myapp
```bash terminal icon="terminal"
bun build --compile ./index.ts ./my-worker.ts --outfile myapp
```
Then, reference the worker in your code:
```ts
```ts index.ts icon="/icons/typescript.svg"
console.log("Hello from Bun!");
// Any of these will work:
@@ -289,13 +326,15 @@ In the future, we may automatically detect usages of statically-known paths in `
If you use a relative path to a file not included in the standalone executable, it will attempt to load that path from disk relative to the current working directory of the process (and then error if it doesn't exist).
---
## SQLite
You can use `bun:sqlite` imports with `bun build --compile`.
By default, the database is resolved relative to the current working directory of the process.
```js
```ts index.ts icon="/icons/typescript.svg"
import db from "./my.db" with { type: "sqlite" };
console.log(db.query("select * from users LIMIT 1").get());
@@ -303,10 +342,12 @@ console.log(db.query("select * from users LIMIT 1").get());
That means if the executable is located at `/usr/bin/hello`, the user's terminal is located at `/home/me/Desktop`, it will look for `/home/me/Desktop/my.db`.
```bash terminal icon="terminal"
cd /home/me/Desktop
./hello
```
$ cd /home/me/Desktop
$ ./hello
```
---
## Embed assets & files
@@ -314,7 +355,7 @@ Standalone executables support embedding files.
To embed files into an executable with `bun build --compile`, import the file in your code.
```ts
```ts index.ts icon="/icons/typescript.svg"
// this becomes an internal file path
import icon from "./icon.png" with { type: "file" };
import { file } from "bun";
@@ -331,7 +372,7 @@ Embedded files can be read using `Bun.file`'s functions or the Node.js `fs.readF
For example, to read the contents of the embedded file:
```js
```ts index.ts icon="/icons/typescript.svg"
import icon from "./icon.png" with { type: "file" };
import { file } from "bun";
@@ -344,7 +385,7 @@ const bytes = await file(icon).arrayBuffer();
If your application wants to embed a SQLite database, set `type: "sqlite"` in the import attribute and the `embed` attribute to `"true"`.
```js
```ts index.ts icon="/icons/typescript.svg"
import myEmbeddedDb from "./my.db" with { type: "sqlite", embed: "true" };
console.log(myEmbeddedDb.query("select * from users LIMIT 1").get());
@@ -356,7 +397,7 @@ This database is read-write, but all changes are lost when the executable exits
As of Bun v1.0.23, you can embed `.node` files into executables.
```js
```ts index.ts icon="/icons/typescript.svg"
const addon = require("./addon.node");
console.log(addon.hello());
@@ -368,13 +409,13 @@ Unfortunately, if you're using `@mapbox/node-pre-gyp` or other similar tools, yo
To embed a directory with `bun build --compile`, use a shell glob in your `bun build` command:
```sh
$ bun build --compile ./index.ts ./public/**/*.png
```bash terminal icon="terminal"
bun build --compile ./index.ts ./public/**/*.png
```
Then, you can reference the files in your code:
```ts
```ts index.ts icon="/icons/typescript.svg"
import icon from "./public/assets/icon.png" with { type: "file" };
import { file } from "bun";
@@ -392,7 +433,7 @@ This is honestly a workaround, and we expect to improve this in the future with
To get a list of all embedded files, use `Bun.embeddedFiles`:
```js
```ts index.ts icon="/icons/typescript.svg"
import "./icon.png" with { type: "file" };
import { embeddedFiles } from "bun";
@@ -413,141 +454,40 @@ By default, embedded files have a content hash appended to their name. This is u
To disable the content hash, pass `--asset-naming` to `bun build --compile` like this:
```sh
$ bun build --compile --asset-naming="[name].[ext]" ./index.ts
```bash terminal icon="terminal"
bun build --compile --asset-naming="[name].[ext]" ./index.ts
```
---
## Minification
To trim down the size of the executable a little, pass `--minify` to `bun build --compile`. This uses Bun's minifier to reduce the code size. Overall though, Bun's binary is still way too big and we need to make it smaller.
## Using Bun.build() API
You can also generate standalone executables using the `Bun.build()` JavaScript API. This is useful when you need programmatic control over the build process.
### Basic usage
```js
await Bun.build({
entrypoints: ["./app.ts"],
outdir: "./dist",
compile: {
target: "bun-windows-x64",
outfile: "myapp.exe",
},
});
```
### Windows metadata with Bun.build()
When targeting Windows, you can specify metadata through the `windows` object:
```js
await Bun.build({
entrypoints: ["./app.ts"],
outdir: "./dist",
compile: {
target: "bun-windows-x64",
outfile: "myapp.exe",
windows: {
title: "My Application",
publisher: "My Company Inc",
version: "1.2.3.4",
description: "A powerful application built with Bun",
copyright: "© 2024 My Company Inc",
hideConsole: false, // Set to true for GUI applications
icon: "./icon.ico", // Path to icon file
},
},
});
```
### Cross-compilation with Bun.build()
You can cross-compile for different platforms:
```js
// Build for multiple platforms
const platforms = [
{ target: "bun-windows-x64", outfile: "app-windows.exe" },
{ target: "bun-linux-x64", outfile: "app-linux" },
{ target: "bun-darwin-arm64", outfile: "app-macos" },
];
for (const platform of platforms) {
await Bun.build({
entrypoints: ["./app.ts"],
outdir: "./dist",
compile: platform,
});
}
```
---
## Windows-specific flags
When compiling a standalone executable for Windows, there are several platform-specific options that can be used to customize the generated `.exe` file:
When compiling a standalone executable on Windows, there are two platform-specific options that can be used to customize metadata on the generated `.exe` file:
### Visual customization
- `--windows-icon=path/to/icon.ico` to customize the executable file icon.
- `--windows-hide-console` to disable the background terminal, which can be used for applications that do not need a TTY.
- `--windows-icon=path/to/icon.ico` - Set the executable file icon
- `--windows-hide-console` - Disable the background terminal window (useful for GUI applications)
<Warning>These flags currently cannot be used when cross-compiling because they depend on Windows APIs.</Warning>
### Metadata customization
You can embed version information and other metadata into your Windows executable:
- `--windows-title <STR>` - Set the product name (appears in file properties)
- `--windows-publisher <STR>` - Set the company name
- `--windows-version <STR>` - Set the version number (e.g. "1.2.3.4")
- `--windows-description <STR>` - Set the file description
- `--windows-copyright <STR>` - Set the copyright information
#### Example with all metadata flags:
```sh
bun build --compile ./app.ts \
--outfile myapp.exe \
--windows-title "My Application" \
--windows-publisher "My Company Inc" \
--windows-version "1.2.3.4" \
--windows-description "A powerful application built with Bun" \
--windows-copyright "© 2024 My Company Inc"
```
This metadata will be visible in Windows Explorer when viewing the file properties:
1. Right-click the executable in Windows Explorer
2. Select "Properties"
3. Go to the "Details" tab
#### Version string format
The `--windows-version` flag accepts version strings in the following formats:
- `"1"` - Will be normalized to "1.0.0.0"
- `"1.2"` - Will be normalized to "1.2.0.0"
- `"1.2.3"` - Will be normalized to "1.2.3.0"
- `"1.2.3.4"` - Full version format
Each version component must be a number between 0 and 65535.
{% callout %}
These flags currently cannot be used when cross-compiling because they depend on Windows APIs. They are only available when building on Windows itself.
{% /callout %}
---
## Code signing on macOS
To codesign a standalone executable on macOS (which fixes Gatekeeper warnings), use the `codesign` command.
```sh
$ codesign --deep --force -vvvv --sign "XXXXXXXXXX" ./myapp
```bash terminal icon="terminal"
codesign --deep --force -vvvv --sign "XXXXXXXXXX" ./myapp
```
We recommend including an `entitlements.plist` file with JIT permissions.
```xml#entitlements.plist
```xml icon="xml" title="info.plist"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
@@ -568,23 +508,21 @@ We recommend including an `entitlements.plist` file with JIT permissions.
To codesign with JIT support, pass the `--entitlements` flag to `codesign`.
```sh
$ codesign --deep --force -vvvv --sign "XXXXXXXXXX" --entitlements entitlements.plist ./myapp
```bash terminal icon="terminal"
codesign --deep --force -vvvv --sign "XXXXXXXXXX" --entitlements entitlements.plist ./myapp
```
After codesigning, verify the executable:
```sh
$ codesign -vvv --verify ./myapp
```bash terminal icon="terminal"
codesign -vvv --verify ./myapp
./myapp: valid on disk
./myapp: satisfies its Designated Requirement
```
{% callout %}
<Warning>Codesign support requires Bun v1.2.4 or newer.</Warning>
Codesign support requires Bun v1.2.4 or newer.
{% /callout %}
---
## Unsupported CLI arguments

View File

@@ -1,418 +0,0 @@
To get started, import HTML files and pass them to the `routes` option in `Bun.serve()`.
```ts
import { sql, serve } from "bun";
import dashboard from "./dashboard.html";
import homepage from "./index.html";
const server = serve({
routes: {
// ** HTML imports **
// Bundle & route index.html to "/". This uses HTMLRewriter to scan the HTML for `<script>` and `<link>` tags, run's Bun's JavaScript & CSS bundler on them, transpiles any TypeScript, JSX, and TSX, downlevels CSS with Bun's CSS parser and serves the result.
"/": homepage,
// Bundle & route dashboard.html to "/dashboard"
"/dashboard": dashboard,
// ** API endpoints ** (Bun v1.2.3+ required)
"/api/users": {
async GET(req) {
const users = await sql`SELECT * FROM users`;
return Response.json(users);
},
async POST(req) {
const { name, email } = await req.json();
const [user] =
await sql`INSERT INTO users (name, email) VALUES (${name}, ${email})`;
return Response.json(user);
},
},
"/api/users/:id": async req => {
const { id } = req.params;
const [user] = await sql`SELECT * FROM users WHERE id = ${id}`;
return Response.json(user);
},
},
// Enable development mode for:
// - Detailed error messages
// - Hot reloading (Bun v1.2.3+ required)
development: true,
// Prior to v1.2.3, the `fetch` option was used to handle all API requests. It is now optional.
// async fetch(req) {
// // Return 404 for unmatched routes
// return new Response("Not Found", { status: 404 });
// },
});
console.log(`Listening on ${server.url}`);
```
```bash
$ bun run app.ts
```
## HTML imports are routes
The web starts with HTML, and so does Bun's fullstack dev server.
To specify entrypoints to your frontend, import HTML files into your JavaScript/TypeScript/TSX/JSX files.
```ts
import dashboard from "./dashboard.html";
import homepage from "./index.html";
```
These HTML files are used as routes in Bun's dev server you can pass to `Bun.serve()`.
```ts
Bun.serve({
routes: {
"/": homepage,
"/dashboard": dashboard,
}
fetch(req) {
// ... api requests
},
});
```
When you make a request to `/dashboard` or `/`, Bun automatically bundles the `<script>` and `<link>` tags in the HTML files, exposes them as static routes, and serves the result.
An index.html file like this:
```html#index.html
<!DOCTYPE html>
<html>
<head>
<title>Home</title>
<link rel="stylesheet" href="./reset.css" />
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<div id="root"></div>
<script type="module" src="./sentry-and-preloads.ts"></script>
<script type="module" src="./my-app.tsx"></script>
</body>
</html>
```
Becomes something like this:
```html#index.html
<!DOCTYPE html>
<html>
<head>
<title>Home</title>
<link rel="stylesheet" href="/index-[hash].css" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/index-[hash].js"></script>
</body>
</html>
```
### How to use with React
To use React in your client-side code, import `react-dom/client` and render your app.
{% codetabs %}
```ts#src/backend.ts
import dashboard from "../public/dashboard.html";
import { serve } from "bun";
serve({
routes: {
"/": dashboard,
},
async fetch(req) {
// ...api requests
return new Response("hello world");
},
});
```
```ts#src/frontend.tsx
import "./styles.css";
import { createRoot } from "react-dom/client";
import { App } from "./app.tsx";
document.addEventListener("DOMContentLoaded", () => {
const root = createRoot(document.getElementById("root"));
root.render(<App />);
});
```
```html#public/dashboard.html
<!DOCTYPE html>
<html>
<head>
<title>Dashboard</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="../src/frontend.tsx"></script>
</body>
</html>
```
```css#src/styles.css
body {
background-color: red;
}
```
```tsx#src/app.tsx
export function App() {
return <div>Hello World</div>;
}
```
{% /codetabs %}
### Development mode
When building locally, enable development mode by setting `development: true` in `Bun.serve()`.
```js-diff
import homepage from "./index.html";
import dashboard from "./dashboard.html";
Bun.serve({
routes: {
"/": homepage,
"/dashboard": dashboard,
}
+ development: true,
fetch(req) {
// ... api requests
},
});
```
When `development` is `true`, Bun will:
- Include the `SourceMap` header in the response so that devtools can show the original source code
- Disable minification
- Re-bundle assets on each request to a .html file
- Enable hot module reloading (unless `hmr: false` is set)
#### Echo console logs from browser to terminal
Bun.serve() supports echoing console logs from the browser to the terminal.
To enable this, pass `console: true` in the `development` object in `Bun.serve()`.
```ts
import homepage from "./index.html";
Bun.serve({
// development can also be an object.
development: {
// Enable Hot Module Reloading
hmr: true,
// Echo console logs from the browser to the terminal
console: true,
},
routes: {
"/": homepage,
},
});
```
When `console: true` is set, Bun will stream console logs from the browser to the terminal. This reuses the existing WebSocket connection from HMR to send the logs.
#### Production mode
Hot reloading and `development: true` helps you iterate quickly, but in production, your server should be as fast as possible and have as few external dependencies as possible.
##### Ahead of time bundling (recommended)
As of Bun v1.2.17, you can use `Bun.build` or `bun build` to bundle your full-stack application ahead of time.
```sh
$ bun build --target=bun --production --outdir=dist ./src/index.ts
```
When Bun's bundler sees an HTML import from server-side code, it will bundle the referenced JavaScript/TypeScript/TSX/JSX and CSS files into a manifest object that Bun.serve() can use to serve the assets.
```ts
import { serve } from "bun";
import index from "./index.html";
serve({
routes: { "/": index },
});
```
{% details summary="Internally, the `index` variable is a manifest object that looks something like this" %}
```json
{
"index": "./index.html",
"files": [
{
"input": "index.html",
"path": "./index-f2me3qnf.js",
"loader": "js",
"isEntry": true,
"headers": {
"etag": "eet6gn75",
"content-type": "text/javascript;charset=utf-8"
}
},
{
"input": "index.html",
"path": "./index.html",
"loader": "html",
"isEntry": true,
"headers": {
"etag": "r9njjakd",
"content-type": "text/html;charset=utf-8"
}
},
{
"input": "index.html",
"path": "./index-gysa5fmk.css",
"loader": "css",
"isEntry": true,
"headers": {
"etag": "50zb7x61",
"content-type": "text/css;charset=utf-8"
}
},
{
"input": "logo.svg",
"path": "./logo-kygw735p.svg",
"loader": "file",
"isEntry": false,
"headers": {
"etag": "kygw735p",
"content-type": "application/octet-stream"
}
},
{
"input": "react.svg",
"path": "./react-ck11dneg.svg",
"loader": "file",
"isEntry": false,
"headers": {
"etag": "ck11dneg",
"content-type": "application/octet-stream"
}
}
]
}
```
{% /details %}
##### Runtime bundling
When adding a build step is too complicated, you can set `development: false` in `Bun.serve()`.
- Enable in-memory caching of bundled assets. Bun will bundle assets lazily on the first request to an `.html` file, and cache the result in memory until the server restarts.
- Enables `Cache-Control` headers and `ETag` headers
- Minifies JavaScript/TypeScript/TSX/JSX files
## Plugins
Bun's [bundler plugins](https://bun.com/docs/bundler/plugins) are also supported when bundling static routes.
To configure plugins for `Bun.serve`, add a `plugins` array in the `[serve.static]` section of your `bunfig.toml`.
### Using TailwindCSS in HTML routes
For example, enable TailwindCSS on your routes by installing and adding the `bun-plugin-tailwind` plugin:
```sh
$ bun add bun-plugin-tailwind
```
```toml#bunfig.toml
[serve.static]
plugins = ["bun-plugin-tailwind"]
```
This will allow you to use TailwindCSS utility classes in your HTML and CSS files. All you need to do is import `tailwindcss` somewhere:
```html#index.html
<!doctype html>
<html>
<head>
<title>Home</title>
<link rel="stylesheet" href="tailwindcss" />
</head>
<body>
<!-- the rest of your HTML... -->
</body>
</html>
```
Or in your CSS:
```css#style.css
@import "tailwindcss";
```
### Custom plugins
Any JS file or module which exports a [valid bundler plugin object](https://bun.com/docs/bundler/plugins#usage) (essentially an object with a `name` and `setup` field) can be placed inside the `plugins` array:
```toml#bunfig.toml
[serve.static]
plugins = ["./my-plugin-implementation.ts"]
```
Bun will lazily resolve and load each plugin and use them to bundle your routes.
Note: this is currently in `bunfig.toml` to make it possible to know statically which plugins are in use when we eventually integrate this with the `bun build` CLI. These plugins work in `Bun.build()`'s JS API, but are not yet supported in the CLI.
## How this works
Bun uses [`HTMLRewriter`](/docs/api/html-rewriter) to scan for `<script>` and `<link>` tags in HTML files, uses them as entrypoints for [Bun's bundler](/docs/bundler), generates an optimized bundle for the JavaScript/TypeScript/TSX/JSX and CSS files, and serves the result.
1. **`<script>` processing**
- Transpiles TypeScript, JSX, and TSX in `<script>` tags
- Bundles imported dependencies
- Generates sourcemaps for debugging
- Minifies when `development` is not `true` in `Bun.serve()`
```html
<script type="module" src="./counter.tsx"></script>
```
2. **`<link>` processing**
- Processes CSS imports and `<link>` tags
- Concatenates CSS files
- Rewrites `url` and asset paths to include content-addressable hashes in URLs
```html
<link rel="stylesheet" href="./styles.css" />
```
3. **`<img>` & asset processing**
- Links to assets are rewritten to include content-addressable hashes in URLs
- Small assets in CSS files are inlined into `data:` URLs, reducing the total number of HTTP requests sent over the wire
4. **Rewrite HTML**
- Combines all `<script>` tags into a single `<script>` tag with a content-addressable hash in the URL
- Combines all `<link>` tags into a single `<link>` tag with a content-addressable hash in the URL
- Outputs a new HTML file
5. **Serve**
- All the output files from the bundler are exposed as static routes, using the same mechanism internally as when you pass a `Response` object to [`static` in `Bun.serve()`](/docs/api/http#static-routes).
This works similarly to how [`Bun.build` processes HTML files](/docs/bundler/html).
## This is a work in progress
- This doesn't support `bun build` yet. It also will in the future.

1064
docs/bundler/fullstack.mdx Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +1,35 @@
Hot Module Replacement (HMR) allows you to update modules in a running
application without needing a full page reload. This preserves the application
state and improves the development experience.
---
title: Hot reloading
description: Hot Module Replacement (HMR) for Bun's development server
---
HMR is enabled by default when using Bun's full-stack development server.
Hot Module Replacement (HMR) allows you to update modules in a running application without needing a full page reload. This preserves the application state and improves the development experience.
<Note>HMR is enabled by default when using Bun's full-stack development server.</Note>
## `import.meta.hot` API Reference
Bun implements a client-side HMR API modeled after [Vite's `import.meta.hot` API](https://vitejs.dev/guide/api-hmr.html). It can be checked for with `if (import.meta.hot)`, tree-shaking it in production
Bun implements a client-side HMR API modeled after [Vite's `import.meta.hot` API](https://vitejs.dev/guide/api-hmr.html). It can be checked for with `if (import.meta.hot)`, tree-shaking it in production.
```ts
```ts title="index.ts" icon="/icons/typescript.svg"
if (import.meta.hot) {
// HMR APIs are available.
}
```
However, **this check is often not needed** as Bun will dead-code-eliminate
calls to all of the HMR APIs in production builds.
However, this check is often not needed as Bun will dead-code-eliminate calls to all of the HMR APIs in production builds.
```ts
```ts title="index.ts" icon="/icons/typescript.svg"
// This entire function call will be removed in production!
import.meta.hot.dispose(() => {
console.log("dispose");
});
```
<Warning>
For this to work, Bun forces these APIs to be called without indirection. That means the following do not work:
```ts#invalid-hmr-usage.ts
```ts title="index.ts" icon="/icons/typescript.svg"
// INVALID: Assigning `hot` to a variable
const hot = import.meta.hot;
hot.accept();
@@ -46,32 +49,32 @@ import.meta.hot.accept();
doSomething(import.meta.hot.data);
```
{% callout %}
</Warning>
**Note** — The HMR API is still a work in progress. Some features are missing. HMR can be disabled in `Bun.serve` by setting the `development` option to `{ hmr: false }`.
<Note>
The HMR API is still a work in progress. Some features are missing. HMR can be disabled in `Bun.serve` by setting the development option to `{ hmr: false }`.
</Note>
{% endcallout %}
## API Methods
| | Method | Notes |
| --- | ------------------ | --------------------------------------------------------------------- |
| ✅ | `hot.accept()` | Indicate that a hot update can be replaced gracefully. |
| ✅ | `hot.data` | Persist data between module evaluations. |
| ✅ | `hot.dispose()` | Add a callback function to run when a module is about to be replaced. |
| ❌ | `hot.invalidate()` | |
| ✅ | `hot.on()` | Attach an event listener |
| ✅ | `hot.off()` | Remove an event listener from `on`. |
| ❌ | `hot.send()` | |
| 🚧 | `hot.prune()` | **NOTE**: Callback is currently never called. |
| ✅ | `hot.decline()` | No-op to match Vite's `import.meta.hot` |
| Method | Status | Notes |
| ------------------ | ------ | --------------------------------------------------------------------- |
| `hot.accept()` | ✅ | Indicate that a hot update can be replaced gracefully. |
| `hot.data` | ✅ | Persist data between module evaluations. |
| `hot.dispose()` | ✅ | Add a callback function to run when a module is about to be replaced. |
| `hot.invalidate()` | ❌ | |
| `hot.on()` | ✅ | Attach an event listener |
| `hot.off()` | ✅ | Remove an event listener from `on`. |
| `hot.send()` | ❌ | |
| `hot.prune()` | 🚧 | NOTE: Callback is currently never called. |
| `hot.decline()` | ✅ | No-op to match Vite's `import.meta.hot` |
### `import.meta.hot.accept()`
## import.meta.hot.accept()
The `accept()` method indicates that a module can be hot-replaced. When called
without arguments, it indicates that this module can be replaced simply by
re-evaluating the file. After a hot update, importers of this module will be
automatically patched.
The `accept()` method indicates that a module can be hot-replaced. When called without arguments, it indicates that this module can be replaced simply by re-evaluating the file. After a hot update, importers of this module will be automatically patched.
```ts#index.ts
```ts title="index.ts" icon="/icons/typescript.svg"
// index.ts
import { getCount } from "./foo.ts";
console.log("count is ", getCount());
@@ -83,28 +86,21 @@ export function getNegativeCount() {
}
```
This creates a hot-reloading boundary for all of the files that `index.ts`
imports. That means whenever `foo.ts` or any of its dependencies are saved, the
update will bubble up to `index.ts` will re-evaluate. Files that import
`index.ts` will then be patched to import the new version of
`getNegativeCount()`. If only `index.ts` is updated, only the one file will be
re-evaluated, and the counter in `foo.ts` is reused.
This creates a hot-reloading boundary for all of the files that `index.ts` imports. That means whenever `foo.ts` or any of its dependencies are saved, the update will bubble up to `index.ts` will re-evaluate. Files that import `index.ts` will then be patched to import the new version of `getNegativeCount()`. If only `index.ts` is updated, only the one file will be re-evaluated, and the counter in `foo.ts` is reused.
This may be used in combination with `import.meta.hot.data` to transfer state
from the previous module to the new one.
This may be used in combination with `import.meta.hot.data` to transfer state from the previous module to the new one.
When no modules call `import.meta.hot.accept()` (and there isn't React Fast
Refresh or a plugin calling it for you), the page will reload when the file
updates, and a console warning shows which files were invalidated. This warning
is safe to ignore if it makes more sense to rely on full page reloads.
<Info>
When no modules call `import.meta.hot.accept()` (and there isn't React Fast Refresh or a plugin calling it for you),
the page will reload when the file updates, and a console warning shows which files were invalidated. This warning is
safe to ignore if it makes more sense to rely on full page reloads.
</Info>
#### With callback
### With callback
When provided one callback, `import.meta.hot.accept` will function how it does
in Vite. Instead of patching the importers of this module, it will call the
callback with the new module.
When provided one callback, `import.meta.hot.accept` will function how it does in Vite. Instead of patching the importers of this module, it will call the callback with the new module.
```ts
```ts title="index.ts" icon="/icons/typescript.svg"
export const count = 0;
import.meta.hot.accept(newModule => {
@@ -115,11 +111,13 @@ import.meta.hot.accept(newModule => {
});
```
Prefer using `import.meta.hot.accept()` without an argument as it usually makes your code easier to understand.
<Tip>
Prefer using `import.meta.hot.accept()` without an argument as it usually makes your code easier to understand.
</Tip>
#### Accepting other modules
### Accepting other modules
```ts
```ts title="index.ts" icon="/icons/typescript.svg"
import { count } from "./foo";
import.meta.hot.accept("./foo", () => {
@@ -131,9 +129,9 @@ import.meta.hot.accept("./foo", () => {
Indicates that a dependency's module can be accepted. When the dependency is updated, the callback will be called with the new module.
#### With multiple dependencies
### With multiple dependencies
```ts
```ts title="index.ts" icon="/icons/typescript.svg"
import.meta.hot.accept(["./foo", "./bar"], newModules => {
// newModules is an array where each item corresponds to the updated module
// or undefined if that module had a syntax error
@@ -142,33 +140,33 @@ import.meta.hot.accept(["./foo", "./bar"], newModules => {
Indicates that multiple dependencies' modules can be accepted. This variant accepts an array of dependencies, where the callback will receive the updated modules, and `undefined` for any that had errors.
### `import.meta.hot.data`
## import.meta.hot.data
`import.meta.hot.data` maintains state between module instances during hot
replacement, enabling data transfer from previous to new versions. When
`import.meta.hot.data` is written into, Bun will also mark this module as
capable of self-accepting (equivalent of calling `import.meta.hot.accept()`).
`import.meta.hot.data` maintains state between module instances during hot replacement, enabling data transfer from previous to new versions. When `import.meta.hot.data` is written into, Bun will also mark this module as capable of self-accepting (equivalent of calling `import.meta.hot.accept()`).
```ts
```jsx title="index.ts" icon="/icons/typescript.svg"
import { createRoot } from "react-dom/client";
import { App } from "./app";
const root = import.meta.hot.data.root ??= createRoot(elem);
const root = (import.meta.hot.data.root ??= createRoot(elem));
root.render(<App />); // re-use an existing root
```
In production, `data` is inlined to be `{}`, meaning it cannot be used as a state holder.
The above pattern is recommended for stateful modules because Bun knows it can minify `{}.prop ??= value` into `value` in production.
<Tip>
The above pattern is recommended for stateful modules because Bun knows it can minify `{}.prop ??= value` into `value`
in production.
</Tip>
### `import.meta.hot.dispose()`
## import.meta.hot.dispose()
Attaches an on-dispose callback. This is called:
- Just before the module is replaced with another copy (before the next is loaded)
- After the module is detached (removing all imports to this module, see `import.meta.hot.prune()`)
```ts
```ts title="index.ts" icon="/icons/typescript.svg"
const sideEffect = setupSideEffect();
import.meta.hot.dispose(() => {
@@ -176,21 +174,17 @@ import.meta.hot.dispose(() => {
});
```
This callback is not called on route navigation or when the browser tab closes.
<Warning>This callback is not called on route navigation or when the browser tab closes.</Warning>
Returning a promise will delay module replacement until the module is disposed.
All dispose callbacks are called in parallel.
Returning a promise will delay module replacement until the module is disposed. All dispose callbacks are called in parallel.
### `import.meta.hot.prune()`
## import.meta.hot.prune()
Attaches an on-prune callback. This is called when all imports to this module
are removed, but the module was previously loaded.
Attaches an on-prune callback. This is called when all imports to this module are removed, but the module was previously loaded.
This can be used to clean up resources that were created when the module was
loaded. Unlike `import.meta.hot.dispose()`, this pairs much better with `accept`
and `data` to manage stateful resources. A full example managing a `WebSocket`:
This can be used to clean up resources that were created when the module was loaded. Unlike `import.meta.hot.dispose()`, this pairs much better with `accept` and `data` to manage stateful resources. A full example managing a WebSocket:
```ts
```ts title="index.ts" icon="/icons/typescript.svg"
import { something } from "./something";
// Initialize or re-use a WebSocket connection
@@ -202,15 +196,16 @@ import.meta.hot.prune(() => {
});
```
If `dispose` was used instead, the WebSocket would close and re-open on every
hot update. Both versions of the code will prevent page reloads when imported
files are updated.
<Info>
If `dispose` was used instead, the WebSocket would close and re-open on every hot update. Both versions of the code
will prevent page reloads when imported files are updated.
</Info>
### `import.meta.hot.on()` and `off()`
## import.meta.hot.on() and off()
`on()` and `off()` are used to listen for events from the HMR runtime. Event names are prefixed with a prefix so that plugins do not conflict with each other.
```ts
```ts title="index.ts" icon="/icons/typescript.svg"
import.meta.hot.on("bun:beforeUpdate", () => {
console.log("before a hot update");
});
@@ -218,7 +213,7 @@ import.meta.hot.on("bun:beforeUpdate", () => {
When a file is replaced, all of its event listeners are automatically removed.
A list of all built-in events:
### Built-in events
| Event | Emitted when |
| ---------------------- | ----------------------------------------------------------------------------------------------- |
@@ -231,4 +226,4 @@ A list of all built-in events:
| `bun:ws:disconnect` | when the HMR WebSocket connection is lost. This can indicate the development server is offline. |
| `bun:ws:connect` | when the HMR WebSocket connects or re-connects. |
For compatibility with Vite, the above events are also available via `vite:*` prefix instead of `bun:*`.
<Note>For compatibility with Vite, the above events are also available via `vite:*` prefix instead of `bun:*`.</Note>

View File

@@ -1,6 +1,11 @@
---
title: HTML & static sites
description: Build static sites, landing pages, and web applications with Bun's bundler
---
Bun's bundler has first-class support for HTML. Build static sites, landing pages, and web applications with zero configuration. Just point Bun at your HTML file and it handles everything else.
```html#index.html
```html title="index.html" icon="file-code"
<!doctype html>
<html>
<head>
@@ -15,7 +20,16 @@ Bun's bundler has first-class support for HTML. Build static sites, landing page
To get started, pass HTML files to `bun`.
{% bunDevServerTerminal alt="bun ./index.html" path="./index.html" routes="" /%}
```bash terminal icon="terminal"
bun ./index.html
```
```
Bun v1.3.2
ready in 6.62ms
→ http://localhost:3000/
Press h + Enter to show shortcuts
```
Bun's development server provides powerful features with zero configuration:
@@ -26,19 +40,26 @@ Bun's development server provides powerful features with zero configuration:
- **Plugins** - Plugins for TailwindCSS and more
- **ESM & CommonJS** - Use ESM and CommonJS in your JavaScript, TypeScript, and JSX files
- **CSS Bundling & Minification** - Bundles CSS from `<link>` tags and `@import` statements
- **Asset Management**
- Automatic copying & hashing of images and assets
- Rewrites asset paths in JavaScript, CSS, and HTML
- **Asset Management** - Automatic copying & hashing of images and assets; Rewrites asset paths in JavaScript, CSS, and HTML
## Single Page Apps (SPA)
When you pass a single .html file to Bun, Bun will use it as a fallback route for all paths. This makes it perfect for single page apps that use client-side routing:
When you pass a single `.html` file to Bun, Bun will use it as a fallback route for all paths. This makes it perfect for single page apps that use client-side routing:
{% bunDevServerTerminal alt="bun index.html" path="index.html" routes="" /%}
```bash terminal icon="terminal"
bun index.html
```
```
Bun v1.3.2
ready in 6.62ms
→ http://localhost:3000/
Press h + Enter to show shortcuts
```
Your React or other SPA will work out of the box — no configuration needed. All routes like `/about`, `/users/123`, etc. will serve the same HTML file, letting your client-side router handle the navigation.
```html#index.html
```html title="index.html" icon="file-code"
<!doctype html>
<html>
<head>
@@ -53,9 +74,21 @@ Your React or other SPA will work out of the box — no configuration needed. Al
## Multi-page apps (MPA)
Some projects have several separate routes or HTML files as entry points. To support multiple entry points, pass them all to `bun`
Some projects have several separate routes or HTML files as entry points. To support multiple entry points, pass them all to `bun`:
{% bunDevServerTerminal alt="bun ./index.html ./about.html" path="./index.html ./about.html" routes="[{\"path\": \"/\", \"file\": \"./index.html\"}, {\"path\": \"/about\", \"file\": \"./about.html\"}]" /%}
```bash terminal icon="terminal"
bun ./index.html ./about.html
```
```txt
Bun v1.3.2
ready in 6.62ms
→ http://localhost:3000/
Routes:
/ ./index.html
/about ./about.html
Press h + Enter to show shortcuts
```
This will serve:
@@ -66,19 +99,44 @@ This will serve:
To specify multiple files, you can use glob patterns that end in `.html`:
{% bunDevServerTerminal alt="bun ./**/*.html" path="./**/*.html" routes="[{\"path\": \"/\", \"file\": \"./index.html\"}, {\"path\": \"/about\", \"file\": \"./about.html\"}]" /%}
```bash terminal icon="terminal"
bun ./**/*.html
```
```
Bun v1.3.2
ready in 6.62ms
→ http://localhost:3000/
Routes:
/ ./index.html
/about ./about.html
Press h + Enter to show shortcuts
```
### Path normalization
The base path is chosen from the longest common prefix among all the files.
{% bunDevServerTerminal alt="bun ./index.html ./about/index.html ./about/foo/index.html" path="./index.html ./about/index.html ./about/foo/index.html" routes="[{\"path\": \"/\", \"file\": \"./index.html\"}, {\"path\": \"/about\", \"file\": \"./about/index.html\"}, {\"path\": \"/about/foo\", \"file\": \"./about/foo/index.html\"}]" /%}
```bash terminal icon="terminal"
bun ./index.html ./about/index.html ./about/foo/index.html
```
```
Bun v1.3.2
ready in 6.62ms
→ http://localhost:3000/
Routes:
/ ./index.html
/about ./about/index.html
/about/foo ./about/foo/index.html
Press h + Enter to show shortcuts
```
## JavaScript, TypeScript, and JSX
Bun's transpiler natively implements JavaScript, TypeScript, and JSX support. [Learn more about loaders in Bun](/docs/bundler/loaders).
Bun's transpiler natively implements JavaScript, TypeScript, and JSX support. Learn more about loaders in Bun.
Bun's transpiler is also used at runtime.
<Note>Bun's transpiler is also used at runtime.</Note>
### ES Modules & CommonJS
@@ -86,7 +144,7 @@ You can use ESM and CJS in your JavaScript, TypeScript, and JSX files. Bun will
There is no pre-build or separate optimization step. It's all done at the same time.
Learn more about [module resolution in Bun](/docs/runtime/modules).
Learn more about module resolution in Bun.
## CSS
@@ -96,7 +154,9 @@ It's also a CSS bundler. You can use `@import` in your CSS files to import other
For example:
```css#styles.css
<CodeGroup>
```css styles.css icon="file-code"
@import "./abc.css";
.container {
@@ -104,15 +164,17 @@ For example:
}
```
```css#abc.css
```css abc.css
body {
background-color: red;
}
```
</CodeGroup>
This outputs:
```css#styles.css
```css
body {
background-color: red;
}
@@ -126,7 +188,7 @@ body {
You can reference local assets in your CSS files.
```css#styles.css
```css styles.css icon="file-code"
body {
background-image: url("./logo.png");
}
@@ -134,7 +196,7 @@ body {
This will copy `./logo.png` to the output directory and rewrite the path in the CSS file to include a content hash.
```css#styles.css
```css styles.css icon="file-code"
body {
background-image: url("./logo-[ABC123].png");
}
@@ -144,7 +206,7 @@ body {
To associate a CSS file with a JavaScript file, you can import it in your JavaScript file.
```ts#app.ts
```ts app.ts icon="/icons/typescript.svg"
import "./styles.css";
import "./more-styles.css";
```
@@ -159,84 +221,57 @@ The dev server supports plugins.
To use TailwindCSS, install the `bun-plugin-tailwind` plugin:
```bash
```bash terminal icon="terminal"
# Or any npm client
$ bun install --dev bun-plugin-tailwind
bun install --dev bun-plugin-tailwind
```
Then, add the plugin to your `bunfig.toml`:
```toml
```toml title="bunfig.toml" icon="settings"
[serve.static]
plugins = ["bun-plugin-tailwind"]
```
Then, reference TailwindCSS in your HTML via `<link>` tag, `@import` in CSS, or `import` in JavaScript.
Then, reference TailwindCSS in your HTML via `<link>` tag, `@import` in CSS, or import in JavaScript.
{% codetabs %}
<Tabs>
<Tab title="index.html">
```html title="index.html" icon="file-code"
{/* Reference TailwindCSS in your HTML */}
<link rel="stylesheet" href="tailwindcss" />
```
</Tab>
<Tab title="styles.css">```css title="styles.css" icon="file-code" @import "tailwindcss"; ```</Tab>
<Tab title="app.ts">```ts title="app.ts" icon="/icons/typescript.svg" import "tailwindcss"; ```</Tab>
</Tabs>
```html#index.html
<!-- Reference TailwindCSS in your HTML -->
<link rel="stylesheet" href="tailwindcss" />
```
<Info>Only one of those are necessary, not all three.</Info>
```css#styles.css
/* Import TailwindCSS in your CSS */
@import "tailwindcss";
```
```ts#app.ts
/* Import TailwindCSS in your JavaScript */
import "tailwindcss";
```
{% /codetabs %}
Only one of those are necessary, not all three.
### Echo console logs from browser to terminal
## Echo console logs from browser to terminal
Bun's dev server supports streaming console logs from the browser to the terminal.
To enable, pass the `--console` CLI flag.
{% bunDevServerTerminal alt="bun ./index.html --console" path="./index.html --console" routes="" /%}
```bash terminal icon="terminal"
bun ./index.html --console
```
```
Bun v1.3.2
ready in 6.62ms
→ http://localhost:3000/
Press h + Enter to show shortcuts
```
Each call to `console.log` or `console.error` will be broadcast to the terminal that started the server. This is useful to see errors from the browser in the same place you run your server. This is also useful for AI agents that watch terminal output.
Internally, this reuses the existing WebSocket connection from hot module reloading to send the logs.
### Edit files in the browser
## Edit files in the browser
Bun's frontend dev server has support for [Automatic Workspace Folders](https://chromium.googlesource.com/devtools/devtools-frontend/+/main/docs/ecosystem/automatic_workspace_folders.md) in Chrome DevTools, which lets you save edits to files in the browser.
{% image src="/images/bun-chromedevtools.gif" alt="Bun's frontend dev server has support for Automatic Workspace Folders in Chrome DevTools, which lets you save edits to files in the browser." /%}
{% details summary="How it works" %}
Bun's dev server automatically adds a `/.well-known/appspecific/com.chrome.devtools.json` route to the server.
This route returns a JSON object with the following shape:
```json
{
"workspace": {
"root": "/path/to/your/project",
"uuid": "a-unique-identifier-for-this-workspace"
}
}
```
For security reasons, this is only enabled when:
1. The request is coming from localhost, 127.0.0.1, or ::1.
2. Hot Module Reloading is enabled.
3. The `chromeDevToolsAutomaticWorkspaceFolders` flag is set to `true` or `undefined`.
4. There are no other routes that match the request.
You can disable this by passing `development: { chromeDevToolsAutomaticWorkspaceFolders: false }` in `Bun.serve`'s options.
{% /details %}
Bun's frontend dev server has support for Automatic Workspace Folders in Chrome DevTools, which lets you save edits to files in the browser.
## Keyboard Shortcuts
@@ -244,45 +279,45 @@ While the server is running:
- `o + Enter` - Open in browser
- `c + Enter` - Clear console
- `q + Enter` (or Ctrl+C) - Quit server
- `q + Enter` (or `Ctrl+C`) - Quit server
## Build for Production
When you're ready to deploy, use `bun build` to create optimized production bundles:
{% codetabs %}
<Tabs>
<Tab title="CLI">
```bash terminal icon="terminal"
bun build ./index.html --minify --outdir=dist
```
</Tab>
<Tab title="API">
```ts title="build.ts" icon="/icons/typescript.svg"
await Bun.build({
entrypoints: ["./index.html"],
outdir: "./dist",
minify: true,
});
```
</Tab>
</Tabs>
```bash#CLI
$ bun build ./index.html --minify --outdir=dist
```
```ts#API
Bun.build({
entrypoints: ["./index.html"],
outdir: "./dist",
minify: {
whitespace: true,
identifiers: true,
syntax: true,
}
});
```
{% /codetabs %}
Currently, plugins are only supported through `Bun.build`'s API or through `bunfig.toml` with the frontend dev server - not yet supported in `bun build`'s CLI.
<Warning>
Currently, plugins are only supported through `Bun.build`'s API or through `bunfig.toml` with the frontend dev server
- not yet supported in `bun build`'s CLI.
</Warning>
### Watch Mode
You can run `bun build --watch` to watch for changes and rebuild automatically. This works nicely for library development.
You've never seen a watch mode this fast.
<Info>You've never seen a watch mode this fast.</Info>
### Plugin API
## Plugin API
Need more control? Configure the bundler through the JavaScript API and use Bun's builtin `HTMLRewriter` to preprocess HTML.
```ts
```ts title="build.ts" icon="/icons/typescript.svg"
await Bun.build({
entrypoints: ["./index.html"],
outdir: "./dist",
@@ -322,28 +357,30 @@ await Bun.build({
Bun automatically handles all common web assets:
- Scripts (`<script src>`) are run through Bun's JavaScript/TypeScript/JSX bundler
- Stylesheets (`<link rel="stylesheet">`) are run through Bun's CSS parser & bundler
- Images (`<img>`, `<picture>`) are copied and hashed
- Media (`<video>`, `<audio>`, `<source>`) are copied and hashed
- **Scripts** (`<script src>`) are run through Bun's JavaScript/TypeScript/JSX bundler
- **Stylesheets** (`<link rel="stylesheet">`) are run through Bun's CSS parser & bundler
- **Images** (`<img>`, `<picture>`) are copied and hashed
- **Media** (`<video>`, `<audio>`, `<source>`) are copied and hashed
- Any `<link>` tag with an `href` attribute pointing to a local file is rewritten to the new path, and hashed
All paths are resolved relative to your HTML file, making it easy to organize your project however you want.
## This is a work in progress
<Warning>
**This is a work in progress**
- Need more plugins
- Need more configuration options for things like asset handling
- Need a way to configure CORS, headers, etc.
If you want to submit a PR, most of the [code is here](https://github.com/oven-sh/bun/blob/main/src/js/internal/html.ts). You could even copy paste that file into your project and use it as a starting point.
If you want to submit a PR, most of the code is [here](https://github.com/oven-sh/bun/blob/main/src/bun.js/api/bun/html-rewriter.ts). You could even copy paste that file into your project and use it as a starting point.
</Warning>
## How this works
This is a small wrapper around Bun's support for HTML imports in JavaScript.
### Adding a backend to your frontend
## Adding a backend to your frontend
To add a backend to your frontend, you can use the `"routes"` option in `Bun.serve`.
To add a backend to your frontend, you can use the "routes" option in `Bun.serve`.
Learn more in [the full-stack docs](/docs/bundler/fullstack).
Learn more in the full-stack docs.

File diff suppressed because it is too large Load Diff

1499
docs/bundler/index.mdx Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,75 +0,0 @@
<!-- This document is a work in progress. It's not currently included in the actual docs. -->
The goal of this document is to break down why bundling is necessary, how it works, and how the bundler became such a key part of modern JavaScript development. The content is not specific to Bun's bundler, but is rather aimed at anyone looking for a greater understanding of how bundlers work and, by extension, how most modern frameworks are implemented.
## What is bundling
With the adoption of ECMAScript modules (ESM), browsers can now resolve `import`/`export` statements in JavaScript files loaded via `<script>` tags.
{% codetabs %}
```html#index.html
<html>
<head>
<script type="module" src="/index.js" ></script>
</head>
</html>
```
```js#index.js
import {sayHello} from "./hello.js";
sayHello();
```
```js#hello.js
export function sayHello() {
console.log("Hello, world!");
}
```
{% /codetabs %}
When a user visits this website, the files are loaded in the following order:
{% image src="/images/module_loading_unbundled.png" /%}
{% callout %}
**Relative imports** — Relative imports are resolved relative to the URL of the importing file. Because we're importing `./hello.js` from `/index.js`, the browser resolves it to `/hello.js`. If instead we'd imported `./hello.js` from `/src/index.js`, the browser would have resolved it to `/src/hello.js`.
{% /callout %}
This approach works, it requires three round-trip HTTP requests before the browser is ready to render the page. On slow internet connections, this may add up to a non-trivial delay.
This example is extremely simplistic. A modern app may be loading dozens of modules from `node_modules`, each consisting of hundred of files. Loading each of these files with a separate HTTP request becomes untenable very quickly. While most of these requests will be running in parallel, the number of round-trip requests can still be very high; plus, there are limits on how many simultaneous requests a browser can make.
{% callout %}
Some recent advances like modulepreload and HTTP/3 are intended to solve some of these problems, but at the moment bundling is still the most performant approach.
{% /callout %}
The answer: bundling.
## Entrypoints
A bundler accepts an "entrypoint" to your source code (in this case, `/index.js`) and outputs a single file containing all of the code needed to run your app. If does so by parsing your source code, reading the `import`/`export` statements, and building a "module graph" of your app's dependencies.
{% image src="/images/bundling.png" /%}
We can now load `/bundle.js` from our `index.html` file and eliminate a round trip request, decreasing load times for our app.
{% image src="/images/module_loading_bundled.png" /%}
## Loaders
Bundlers typically have some set of built-in "loaders".
## Transpilation
The JavaScript files above are just that: plain JavaScript. They can be directly executed by any modern browser.
But modern tooling goes far beyond HTML, JavaScript, and CSS. JSX, TypeScript, and PostCSS/CSS-in-JS are all popular technologies that involve non-standard syntax that must be converted into vanilla JavaScript and CSS before if can be consumed by a browser.
## Chunking
## Module resolution
## Plugins

356
docs/bundler/loaders.mdx Normal file
View File

@@ -0,0 +1,356 @@
---
title: Loaders
description: Built-in loaders for the Bun bundler and runtime
---
The Bun bundler implements a set of default loaders out of the box.
> As a rule of thumb: **the bundler and the runtime both support the same set of file types out of the box.**
`.js` `.cjs` `.mjs` `.mts` `.cts` `.ts` `.tsx` `.jsx` `.toml` `.json` `.txt` `.wasm` `.node` `.html`
Bun uses the file extension to determine which built-in loader should be used to parse the file. Every loader has a name, such as `js`, `tsx`, or `json`. These names are used when building plugins that extend Bun with custom loaders.
You can explicitly specify which loader to use using the `'loader'` import attribute.
```ts title="index.ts" icon="/icons/typescript.svg"
import my_toml from "./my_file" with { loader: "toml" };
```
## Built-in loaders
### `js`
**JavaScript loader.** Default for `.cjs` and `.mjs`.
Parses the code and applies a set of default transforms like dead-code elimination and tree shaking. Note that Bun does not attempt to down-convert syntax at the moment.
---
### `jsx`
**JavaScript + JSX loader.** Default for `.js` and `.jsx`.
Same as the `js` loader, but JSX syntax is supported. By default, JSX is down-converted to plain JavaScript; the details of how this is done depends on the `jsx*` compiler options in your `tsconfig.json`. Refer to the [TypeScript documentation on JSX](https://www.typescriptlang.org/tsconfig#jsx) for more information.
---
### `ts`
**TypeScript loader.** Default for `.ts`, `.mts`, and `.cts`.
Strips out all TypeScript syntax, then behaves identically to the `js` loader. Bun does not perform typechecking.
---
### `tsx`
**TypeScript + JSX loader.** Default for `.tsx`.
Transpiles both TypeScript and JSX to vanilla JavaScript.
---
### `json`
**JSON loader.** Default for `.json`.
JSON files can be directly imported.
```js
import pkg from "./package.json";
pkg.name; // => "my-package"
```
During bundling, the parsed JSON is inlined into the bundle as a JavaScript object.
```js
const pkg = {
name: "my-package",
// ... other fields
};
pkg.name;
```
If a `.json` file is passed as an entrypoint to the bundler, it will be converted to a `.js` module that `export default`s the parsed object.
<CodeGroup>
```json Input
{
"name": "John Doe",
"age": 35,
"email": "johndoe@example.com"
}
```
```ts Output
export default {
name: "John Doe",
age: 35,
email: "johndoe@example.com",
};
```
</CodeGroup>
---
### toml
**TOML loader.** Default for `.toml`.
TOML files can be directly imported. Bun will parse them with its fast native TOML parser.
```js
import config from "./bunfig.toml";
config.logLevel; // => "debug"
// via import attribute:
// import myCustomTOML from './my.config' with {type: "toml"};
```
During bundling, the parsed TOML is inlined into the bundle as a JavaScript object.
```js
var config = {
logLevel: "debug",
// ...other fields
};
config.logLevel;
```
If a `.toml` file is passed as an entrypoint, it will be converted to a `.js` module that `export default`s the parsed object.
<CodeGroup>
```toml Input
name = "John Doe"
age = 35
email = "johndoe@example.com"
```
```ts Output
export default {
name: "John Doe",
age: 35,
email: "johndoe@example.com",
};
```
</CodeGroup>
---
### text
**Text loader.** Default for `.txt`.
The contents of the text file are read and inlined into the bundle as a string. Text files can be directly imported. The file is read and returned as a string.
```js
import contents from "./file.txt";
console.log(contents); // => "Hello, world!"
// To import an html file as text
// The "type" attribute can be used to override the default loader.
import html from "./index.html" with { type: "text" };
```
When referenced during a build, the contents are inlined into the bundle as a string.
```js
var contents = `Hello, world!`;
console.log(contents);
```
If a `.txt` file is passed as an entrypoint, it will be converted to a `.js` module that `export default`s the file contents.
<CodeGroup>
```txt Input
Hello, world!
```
```ts Output
export default "Hello, world!";
```
</CodeGroup>
---
### napi
**Native addon loader.** Default for `.node`.
In the runtime, native addons can be directly imported.
```js
import addon from "./addon.node";
console.log(addon);
```
<Note>In the bundler, `.node` files are handled using the file loader.</Note>
---
### sqlite
**SQLite loader.** Requires `with { "type": "sqlite" }` import attribute.
In the runtime and bundler, SQLite databases can be directly imported. This will load the database using `bun:sqlite`.
```js
import db from "./my.db" with { type: "sqlite" };
```
<Warning>This is only supported when the target is `bun`.</Warning>
By default, the database is external to the bundle (so that you can potentially use a database loaded elsewhere), so the database file on-disk won't be bundled into the final output.
You can change this behavior with the `"embed"` attribute:
```js
// embed the database into the bundle
import db from "./my.db" with { type: "sqlite", embed: "true" };
```
<Info>
When using a standalone executable, the database is embedded into the single-file executable.
Otherwise, the database to embed is copied into the `outdir` with a hashed filename.
</Info>
---
### html
The `html` loader processes HTML files and bundles any referenced assets. It will:
- Bundle and hash referenced JavaScript files (`<script src="...">`)
- Bundle and hash referenced CSS files (`<link rel="stylesheet" href="...">`)
- Hash referenced images (`<img src="...">`)
- Preserve external URLs (by default, anything starting with `http://` or `https://`)
For example, given this HTML file:
```html title="src/index.html"
<!DOCTYPE html>
<html>
<body>
<img src="./image.jpg" alt="Local image" />
<img src="https://example.com/image.jpg" alt="External image" />
<script type="module" src="./script.js"></script>
</body>
</html>
```
It will output a new HTML file with the bundled assets:
```html title="dist/index.html"
<!DOCTYPE html>
<html>
<body>
<img src="./image-HASHED.jpg" alt="Local image" />
<img src="https://example.com/image.jpg" alt="External image" />
<script type="module" src="./output-ALSO-HASHED.js"></script>
</body>
</html>
```
Under the hood, it uses [`lol-html`](https://github.com/cloudflare/lol-html) to extract script and link tags as entrypoints, and other assets as external.
<Accordion title="List of supported HTML selectors">
Currently, the list of selectors is:
- `audio[src]`
- `iframe[src]`
- `img[src]`
- `img[srcset]`
- `link:not([rel~='stylesheet']):not([rel~='modulepreload']):not([rel~='manifest']):not([rel~='icon']):not([rel~='apple-touch-icon'])[href]`
- `link[as='font'][href], link[type^='font/'][href]`
- `link[as='image'][href]`
- `link[as='style'][href]`
- `link[as='video'][href], link[as='audio'][href]`
- `link[as='worker'][href]`
- `link[rel='icon'][href], link[rel='apple-touch-icon'][href]`
- `link[rel='manifest'][href]`
- `link[rel='stylesheet'][href]`
- `script[src]`
- `source[src]`
- `source[srcset]`
- `video[poster]`
- `video[src]`
</Accordion>
<Note>
**HTML Loader Behavior in Different Contexts**
The `html` loader behaves differently depending on how it's used:
- Static Build: When you run `bun build ./index.html`, Bun produces a static site with all assets bundled and hashed.
- Runtime: When you run `bun run server.ts` (where `server.ts` imports an HTML file), Bun bundles assets on-the-fly during development, enabling features like hot module replacement.
- Full-stack Build: When you run `bun build --target=bun server.ts` (where `server.ts` imports an HTML file), the import resolves to a manifest object that `Bun.serve` uses to efficiently serve pre-bundled assets in production.
</Note>
---
### sh
**Bun Shell loader.** Default for `.sh` files.
This loader is used to parse Bun Shell scripts. It's only supported when starting Bun itself, so it's not available in the bundler or in the runtime.
```bash
bun run ./script.sh
```
---
### file
**File loader.** Default for all unrecognized file types.
The file loader resolves the import as a path/URL to the imported file. It's commonly used for referencing media or font assets.
```js
// logo.ts
import logo from "./logo.svg";
console.log(logo);
```
In the runtime, Bun checks that the `logo.svg` file exists and converts it to an absolute path to the location of `logo.svg` on disk.
```bash
bun run logo.ts
# Output: /path/to/project/logo.svg
```
In the bundler, things are slightly different. The file is copied into `outdir` as-is, and the import is resolved as a relative path pointing to the copied file.
```js
// Output
var logo = "./logo.svg";
console.log(logo);
```
If a value is specified for `publicPath`, the import will use value as a prefix to construct an absolute path/URL.
| Public path | Resolved import |
| ---------------------------- | ---------------------------------- |
| `""` (default) | `/logo.svg` |
| `"/assets"` | `/assets/logo.svg` |
| `"https://cdn.example.com/"` | `https://cdn.example.com/logo.svg` |
<Note>
The location and file name of the copied file is determined by the value of `naming.asset`.
This loader is copied into the `outdir` as-is. The name of the copied file is determined using the value of `naming.asset`.
</Note>

View File

@@ -1,10 +1,13 @@
Macros are a mechanism for running JavaScript functions _at bundle-time_. The value returned from these functions are directly inlined into your bundle.
---
title: Macros
description: Run JavaScript functions at bundle-time with Bun macros
---
<!-- embed the result in your (browser) bundle. This is useful for things like embedding the current Git commit hash in your code, making fetch requests to your API at build-time, dead code elimination, and more. -->
Macros are a mechanism for running JavaScript functions at bundle-time. The value returned from these functions are directly inlined into your bundle.
As a toy example, consider this simple function that returns a random number.
```ts
```ts title="random.ts" icon="/icons/typescript.svg"
export function random() {
return Math.random();
}
@@ -12,24 +15,28 @@ export function random() {
This is just a regular function in a regular file, but we can use it as a macro like so:
```ts#cli.tsx
import { random } from './random.ts' with { type: 'macro' };
```tsx title="cli.tsx" icon="/icons/typescript.svg"
import { random } from "./random.ts" with { type: "macro" };
console.log(`Your random number is ${random()}`);
```
{% callout %}
**Note** — Macros are indicated using [_import attribute_](https://github.com/tc39/proposal-import-attributes) syntax. If you haven't seen this syntax before, it's a Stage 3 TC39 proposal that lets you attach additional metadata to `import` statements.
{% /callout %}
<Note>
Macros are indicated using import attribute syntax. If you haven't seen this syntax before, it's a Stage 3 TC39
proposal that lets you attach additional metadata to import statements.
</Note>
Now we'll bundle this file with `bun build`. The bundled file will be printed to stdout.
```bash
$ bun build ./cli.tsx
```bash terminal icon="terminal"
bun build ./cli.tsx
```
```js
console.log(`Your random number is ${0.6805550949689833}`);
```
As you can see, the source code of the `random` function occurs nowhere in the bundle. Instead, it is executed _during bundling_ and function call (`random()`) is replaced with the result of the function. Since the source code will never be included in the bundle, macros can safely perform privileged operations like reading from a database.
As you can see, the source code of the `random` function occurs nowhere in the bundle. Instead, it is executed during bundling and function call (`random()`) is replaced with the result of the function. Since the source code will never be included in the bundle, macros can safely perform privileged operations like reading from a database.
## When to use macros
@@ -41,8 +48,8 @@ If you find yourself running a lot of code at bundle-time though, consider runni
Bun Macros are import statements annotated using either:
- `with { type: 'macro' }` — an [import attribute](https://github.com/tc39/proposal-import-attributes), a Stage 3 ECMA Scrd
- `assert { type: 'macro' }` — an import assertion, an earlier incarnation of import attributes that has now been abandoned (but is [already supported](https://caniuse.com/mdn-javascript_statements_import_import_assertions) by a number of browsers and runtimes)
- `with { type: 'macro' }` — an import attribute, a Stage 3 ECMA Script proposal
- `assert { type: 'macro' }` — an import assertion, an earlier incarnation of import attributes that has now been abandoned (but is already supported by a number of browsers and runtimes)
## Security considerations
@@ -50,7 +57,7 @@ Macros must explicitly be imported with `{ type: "macro" }` in order to be execu
You can disable macros entirely by passing the `--no-macros` flag to Bun. It produces a build error like this:
```js
```
error: Macros are disabled
foo();
@@ -58,9 +65,9 @@ foo();
./hello.js:3:1 53
```
To reduce the potential attack surface for malicious packages, macros cannot be _invoked_ from inside `node_modules/**/*`. If a package attempts to invoke a macro, you'll see an error like this:
To reduce the potential attack surface for malicious packages, macros cannot be invoked from inside `node_modules/**/*`. If a package attempts to invoke a macro, you'll see an error like this:
```js
```
error: For security reasons, macros cannot be run from node_modules.
beEvil();
@@ -70,17 +77,17 @@ node_modules/evil/index.js:3:1 50
Your application code can still import macros from `node_modules` and invoke them.
```ts
```ts title="cli.tsx" icon="/icons/typescript.svg"
import { macro } from "some-package" with { type: "macro" };
macro();
```
## Export condition `"macro"`
## Export condition "macro"
When shipping a library containing a macro to `npm` or another package registry, use the `"macro"` [export condition](https://nodejs.org/api/packages.html#conditional-exports) to provide a special version of your package exclusively for the macro environment.
When shipping a library containing a macro to npm or another package registry, use the `"macro"` export condition to provide a special version of your package exclusively for the macro environment.
```jsonc#package.json
```json title="package.json" icon="file-code"
{
"name": "my-package",
"exports": {
@@ -94,7 +101,7 @@ When shipping a library containing a macro to `npm` or another package registry,
With this configuration, users can consume your package at runtime or at bundle-time using the same import specifier:
```ts
```ts title="index.ts" icon="/icons/typescript.svg"
import pkg from "my-package"; // runtime import
import { macro } from "my-package" with { type: "macro" }; // macro import
```
@@ -105,15 +112,15 @@ The first import will resolve to `./node_modules/my-package/index.js`, while the
When Bun's transpiler sees a macro import, it calls the function inside the transpiler using Bun's JavaScript runtime and converts the return value from JavaScript into an AST node. These JavaScript functions are called at bundle-time, not runtime.
Macros are executed synchronously in the transpiler during the visiting phase—before plugins and before the transpiler generates the AST. They are executed in the order they are imported. The transpiler will wait for the macro to finish executing before continuing. The transpiler will also `await` any `Promise` returned by a macro.
Macros are executed synchronously in the transpiler during the visiting phase—before plugins and before the transpiler generates the AST. They are executed in the order they are imported. The transpiler will wait for the macro to finish executing before continuing. The transpiler will also await any Promise returned by a macro.
Bun's bundler is multi-threaded. As such, macros execute in parallel inside of multiple spawned JavaScript "workers".
## Dead code elimination
The bundler performs dead code elimination _after_ running and inlining macros. So given the following macro:
The bundler performs dead code elimination after running and inlining macros. So given the following macro:
```ts#returnFalse.ts
```ts title="returnFalse.ts" icon="/icons/typescript.svg"
export function returnFalse() {
return false;
}
@@ -121,7 +128,7 @@ export function returnFalse() {
...then bundling the following file will produce an empty bundle, provided that the minify syntax option is enabled.
```ts
```ts title="index.ts" icon="/icons/typescript.svg"
import { returnFalse } from "./returnFalse.ts" with { type: "macro" };
if (returnFalse()) {
@@ -133,19 +140,19 @@ if (returnFalse()) {
Bun's transpiler needs to be able to serialize the result of the macro so it can be inlined into the AST. All JSON-compatible data structures are supported:
```ts#macro.ts
```ts title="macro.ts" icon="/icons/typescript.svg"
export function getObject() {
return {
foo: "bar",
baz: 123,
array: [ 1, 2, { nested: "value" }],
array: [1, 2, { nested: "value" }],
};
}
```
Macros can be async, or return `Promise` instances. Bun's transpiler will automatically `await` the `Promise` and inline the result.
Macros can be async, or return Promise instances. Bun's transpiler will automatically await the Promise and inline the result.
```ts#macro.ts
```ts title="macro.ts" icon="/icons/typescript.svg"
export async function getText() {
return "async value";
}
@@ -153,21 +160,21 @@ export async function getText() {
The transpiler implements special logic for serializing common data formats like `Response`, `Blob`, `TypedArray`.
- `TypedArray`: Resolves to a base64-encoded string.
- `Response`: Bun will read the `Content-Type` and serialize accordingly; for instance, a `Response` with type `application/json` will be automatically parsed into an object and `text/plain` will be inlined as a string. Responses with an unrecognized or `undefined` `type` will be base-64 encoded.
- `Blob`: As with `Response`, the serialization depends on the `type` property.
- **TypedArray**: Resolves to a base64-encoded string.
- **Response**: Bun will read the `Content-Type` and serialize accordingly; for instance, a Response with type `application/json` will be automatically parsed into an object and `text/plain` will be inlined as a string. Responses with an unrecognized or undefined type will be base-64 encoded.
- **Blob**: As with Response, the serialization depends on the `type` property.
The result of `fetch` is `Promise<Response>`, so it can be directly returned.
```ts#macro.ts
```ts title="macro.ts" icon="/icons/typescript.svg"
export function getObject() {
return fetch("https://bun.com")
return fetch("https://bun.com");
}
```
Functions and instances of most classes (except those mentioned above) are not serializable.
```ts
```ts title="macro.ts" icon="/icons/typescript.svg"
export function getText(url: string) {
// this doesn't work!
return () => {};
@@ -178,7 +185,7 @@ export function getText(url: string) {
Macros can accept inputs, but only in limited cases. The value must be statically known. For example, the following is not allowed:
```ts
```ts title="index.ts" icon="/icons/typescript.svg"
import { getText } from "./getText.ts" with { type: "macro" };
export function howLong() {
@@ -192,7 +199,7 @@ export function howLong() {
However, if the value of `foo` is known at bundle-time (say, if it's a constant or the result of another macro) then it's allowed:
```ts
```ts title="index.ts" icon="/icons/typescript.svg"
import { getText } from "./getText.ts" with { type: "macro" };
import { getFoo } from "./getFoo.ts" with { type: "macro" };
@@ -206,7 +213,7 @@ export function howLong() {
This outputs:
```ts
```js
function howLong() {
console.log("The page is", 1322, "characters long");
}
@@ -217,11 +224,9 @@ export { howLong };
### Embed latest git commit hash
{% codetabs %}
```ts#getGitCommitHash.ts
```ts title="getGitCommitHash.ts" icon="/icons/typescript.svg"
export function getGitCommitHash() {
const {stdout} = Bun.spawnSync({
const { stdout } = Bun.spawnSync({
cmd: ["git", "rev-parse", "HEAD"],
stdout: "pipe",
});
@@ -230,33 +235,32 @@ export function getGitCommitHash() {
}
```
{% /codetabs %}
<!-- --target=browser so they can clearly see it's for browsers -->
When we build it, the `getGitCommitHash` is replaced with the result of calling the function:
{% codetabs %}
<CodeGroup>
```ts#input
import { getGitCommitHash } from './getGitCommitHash.ts' with { type: 'macro' };
```ts input
import { getGitCommitHash } from "./getGitCommitHash.ts" with { type: "macro" };
console.log(`The current Git commit hash is ${getGitCommitHash()}`);
```
```bash#output
console.log(`The current Git commit hash is 3ee3259104f`);
```ts output
console.log(`The current Git commit hash is 3ee3259104e4507cf62c160f0ff5357ec4c7a7f8`);
```
{% /codetabs %}
</CodeGroup>
You're probably thinking "Why not just use `process.env.GIT_COMMIT_HASH`?" Well, you can do that too. But can you do this with an environment variable?
<Info>
You're probably thinking "Why not just use `process.env.GIT_COMMIT_HASH`?" Well, you can do that too. But can you do
this with an environment variable?
</Info>
### Make `fetch()` requests at bundle-time
### Make fetch() requests at bundle-time
In this example, we make an outgoing HTTP request using `fetch()`, parse the HTML response using `HTMLRewriter`, and return an object containing the title and meta tagsall at bundle-time.
```ts
```ts title="meta.ts" icon="/icons/typescript.svg"
export async function extractMetaTags(url: string) {
const response = await fetch(url);
const meta = {
@@ -271,9 +275,7 @@ export async function extractMetaTags(url: string) {
.on("meta", {
element(element) {
const name =
element.getAttribute("name") ||
element.getAttribute("property") ||
element.getAttribute("itemprop");
element.getAttribute("name") || element.getAttribute("property") || element.getAttribute("itemprop");
if (name) meta[name] = element.getAttribute("content");
},
@@ -284,14 +286,12 @@ export async function extractMetaTags(url: string) {
}
```
<!-- --target=browser so they can clearly see it's for browsers -->
The `extractMetaTags` function is erased at bundle-time and replaced with the result of the function call. This means that the fetch request happens at bundle-time, and the result is embedded in the bundle. Also, the branch throwing the error is eliminated since it's unreachable.
The `extractMetaTags` function is erased at bundle-time and replaced with the result of the function call. This means that the `fetch` request happens at bundle-time, and the result is embedded in the bundle. Also, the branch throwing the error is eliminated since it's unreachable.
<CodeGroup>
{% codetabs %}
```ts#input
import { extractMetaTags } from './meta.ts' with { type: 'macro' };
```jsx input
import { extractMetaTags } from "./meta.ts" with { type: "macro" };
export const Head = () => {
const headTags = extractMetaTags("https://example.com");
@@ -300,30 +300,29 @@ export const Head = () => {
throw new Error("Expected title to be 'Example Domain'");
}
return <head>
<title>{headTags.title}</title>
<meta name="viewport" content={headTags.viewport} />
</head>;
return (
<head>
<title>{headTags.title}</title>
<meta name="viewport" content={headTags.viewport} />
</head>
);
};
```
```ts#output
import { jsx, jsxs } from "react/jsx-runtime";
```jsx output
export const Head = () => {
jsxs("head", {
children: [
jsx("title", {
children: "Example Domain",
}),
jsx("meta", {
name: "viewport",
content: "width=device-width, initial-scale=1",
}),
],
});
};
const headTags = {
title: "Example Domain",
viewport: "width=device-width, initial-scale=1",
};
export { Head };
return (
<head>
<title>{headTags.title}</title>
<meta name="viewport" content={headTags.viewport} />
</head>
);
};
```
{% /codetabs %}
</CodeGroup>

1306
docs/bundler/minifier.mdx Normal file

File diff suppressed because it is too large Load Diff

411
docs/bundler/plugins.mdx Normal file
View File

@@ -0,0 +1,411 @@
---
title: Plugins
description: Universal plugin API for extending Bun's runtime and bundler
---
Bun provides a universal plugin API that can be used to extend both the runtime and bundler.
Plugins intercept imports and perform custom loading logic: reading files, transpiling code, etc. They can be used to add support for additional file types, like `.scss` or `.yaml`. In the context of Bun's bundler, plugins can be used to implement framework-level features like CSS extraction, macros, and client-server code co-location.
## Lifecycle hooks
Plugins can register callbacks to be run at various points in the lifecycle of a bundle:
- `onStart()`: Run once the bundler has started a bundle
- `onResolve()`: Run before a module is resolved
- `onLoad()`: Run before a module is loaded
- `onBeforeParse()`: Run zero-copy native addons in the parser thread before a file is parsed
## Reference
A rough overview of the types (please refer to Bun's `bun.d.ts` for the full type definitions):
```ts title="bun.d.ts" icon="/icons/typescript.svg"
type PluginBuilder = {
onStart(callback: () => void): void;
onResolve: (
args: { filter: RegExp; namespace?: string },
callback: (args: { path: string; importer: string }) => {
path: string;
namespace?: string;
} | void,
) => void;
onLoad: (
args: { filter: RegExp; namespace?: string },
defer: () => Promise<void>,
callback: (args: { path: string }) => {
loader?: Loader;
contents?: string;
exports?: Record<string, any>;
},
) => void;
config: BuildConfig;
};
type Loader = "js" | "jsx" | "ts" | "tsx" | "css" | "json" | "toml";
```
## Usage
A plugin is defined as simple JavaScript object containing a `name` property and a `setup` function.
```ts title="myPlugin.ts" icon="/icons/typescript.svg"
import type { BunPlugin } from "bun";
const myPlugin: BunPlugin = {
name: "Custom loader",
setup(build) {
// implementation
},
};
```
This plugin can be passed into the `plugins` array when calling `Bun.build`.
```ts title="index.ts" icon="/icons/typescript.svg"
await Bun.build({
entrypoints: ["./app.ts"],
outdir: "./out",
plugins: [myPlugin],
});
```
## Plugin lifecycle
### Namespaces
`onLoad` and `onResolve` accept an optional `namespace` string. What is a namespace?
Every module has a namespace. Namespaces are used to prefix the import in transpiled code; for instance, a loader with a `filter: /\.yaml$/` and `namespace: "yaml:"` will transform an import from `./myfile.yaml` into `yaml:./myfile.yaml`.
The default namespace is `"file"` and it is not necessary to specify it, for instance: `import myModule from "./my-module.ts"` is the same as `import myModule from "file:./my-module.ts"`.
Other common namespaces are:
- `"bun"`: for Bun-specific modules (e.g. `"bun:test"`, `"bun:sqlite"`)
- `"node"`: for Node.js modules (e.g. `"node:fs"`, `"node:path"`)
### onStart
```ts
onStart(callback: () => void): Promise<void> | void;
```
Registers a callback to be run when the bundler starts a new bundle.
```ts title="index.ts" icon="/icons/typescript.svg"
import { plugin } from "bun";
plugin({
name: "onStart example",
setup(build) {
build.onStart(() => {
console.log("Bundle started!");
});
},
});
```
The callback can return a Promise. After the bundle process has initialized, the bundler waits until all `onStart()` callbacks have completed before continuing.
For example:
```ts title="index.ts" icon="/icons/typescript.svg"
const result = await Bun.build({
entrypoints: ["./app.ts"],
outdir: "./dist",
sourcemap: "external",
plugins: [
{
name: "Sleep for 10 seconds",
setup(build) {
build.onStart(async () => {
await Bun.sleep(10_000);
});
},
},
{
name: "Log bundle time to a file",
setup(build) {
build.onStart(async () => {
const now = Date.now();
await Bun.$`echo ${now} > bundle-time.txt`;
});
},
},
],
});
```
In the above example, Bun will wait until the first `onStart()` (sleeping for 10 seconds) has completed, as well as the second `onStart()` (writing the bundle time to a file).
<Note>
`onStart()` callbacks (like every other lifecycle callback) do not have the ability to modify the `build.config`
object. If you want to mutate `build.config`, you must do so directly in the `setup()` function.
</Note>
### onResolve
```ts
onResolve(
args: { filter: RegExp; namespace?: string },
callback: (args: { path: string; importer: string }) => {
path: string;
namespace?: string;
} | void,
): void;
```
To bundle your project, Bun walks down the dependency tree of all modules in your project. For each imported module, Bun actually has to find and read that module. The "finding" part is known as "resolving" a module.
The `onResolve()` plugin lifecycle callback allows you to configure how a module is resolved.
The first argument to `onResolve()` is an object with a `filter` and `namespace` property. The `filter` is a regular expression which is run on the import string. Effectively, these allow you to filter which modules your custom resolution logic will apply to.
The second argument to `onResolve()` is a callback which is run for each module import Bun finds that matches the filter and namespace defined in the first argument.
The callback receives as input the path to the matching module. The callback can return a new path for the module. Bun will read the contents of the new path and parse it as a module.
For example, redirecting all imports to `images/` to `./public/images/`:
```ts title="index.ts" icon="/icons/typescript.svg"
import { plugin } from "bun";
plugin({
name: "onResolve example",
setup(build) {
build.onResolve({ filter: /.*/, namespace: "file" }, args => {
if (args.path.startsWith("images/")) {
return {
path: args.path.replace("images/", "./public/images/"),
};
}
});
},
});
```
### onLoad
```ts
onLoad(
args: { filter: RegExp; namespace?: string },
defer: () => Promise<void>,
callback: (args: { path: string, importer: string, namespace: string, kind: ImportKind }) => {
loader?: Loader;
contents?: string;
exports?: Record<string, any>;
},
): void;
```
After Bun's bundler has resolved a module, it needs to read the contents of the module and parse it.
The `onLoad()` plugin lifecycle callback allows you to modify the contents of a module before it is read and parsed by Bun.
Like `onResolve()`, the first argument to `onLoad()` allows you to filter which modules this invocation of `onLoad()` will apply to.
The second argument to `onLoad()` is a callback which is run for each matching module before Bun loads the contents of the module into memory.
This callback receives as input the path to the matching module, the importer of the module (the module that imported the module), the namespace of the module, and the kind of the module.
The callback can return a new `contents` string for the module as well as a new `loader`.
For example:
```ts title="index.ts" icon="/icons/typescript.svg"
import { plugin } from "bun";
const envPlugin: BunPlugin = {
name: "env plugin",
setup(build) {
build.onLoad({ filter: /env/, namespace: "file" }, args => {
return {
contents: `export default ${JSON.stringify(process.env)}`,
loader: "js",
};
});
},
});
Bun.build({
entrypoints: ["./app.ts"],
outdir: "./dist",
plugins: [envPlugin],
});
// import env from "env"
// env.FOO === "bar"
```
This plugin will transform all imports of the form `import env from "env"` into a JavaScript module that exports the current environment variables.
#### .defer()
One of the arguments passed to the `onLoad` callback is a `defer` function. This function returns a Promise that is resolved when all other modules have been loaded.
This allows you to delay execution of the `onLoad` callback until all other modules have been loaded.
This is useful for returning contents of a module that depends on other modules.
<Accordion title="Example: tracking and reporting unused exports">
```ts title="index.ts" icon="/icons/typescript.svg"
import { plugin } from "bun";
plugin({
name: "track imports",
setup(build) {
const transpiler = new Bun.Transpiler();
let trackedImports: Record<string, number> = {};
// Each module that goes through this onLoad callback
// will record its imports in `trackedImports`
build.onLoad({ filter: /\.ts/ }, async ({ path }) => {
const contents = await Bun.file(path).arrayBuffer();
const imports = transpiler.scanImports(contents);
for (const i of imports) {
trackedImports[i.path] = (trackedImports[i.path] || 0) + 1;
}
return undefined;
});
build.onLoad({ filter: /stats\.json/ }, async ({ defer }) => {
// Wait for all files to be loaded, ensuring
// that every file goes through the above `onLoad()` function
// and their imports tracked
await defer();
// Emit JSON containing the stats of each import
return {
contents: `export default ${JSON.stringify(trackedImports)}`,
loader: "json",
};
});
},
});
```
</Accordion>
<Warning>
The `.defer()` function currently has the limitation that it can only be called once per `onLoad` callback.
</Warning>
## Native plugins
One of the reasons why Bun's bundler is so fast is that it is written in native code and leverages multi-threading to load and parse modules in parallel.
However, one limitation of plugins written in JavaScript is that JavaScript itself is single-threaded.
Native plugins are written as NAPI modules and can be run on multiple threads. This allows native plugins to run much faster than JavaScript plugins.
In addition, native plugins can skip unnecessary work such as the UTF-8 -> UTF-16 conversion needed to pass strings to JavaScript.
These are the following lifecycle hooks which are available to native plugins:
- `onBeforeParse()`: Called on any thread before a file is parsed by Bun's bundler.
Native plugins are NAPI modules which expose lifecycle hooks as C ABI functions.
To create a native plugin, you must export a C ABI function which matches the signature of the native lifecycle hook you want to implement.
### Creating a native plugin in Rust
Native plugins are NAPI modules which expose lifecycle hooks as C ABI functions.
To create a native plugin, you must export a C ABI function which matches the signature of the native lifecycle hook you want to implement.
```bash terminal icon="terminal"
bun add -g @napi-rs/cli
napi new
```
Then install this crate:
```bash terminal icon="terminal"
cargo add bun-native-plugin
```
Now, inside the `lib.rs` file, we'll use the `bun_native_plugin::bun` proc macro to define a function which will implement our native plugin.
Here's an example implementing the `onBeforeParse` hook:
```rust title="lib.rs" icon="/icons/rust.svg"
use bun_native_plugin::{define_bun_plugin, OnBeforeParse, bun, Result, anyhow, BunLoader};
use napi_derive::napi;
/// Define the plugin and its name
define_bun_plugin!("replace-foo-with-bar");
/// Here we'll implement `onBeforeParse` with code that replaces all occurrences of
/// `foo` with `bar`.
///
/// We use the #[bun] macro to generate some of the boilerplate code.
///
/// The argument of the function (`handle: &mut OnBeforeParse`) tells
/// the macro that this function implements the `onBeforeParse` hook.
#[bun]
pub fn replace_foo_with_bar(handle: &mut OnBeforeParse) -> Result<()> {
// Fetch the input source code.
let input_source_code = handle.input_source_code()?;
// Get the Loader for the file
let loader = handle.output_loader();
let output_source_code = input_source_code.replace("foo", "bar");
handle.set_output_source_code(output_source_code, BunLoader::BUN_LOADER_JSX);
Ok(())
}
```
And to use it in `Bun.build()`:
```ts title="index.ts" icon="/icons/typescript.svg"
import myNativeAddon from "./my-native-addon";
Bun.build({
entrypoints: ["./app.tsx"],
plugins: [
{
name: "my-plugin",
setup(build) {
build.onBeforeParse(
{
namespace: "file",
filter: "**/*.tsx",
},
{
napiModule: myNativeAddon,
symbol: "replace_foo_with_bar",
// external: myNativeAddon.getSharedState()
},
);
},
},
],
});
```
### onBeforeParse
```ts
onBeforeParse(
args: { filter: RegExp; namespace?: string },
callback: { napiModule: NapiModule; symbol: string; external?: unknown },
): void;
```
This lifecycle callback is run immediately before a file is parsed by Bun's bundler.
As input, it receives the file's contents and can optionally return new source code.
<Info>This callback can be called from any thread and so the napi module implementation must be thread-safe.</Info>

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +0,0 @@
This command installs completions for `zsh` and/or `fish`. It runs automatically on every `bun upgrade` and on install. It reads from `$SHELL` to determine which shell to install for. It tries several common shell completion directories for your shell and OS.
If you want to copy the completions manually, run `bun completions > path-to-file`. If you know the completions directory to install them to, run `bun completions /path/to/directory`.

View File

@@ -1,349 +0,0 @@
### `bun install`
bun install is a fast package manager & npm client.
bun install can be configured via `bunfig.toml`, environment variables, and CLI flags.
#### Configuring `bun install` with `bunfig.toml`
`bunfig.toml` is searched for in the following paths on `bun install`, `bun remove`, and `bun add`:
1. `$XDG_CONFIG_HOME/.bunfig.toml` or `$HOME/.bunfig.toml`
2. `./bunfig.toml`
If both are found, the results are merged together.
Configuring with `bunfig.toml` is optional. Bun tries to be zero configuration in general, but that's not always possible.
```toml
# Using scoped packages with bun install
[install.scopes]
# Scope name The value can be a URL string or an object
"@mybigcompany" = { token = "123456", url = "https://registry.mybigcompany.com" }
# URL is optional and falls back to the default registry
# The "@" in the scope is optional
mybigcompany2 = { token = "123456" }
# Environment variables can be referenced as a string that starts with $ and it will be replaced
mybigcompany3 = { token = "$npm_config_token" }
# Setting username and password turns it into a Basic Auth header by taking base64("username:password")
mybigcompany4 = { username = "myusername", password = "$npm_config_password", url = "https://registry.yarnpkg.com/" }
# You can set username and password in the registry URL. This is the same as above.
mybigcompany5 = "https://username:password@registry.yarnpkg.com/"
# You can set a token for a registry URL:
mybigcompany6 = "https://:$NPM_CONFIG_TOKEN@registry.yarnpkg.com/"
[install]
# Default registry
# can be a URL string or an object
registry = "https://registry.yarnpkg.com/"
# as an object
#registry = { url = "https://registry.yarnpkg.com/", token = "123456" }
# Install for production? This is the equivalent to the "--production" CLI argument
production = false
# Save a text-based lockfile? This is equivalent to the "--save-text-lockfile" CLI argument
saveTextLockfile = false
# Disallow changes to lockfile? This is the equivalent to the "--frozen-lockfile" CLI argument
frozenLockfile = false
# Don't actually install
dryRun = true
# Install optionalDependencies (default: true)
# Setting this to false is equivalent to the `--omit=optional` CLI argument
optional = true
# Install local devDependencies (default: true)
# Setting this to false is equivalent to the `--omit=dev` CLI argument
dev = true
# Install peerDependencies (default: true)
# Setting this to false is equivalent to the `--omit=peer` CLI argument
peer = true
# Max number of concurrent lifecycle scripts (default: (cpu count or GOMAXPROCS) x2)
concurrentScripts = 16
# When using `bun install -g`, install packages here
globalDir = "~/.bun/install/global"
# When using `bun install -g`, link package bins here
globalBinDir = "~/.bun/bin"
# cache-related configuration
[install.cache]
# The directory to use for the cache
dir = "~/.bun/install/cache"
# Don't load from the global cache.
# Note: Bun may still write to node_modules/.cache
disable = false
# Always resolve the latest versions from the registry
disableManifest = false
# Lockfile-related configuration
[install.lockfile]
# Print a yarn v1 lockfile
# Note: it does not load the lockfile, it just converts bun.lock into a yarn.lock
print = "yarn"
# Save the lockfile to disk
save = true
```
If it's easier to read as TypeScript types:
```ts
export interface Root {
install: Install;
}
export interface Install {
scopes: Scopes;
registry: Registry;
production: boolean;
saveTextLockfile: boolean;
frozenLockfile: boolean;
dryRun: boolean;
optional: boolean;
dev: boolean;
peer: boolean;
globalDir: string;
globalBinDir: string;
cache: Cache;
lockfile: Lockfile;
logLevel: "debug" | "error" | "warn";
}
type Registry =
| string
| {
url?: string;
token?: string;
username?: string;
password?: string;
};
type Scopes = Record<string, Registry>;
export interface Cache {
dir: string;
disable: boolean;
disableManifest: boolean;
}
export interface Lockfile {
print?: "yarn";
save: boolean;
}
```
## Configuring with environment variables
Environment variables have a higher priority than `bunfig.toml`.
| Name | Description |
| -------------------------------- | ------------------------------------------------------------- |
| BUN_CONFIG_REGISTRY | Set an npm registry (default: <https://registry.npmjs.org>) |
| BUN_CONFIG_TOKEN | Set an auth token (currently does nothing) |
| BUN_CONFIG_YARN_LOCKFILE | Save a Yarn v1-style yarn.lock |
| BUN_CONFIG_LINK_NATIVE_BINS | Point `bin` in package.json to a platform-specific dependency |
| BUN_CONFIG_SKIP_SAVE_LOCKFILE | Dont save a lockfile |
| BUN_CONFIG_SKIP_LOAD_LOCKFILE | Dont load a lockfile |
| BUN_CONFIG_SKIP_INSTALL_PACKAGES | Dont install any packages |
Bun always tries to use the fastest available installation method for the target platform. On macOS, thats `clonefile` and on Linux, thats `hardlink`. You can change which installation method is used with the `--backend` flag. When unavailable or on error, `clonefile` and `hardlink` fallsback to a platform-specific implementation of copying files.
Bun stores installed packages from npm in `~/.bun/install/cache/${name}@${version}`. Note that if the semver version has a `build` or a `pre` tag, it is replaced with a hash of that value instead. This is to reduce the chances of errors from long file paths, but unfortunately complicates figuring out where a package was installed on disk.
When the `node_modules` folder exists, before installing, Bun checks if the `"name"` and `"version"` in `package/package.json` in the expected node_modules folder matches the expected `name` and `version`. This is how it determines whether it should install. It uses a custom JSON parser which stops parsing as soon as it finds `"name"` and `"version"`.
When a `bun.lock` doesnt exist or `package.json` has changed dependencies, tarballs are downloaded & extracted eagerly while resolving.
When a `bun.lock` exists and `package.json` hasnt changed, Bun downloads missing dependencies lazily. If the package with a matching `name` & `version` already exists in the expected location within `node_modules`, Bun wont attempt to download the tarball.
## Platform-specific dependencies?
bun stores normalized `cpu` and `os` values from npm in the lockfile, along with the resolved packages. It skips downloading, extracting, and installing packages disabled for the current target at runtime. This means the lockfile won't change between platforms/architectures even if the packages ultimately installed do change.
### `--cpu` and `--os` flags
You can override the target platform for package selection:
```bash
bun install --cpu=x64 --os=linux
```
This installs packages for the specified platform instead of the current system. Useful for cross-platform builds or when preparing deployments for different environments.
**Accepted values for `--cpu`**: `arm64`, `x64`, `ia32`, `ppc64`, `s390x`
**Accepted values for `--os`**: `linux`, `darwin`, `win32`, `freebsd`, `openbsd`, `sunos`, `aix`
## Peer dependencies?
Peer dependencies are handled similarly to yarn. `bun install` will automatically install peer dependencies. If the dependency is marked optional in `peerDependenciesMeta`, an existing dependency will be chosen if possible.
## Lockfile
`bun.lock` is Buns lockfile format. See [our blogpost about the text lockfile](https://bun.com/blog/bun-lock-text-lockfile).
Prior to Bun 1.2, the lockfile was binary and called `bun.lockb`. Old lockfiles can be upgraded to the new format by running `bun install --save-text-lockfile --frozen-lockfile --lockfile-only`, and then deleting `bun.lockb`.
## Cache
To delete the cache:
```bash
$ rm -rf ~/.bun/install/cache
```
## Platform-specific backends
`bun install` uses different system calls to install dependencies depending on the platform. This is a performance optimization. You can force a specific backend with the `--backend` flag.
**`hardlink`** is the default backend on Linux. Benchmarking showed it to be the fastest on Linux.
```bash
$ rm -rf node_modules
$ bun install --backend hardlink
```
**`clonefile`** is the default backend on macOS. Benchmarking showed it to be the fastest on macOS. It is only available on macOS.
```bash
$ rm -rf node_modules
$ bun install --backend clonefile
```
**`clonefile_each_dir`** is similar to `clonefile`, except it clones each file individually per directory. It is only available on macOS and tends to perform slower than `clonefile`. Unlike `clonefile`, this does not recursively clone subdirectories in one system call.
```bash
$ rm -rf node_modules
$ bun install --backend clonefile_each_dir
```
**`copyfile`** is the fallback used when any of the above fail, and is the slowest. on macOS, it uses `fcopyfile()` and on linux it uses `copy_file_range()`.
```bash
$ rm -rf node_modules
$ bun install --backend copyfile
```
**`symlink`** is typically only used for `file:` dependencies (and eventually `link:`) internally. To prevent infinite loops, it skips symlinking the `node_modules` folder.
If you install with `--backend=symlink`, Node.js won't resolve node_modules of dependencies unless each dependency has its own node_modules folder or you pass `--preserve-symlinks` to `node` or `bun`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks).
```bash
$ rm -rf node_modules
$ bun install --backend symlink
$ bun --preserve-symlinks ./my-file.js
$ node --preserve-symlinks ./my-file.js # https://nodejs.org/api/cli.html#--preserve-symlinks
```
## npm registry metadata
bun uses a binary format for caching NPM registry responses. This loads much faster than JSON and tends to be smaller on disk.
You will see these files in `~/.bun/install/cache/*.npm`. The filename pattern is `${hash(packageName)}.npm`. Its a hash so that extra directories dont need to be created for scoped packages.
Bun's usage of `Cache-Control` ignores `Age`. This improves performance, but means bun may be about 5 minutes out of date to receive the latest package version metadata from npm.
## pnpm migration
Bun automatically migrates projects from pnpm to bun. When a `pnpm-lock.yaml` file is detected and no `bun.lock` file exists, Bun will automatically migrate the lockfile to `bun.lock` during installation. The original `pnpm-lock.yaml` file remains unmodified.
```bash
bun install
```
**Note**: Migration only runs when `bun.lock` is absent. There is currently no opt-out flag for pnpm migration.
The migration process handles:
### Lockfile Migration
- Converts `pnpm-lock.yaml` to `bun.lock` format
- Preserves package versions and resolution information
- Maintains dependency relationships and peer dependencies
- Handles patched dependencies with integrity hashes
### Workspace Configuration
When a `pnpm-workspace.yaml` file exists, Bun migrates workspace settings to your root `package.json`:
```yaml
# pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
catalog:
react: ^18.0.0
typescript: ^5.0.0
catalogs:
build:
webpack: ^5.0.0
babel: ^7.0.0
```
The workspace packages list and catalogs are moved to the `workspaces` field in `package.json`:
```json
{
"workspaces": {
"packages": ["apps/*", "packages/*"],
"catalog": {
"react": "^18.0.0",
"typescript": "^5.0.0"
},
"catalogs": {
"build": {
"webpack": "^5.0.0",
"babel": "^7.0.0"
}
}
}
}
```
### Catalog Dependencies
Dependencies using pnpm's `catalog:` protocol are preserved:
```json
{
"dependencies": {
"react": "catalog:",
"webpack": "catalog:build"
}
}
```
### Configuration Migration
The following pnpm configuration is migrated from both `pnpm-lock.yaml` and `pnpm-workspace.yaml`:
- **Overrides**: Moved from `pnpm.overrides` to root-level `overrides` in `package.json`
- **Patched Dependencies**: Moved from `pnpm.patchedDependencies` to root-level `patchedDependencies` in `package.json`
- **Workspace Overrides**: Applied from `pnpm-workspace.yaml` to root `package.json`
### Requirements
- Requires pnpm lockfile version 7 or higher
- Workspace packages must have a `name` field in their `package.json`
- All catalog entries referenced by dependencies must exist in the catalogs definition
After migration, you can safely remove `pnpm-lock.yaml` and `pnpm-workspace.yaml` files.

View File

@@ -1,39 +0,0 @@
To upgrade Bun, run `bun upgrade`.
It automatically downloads the latest version of Bun and overwrites the currently-running version.
This works by checking the latest version of Bun in [bun-releases-for-updater](https://github.com/Jarred-Sumner/bun-releases-for-updater/releases) and unzipping it using the system-provided `unzip` library (so that Gatekeeper works on macOS)
If for any reason you run into issues, you can also use the curl install script:
```bash
$ curl https://bun.com/install | bash
```
It will still work when Bun is already installed.
Bun is distributed as a single binary file, so you can also do this manually:
- Download the latest version of Bun for your platform in [bun-releases-for-updater](https://github.com/Jarred-Sumner/bun-releases-for-updater/releases/latest) (`darwin` == macOS)
- Unzip the folder
- Move the `bun` binary to `~/.bun/bin` (or anywhere)
## `--canary`
[Canary](https://github.com/oven-sh/bun/releases/tag/canary) builds are generated on every commit.
To install a [canary](https://github.com/oven-sh/bun/releases/tag/canary) build of Bun, run:
```bash
$ bun upgrade --canary
```
This flag is not persistent (though that might change in the future). If you want to always run the canary build of Bun, set the `BUN_CANARY` environment variable to `1` in your shell's startup script.
This will download the release zip from https://github.com/oven-sh/bun/releases/tag/canary.
To revert to the latest published version of Bun, run:
```bash
$ bun upgrade
```

View File

@@ -1,65 +0,0 @@
`bun info` displays package metadata from the npm registry.
## Usage
```bash
$ bun info react
```
This will display information about the `react` package, including its latest version, description, homepage, dependencies, and more.
## Viewing specific versions
To view information about a specific version:
```bash
$ bun info react@18.0.0
```
## Viewing specific properties
You can also query specific properties from the package metadata:
```bash
$ bun info react version
$ bun info react dependencies
$ bun info react repository.url
```
## JSON output
To get the output in JSON format, use the `--json` flag:
```bash
$ bun info react --json
```
## Alias
`bun pm view` is an alias for `bun info`:
```bash
$ bun pm view react # equivalent to: bun info react
```
## Examples
```bash
# View basic package information
$ bun info is-number
# View a specific version
$ bun info is-number@7.0.0
# View all available versions
$ bun info is-number versions
# View package dependencies
$ bun info express dependencies
# View package homepage
$ bun info lodash homepage
# Get JSON output
$ bun info react --json
```

View File

@@ -1,76 +0,0 @@
Scaffold an empty Bun project with the interactive `bun init` command.
```bash
$ bun init
bun init helps you get started with a minimal project and tries to
guess sensible defaults. Press ^C anytime to quit.
package name (quickstart):
entry point (index.ts):
Done! A package.json file was saved in the current directory.
+ index.ts
+ .gitignore
+ tsconfig.json (for editor auto-complete)
+ README.md
To get started, run:
bun run index.ts
```
Press `enter` to accept the default answer for each prompt, or pass the `-y` flag to auto-accept the defaults.
{% details summary="How `bun init` works" %}
`bun init` is a quick way to start a blank project with Bun. It guesses with sane defaults and is non-destructive when run multiple times.
![Demo](https://user-images.githubusercontent.com/709451/183006613-271960a3-ff22-4f7c-83f5-5e18f684c836.gif)
It creates:
- a `package.json` file with a name that defaults to the current directory name
- a `tsconfig.json` file or a `jsconfig.json` file, depending if the entry point is a TypeScript file or not
- an entry point which defaults to `index.ts` unless any of `index.{tsx, jsx, js, mts, mjs}` exist or the `package.json` specifies a `module` or `main` field
- a `README.md` file
AI Agent rules (disable with `$BUN_AGENT_RULE_DISABLED=1`):
- a `CLAUDE.md` file when Claude CLI is detected (disable with `CLAUDE_CODE_AGENT_RULE_DISABLED` env var)
- a `.cursor/rules/*.mdc` file to guide [Cursor AI](https://cursor.sh) to use Bun instead of Node.js and npm when Cursor is detected
If you pass `-y` or `--yes`, it will assume you want to continue without asking questions.
At the end, it runs `bun install` to install `@types/bun`.
{% /details %}
{% bunCLIUsage command="init" /%}
## React
The `--react` flag will scaffold a React project:
```bash
$ bun init --react
```
The `--react` flag accepts the following values:
- `tailwind` - Scaffold a React project with Tailwind CSS
- `shadcn` - Scaffold a React project with Shadcn/UI and Tailwind CSS
### React + TailwindCSS
This will create a React project with Tailwind CSS configured with Bun's bundler and dev server.
```bash
$ bun init --react=tailwind
```
### React + @shadcn/ui
This will create a React project with shadcn/ui and Tailwind CSS configured with Bun's bundler and dev server.
```bash
$ bun init --react=shadcn
```

View File

@@ -1,11 +0,0 @@
An alias for `bun patch --commit` to maintain compatibility with pnpm.
To get started with patch, first prepare the package for patching with [`bun patch <pkg>`](https://bun.com/docs/install/patch).
### `--patches-dir`
By default, `bun patch-commit` will use the `patches` directory in the temporary directory.
You can specify a different directory with the `--patches-dir` flag.
{% bunCLIUsage command="patch-commit" /%}

View File

@@ -1,7 +0,0 @@
To remove a dependency:
```bash
$ bun remove ts-node
```
{% bunCLIUsage command="remove" /%}

View File

@@ -1,9 +0,0 @@
Use `bun unlink` in the root directory to unregister a local package.
```bash
$ cd /path/to/cool-pkg
$ bun unlink
bun unlink v1.x (7416672e)
```
{% bunCLIUsage command="unlink" /%}

View File

@@ -1,57 +0,0 @@
Bun uses [a fork](https://github.com/oven-sh/WebKit) of WebKit with a small number of changes.
It's important to periodically update WebKit for many reasons:
- Security
- Performance
- Compatibility
- …and many more.
To upgrade, first find the commit in **Bun's WebKit fork** (not Bun!) between when we last upgraded and now.
```bash
$ cd src/bun.js/WebKit # In the WebKit directory! not bun
$ git checkout $COMMIT
```
This is the main command to run:
```bash
$ git merge upstream main
# If you get an error saying histories are unrelated, run this and try again:
$ git fetch --unshallow
```
Then, you will likely see some silly merge conflicts. Fix them and then run:
```bash
# You might have to run this multiple times.
$ rm -rf WebKitBuild
# Go to Bun's directory! Not WebKit.
cd ../../../../
make jsc-build-mac-compile
```
Make sure that JSC's CLI is able to load successfully. This verifies that the build is working.
You know this worked when it printed help options. If it complains about symbols, crashes, or anything else that looks wrong, something is wrong.
```bash
src/bun.js/WebKit/WebKitBuild/Release/bin/jsc --help
```
Then, clear out our bindings and regenerate the C++<>Zig headers:
```bash
make clean-bindings headers builtins
```
Now update Bun's bindings wherever there are compiler errors:
```bash
# It will take awhile if you don't pass -j here
make bindings -j10
```
This is the hard part. It might involve digging through WebKit's commit history to figure out what changed and why. Fortunately, WebKit contributors write great commit messages.

626
docs/docs.json Normal file
View File

@@ -0,0 +1,626 @@
{
"$schema": "https://mintlify.com/docs.json",
"theme": "aspen",
"name": "Bun",
"seo": {
"metatags": {
"canonical": "https://bun.com/docs"
}
},
"colors": {
"light": "#ff73a8",
"primary": "#ff73a8",
"dark": "#ff73a8"
},
"background": {
"decoration": "gradient"
},
"favicon": "/logo/bun.png",
"icons": {
"library": "lucide"
},
"fonts": {
"heading": {
"family": "Inter Display Bold",
"source": "https://mintlify-assets.b-cdn.net/fonts/InterDisplay-Bold.woff2",
"format": "woff2"
}
},
"appearance": {
"default": "system"
},
"logo": {
"light": "/logo/logo-with-wordmark-dark.svg",
"dark": "/logo/logo-with-wordmark-light.svg"
},
"navbar": {
"links": [
{
"label": "Install Bun",
"href": "https://www.bun.com/docs/installation",
"icon": "download",
"primary": true
}
]
},
"contextual": {
"options": ["copy", "view", "chatgpt", "claude", "perplexity", "mcp", "cursor", "vscode"]
},
"styling": {
"codeblocks": {
"theme": {
"light": "github-light",
"dark": "dracula"
}
}
},
"navigation": {
"tabs": [
{
"tab": "Runtime",
"icon": "cog",
"groups": [
{
"group": "Get Started",
"icon": "terminal",
"pages": [
"/index",
"/installation",
"/quickstart",
"/typescript",
"/runtime/templating/init",
"/runtime/templating/create"
]
},
{
"group": "Core Runtime",
"icon": "cog",
"pages": ["/runtime/index", "/runtime/watch-mode", "/runtime/debugger", "/runtime/bunfig"]
},
{
"group": "File & Module System",
"icon": "file",
"pages": [
"/runtime/file-types",
"/runtime/module-resolution",
"/runtime/jsx",
"/runtime/auto-install",
"/runtime/plugins",
"/runtime/file-system-router"
]
},
{
"group": "HTTP server",
"icon": "server",
"pages": [
"/runtime/http/server",
"/runtime/http/routing",
"/runtime/http/cookies",
"/runtime/http/tls",
"/runtime/http/error-handling",
"/runtime/http/metrics"
]
},
{
"group": "Networking",
"icon": "globe",
"expanded": true,
"pages": [
"/runtime/networking/fetch",
"/runtime/http/websockets",
"/runtime/networking/tcp",
"/runtime/networking/udp",
"/runtime/networking/dns"
]
},
{
"group": "Data & Storage",
"icon": "database",
"pages": [
"/runtime/cookies",
"/runtime/file-io",
"/runtime/streams",
"/runtime/binary-data",
"/runtime/sql",
"/runtime/sqlite",
"/runtime/s3",
"/runtime/redis"
]
},
{
"group": "Concurrency",
"icon": "split",
"pages": ["/runtime/workers"]
},
{
"group": "Process & System",
"icon": "computer",
"pages": ["/runtime/environment-variables", "/runtime/shell", "/runtime/child-process"]
},
{
"group": "Interop & Tooling",
"icon": "puzzle",
"pages": ["/runtime/node-api", "/runtime/ffi", "/runtime/c-compiler", "/runtime/transpiler"]
},
{
"group": "Utilities",
"icon": "wrench",
"pages": [
"/runtime/secrets",
"/runtime/console",
"/runtime/yaml",
"/runtime/html-rewriter",
"/runtime/hashing",
"/runtime/glob",
"/runtime/semver",
"/runtime/color",
"/runtime/utils"
]
},
{
"group": "Standards & Compatibility",
"icon": "badge-check",
"pages": ["/runtime/globals", "/runtime/bun-apis", "/runtime/web-apis", "/runtime/nodejs-compat"]
},
{
"group": "Contributing",
"icon": "heart",
"pages": [
"/project/roadmap",
"/project/benchmarking",
"/project/contributing",
"/project/building-windows",
"/project/bindgen",
"/project/license"
]
}
]
},
{
"tab": "Package Manager",
"icon": "box",
"groups": [
{
"group": "Core Commands",
"icon": "terminal",
"pages": ["/pm/cli/install", "/pm/cli/add", "/pm/cli/remove", "/pm/cli/update", "/pm/bunx"]
},
{
"group": "Publishing & Analysis",
"icon": "upload",
"pages": ["/pm/cli/publish", "/pm/cli/outdated", "/pm/cli/why", "/pm/cli/audit"]
},
{
"group": "Workspace Management",
"icon": "folders",
"pages": ["/pm/workspaces", "/pm/catalogs", "/pm/cli/link", "/pm/cli/pm"]
},
{
"group": "Advanced Configuration",
"icon": "settings",
"pages": [
"/pm/cli/patch",
"/pm/filter",
"/pm/global-cache",
"/pm/isolated-installs",
"/pm/lockfile",
"/pm/lifecycle",
"/pm/scopes-registries",
"/pm/overrides",
"/pm/security-scanner-api",
"/pm/npmrc"
]
}
]
},
{
"tab": "Bundler",
"icon": "combine",
"groups": [
{
"group": "Core",
"icon": "package",
"pages": ["/bundler/index"]
},
{
"group": "Development Server",
"icon": "monitor",
"pages": ["/bundler/fullstack", "/bundler/hot-reloading"]
},
{
"group": "Asset Processing",
"icon": "image",
"pages": ["/bundler/html-static", "/bundler/css", "/bundler/loaders"]
},
{
"group": "Single File Executable",
"icon": "binary",
"pages": ["/bundler/executables"]
},
{
"group": "Extensions",
"icon": "plug",
"pages": ["/bundler/plugins", "/bundler/macros"]
},
{
"group": "Optimization",
"icon": "zap",
"pages": ["/bundler/bytecode", "/bundler/minifier"]
},
{
"group": "Migration",
"icon": "arrow-right",
"pages": ["/bundler/esbuild"]
}
]
},
{
"tab": "Test Runner",
"icon": "flask-conical",
"groups": [
{
"group": "Getting Started",
"icon": "circle-play",
"pages": ["/test/index", "/test/writing-tests", "/test/configuration"]
},
{
"group": "Test Execution",
"icon": "zap",
"pages": ["/test/runtime-behavior", "/test/discovery"]
},
{
"group": "Test Features",
"icon": "sparkles",
"pages": ["/test/lifecycle", "/test/mocks", "/test/snapshots", "/test/dates-times"]
},
{
"group": "Specialized Testing",
"icon": "microscope",
"pages": ["/test/dom"]
},
{
"group": "Reporting",
"icon": "file-text",
"pages": ["/test/code-coverage", "/test/reporters"]
}
]
},
{
"tab": "Guides",
"icon": "map",
"groups": [
{
"group": "Overview",
"icon": "globe",
"pages": ["/guides/index"]
},
{
"group": "Deployment",
"icon": "rocket",
"pages": [
"/guides/deployment/vercel",
"/guides/deployment/railway",
"/guides/deployment/render",
"/guides/deployment/aws-lambda",
"/guides/deployment/digital-ocean",
"/guides/deployment/google-cloud-run"
]
},
{
"group": "Runtime & Debugging",
"icon": "bug",
"pages": [
"/guides/runtime/typescript",
"/guides/runtime/tsconfig-paths",
"/guides/runtime/vscode-debugger",
"/guides/runtime/web-debugger",
"/guides/runtime/heap-snapshot",
"/guides/runtime/build-time-constants",
"/guides/runtime/define-constant",
"/guides/runtime/cicd",
"/guides/runtime/codesign-macos-executable"
]
},
{
"group": "Utilities",
"icon": "wrench",
"pages": [
"/guides/util/detect-bun",
"/guides/util/version",
"/guides/util/hash-a-password",
"/guides/util/javascript-uuid",
"/guides/util/base64",
"/guides/util/gzip",
"/guides/util/deflate",
"/guides/util/escape-html",
"/guides/util/deep-equals",
"/guides/util/sleep",
"/guides/util/file-url-to-path",
"/guides/util/path-to-file-url",
"/guides/util/which-path-to-executable-bin",
"/guides/util/import-meta-dir",
"/guides/util/import-meta-file",
"/guides/util/import-meta-path",
"/guides/util/entrypoint",
"/guides/util/main"
]
},
{
"group": "Ecosystem & Frameworks",
"icon": "puzzle",
"pages": [
"/guides/ecosystem/astro",
"/guides/ecosystem/discordjs",
"/guides/ecosystem/docker",
"/guides/ecosystem/drizzle",
"/guides/ecosystem/edgedb",
"/guides/ecosystem/elysia",
"/guides/ecosystem/express",
"/guides/ecosystem/hono",
"/guides/ecosystem/mongoose",
"/guides/ecosystem/neon-drizzle",
"/guides/ecosystem/neon-serverless-postgres",
"/guides/ecosystem/nextjs",
"/guides/ecosystem/nuxt",
"/guides/ecosystem/pm2",
"/guides/ecosystem/prisma",
"/guides/ecosystem/prisma-postgres",
"/guides/ecosystem/qwik",
"/guides/ecosystem/react",
"/guides/ecosystem/remix",
"/guides/ecosystem/sentry",
"/guides/ecosystem/solidstart",
"/guides/ecosystem/ssr-react",
"/guides/ecosystem/stric",
"/guides/ecosystem/sveltekit",
"/guides/ecosystem/systemd",
"/guides/ecosystem/vite",
"/guides/ecosystem/upstash"
]
},
{
"group": "HTTP & Networking",
"icon": "globe",
"pages": [
"/guides/http/server",
"/guides/http/simple",
"/guides/http/fetch",
"/guides/http/hot",
"/guides/http/cluster",
"/guides/http/tls",
"/guides/http/proxy",
"/guides/http/stream-file",
"/guides/http/file-uploads",
"/guides/http/fetch-unix",
"/guides/http/stream-iterator",
"/guides/http/stream-node-streams-in-bun"
]
},
{
"group": "WebSocket",
"icon": "radio",
"pages": [
"/guides/websocket/simple",
"/guides/websocket/pubsub",
"/guides/websocket/context",
"/guides/websocket/compression"
]
},
{
"group": "Processes & System",
"icon": "cpu",
"pages": [
"/guides/process/spawn",
"/guides/process/spawn-stdout",
"/guides/process/spawn-stderr",
"/guides/process/argv",
"/guides/process/stdin",
"/guides/process/ipc",
"/guides/process/ctrl-c",
"/guides/process/os-signals",
"/guides/process/nanoseconds",
"/guides/runtime/shell",
"/guides/runtime/timezone",
"/guides/runtime/set-env",
"/guides/runtime/read-env"
]
},
{
"group": "Package Manager",
"icon": "package",
"pages": [
"/guides/install/add",
"/guides/install/add-dev",
"/guides/install/add-optional",
"/guides/install/add-peer",
"/guides/install/add-git",
"/guides/install/add-tarball",
"/guides/install/npm-alias",
"/guides/install/workspaces",
"/guides/install/custom-registry",
"/guides/install/registry-scope",
"/guides/install/azure-artifacts",
"/guides/install/jfrog-artifactory",
"/guides/install/trusted",
"/guides/install/yarnlock",
"/guides/install/from-npm-install-to-bun-install",
"/guides/install/git-diff-bun-lockfile",
"/guides/install/cicd"
]
},
{
"group": "Test Runner",
"icon": "flask-conical",
"pages": [
"/guides/test/run-tests",
"/guides/test/watch-mode",
"/guides/test/migrate-from-jest",
"/guides/test/mock-functions",
"/guides/test/spy-on",
"/guides/test/mock-clock",
"/guides/test/snapshot",
"/guides/test/update-snapshots",
"/guides/test/coverage",
"/guides/test/coverage-threshold",
"/guides/test/skip-tests",
"/guides/test/todo-tests",
"/guides/test/timeout",
"/guides/test/bail",
"/guides/test/rerun-each",
"/guides/test/testing-library",
"/guides/test/happy-dom",
"/guides/test/svelte-test"
]
},
{
"group": "Runtime & Debugging",
"icon": "bug",
"pages": [
"/guides/runtime/vscode-debugger",
"/guides/runtime/web-debugger",
"/guides/runtime/heap-snapshot",
"/guides/runtime/build-time-constants",
"/guides/runtime/define-constant",
"/guides/runtime/cicd",
"/guides/runtime/codesign-macos-executable"
]
},
{
"group": "Module System",
"icon": "box",
"pages": [
"/guides/runtime/import-json",
"/guides/runtime/import-toml",
"/guides/runtime/import-yaml",
"/guides/runtime/import-html",
"/guides/util/import-meta-dir",
"/guides/util/import-meta-file",
"/guides/util/import-meta-path",
"/guides/util/entrypoint",
"/guides/util/main"
]
},
{
"group": "File System",
"icon": "folder",
"pages": [
"/guides/read-file/string",
"/guides/read-file/buffer",
"/guides/read-file/uint8array",
"/guides/read-file/arraybuffer",
"/guides/read-file/json",
"/guides/read-file/mime",
"/guides/read-file/exists",
"/guides/read-file/watch",
"/guides/read-file/stream",
"/guides/write-file/basic",
"/guides/write-file/blob",
"/guides/write-file/response",
"/guides/write-file/append",
"/guides/write-file/filesink",
"/guides/write-file/stream",
"/guides/write-file/stdout",
"/guides/write-file/cat",
"/guides/write-file/file-cp",
"/guides/write-file/unlink",
"/guides/runtime/delete-file",
"/guides/runtime/delete-directory"
]
},
{
"group": "Utilities",
"icon": "wrench",
"pages": [
"/guides/util/hash-a-password",
"/guides/util/javascript-uuid",
"/guides/util/base64",
"/guides/util/gzip",
"/guides/util/deflate",
"/guides/util/escape-html",
"/guides/util/deep-equals",
"/guides/util/sleep",
"/guides/util/file-url-to-path",
"/guides/util/path-to-file-url",
"/guides/util/which-path-to-executable-bin"
]
},
{
"group": "HTML Processing",
"icon": "file-code",
"pages": ["/guides/html-rewriter/extract-links", "/guides/html-rewriter/extract-social-meta"]
},
{
"group": "Binary Data",
"icon": "binary",
"pages": [
"/guides/binary/arraybuffer-to-string",
"/guides/binary/arraybuffer-to-buffer",
"/guides/binary/arraybuffer-to-blob",
"/guides/binary/arraybuffer-to-array",
"/guides/binary/arraybuffer-to-typedarray",
"/guides/binary/buffer-to-string",
"/guides/binary/buffer-to-arraybuffer",
"/guides/binary/buffer-to-blob",
"/guides/binary/buffer-to-typedarray",
"/guides/binary/buffer-to-readablestream",
"/guides/binary/blob-to-string",
"/guides/binary/blob-to-arraybuffer",
"/guides/binary/blob-to-typedarray",
"/guides/binary/blob-to-dataview",
"/guides/binary/blob-to-stream",
"/guides/binary/typedarray-to-string",
"/guides/binary/typedarray-to-arraybuffer",
"/guides/binary/typedarray-to-buffer",
"/guides/binary/typedarray-to-blob",
"/guides/binary/typedarray-to-dataview",
"/guides/binary/typedarray-to-readablestream",
"/guides/binary/dataview-to-string"
]
},
{
"group": "Streams",
"icon": "waves",
"pages": [
"/guides/streams/to-string",
"/guides/streams/to-json",
"/guides/streams/to-blob",
"/guides/streams/to-buffer",
"/guides/streams/to-arraybuffer",
"/guides/streams/to-typedarray",
"/guides/streams/to-array",
"/guides/streams/node-readable-to-string",
"/guides/streams/node-readable-to-json",
"/guides/streams/node-readable-to-blob",
"/guides/streams/node-readable-to-uint8array",
"/guides/streams/node-readable-to-arraybuffer"
]
}
]
},
{
"tab": "Reference",
"icon": "book",
"href": "https://bun.com/reference"
},
{
"tab": "Blog",
"icon": "newspaper",
"href": "https://bun.com/blog"
},
{
"tab": "Feedback",
"icon": "lightbulb",
"pages": ["/feedback"]
}
]
},
"footer": {
"socials": {
"x": "https://x.com/bunjavascript",
"github": "https://github.com/oven-sh/bun",
"discord": "https://bun.com/discord",
"youtube": "https://www.youtube.com/@bunjs"
}
}
}

View File

@@ -1,24 +0,0 @@
[Elysia](https://elysiajs.com) is a Bun-first performance focused web framework that takes full advantage of Bun's HTTP, file system, and hot reloading APIs.
Designed with TypeScript in mind, you don't need to understand TypeScript to gain the benefit of TypeScript with Elysia. The library understands what you want and automatically infers the type from your code.
⚡️ Elysia is [one of the fastest Bun web frameworks](https://github.com/SaltyAom/bun-http-framework-benchmark)
```ts#server.ts
import { Elysia } from 'elysia'
const app = new Elysia()
.get('/', () => 'Hello Elysia')
.listen(8080)
console.log(`🦊 Elysia is running at on port ${app.server.port}...`)
```
Get started with `bun create`.
```bash
$ bun create elysia ./myapp
$ cd myapp
$ bun run dev
```
Refer to the Elysia [documentation](https://elysiajs.com/quick-start.html) for more information.

View File

@@ -1,37 +0,0 @@
Projects that use Express and other major Node.js HTTP libraries should work out of the box.
{% callout %}
If you run into bugs, [please file an issue](https://bun.com/issues) _in Bun's repo_, not the library. It is Bun's responsibility to address Node.js compatibility issues.
{% /callout %}
```ts
import express from "express";
const app = express();
const port = 8080;
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(port, () => {
console.log(`Listening on port ${port}...`);
});
```
Bun implements the [`node:http`](https://nodejs.org/api/http.html) and [`node:https`](https://nodejs.org/api/https.html) modules that these libraries rely on. These modules can also be used directly, though [`Bun.serve`](https://bun.com/docs/api/http) is recommended for most use cases.
{% callout %}
**Note** — Refer to the [Runtime > Node.js APIs](https://bun.com/docs/runtime/nodejs-apis#node-http) page for more detailed compatibility information.
{% /callout %}
```ts
import * as http from "node:http";
http
.createServer(function (req, res) {
res.write("Hello World!");
res.end();
})
.listen(8080);
```

View File

@@ -1,18 +0,0 @@
[Hono](https://github.com/honojs/hono) is a lightweight ultrafast web framework designed for the edge.
```ts
import { Hono } from "hono";
const app = new Hono();
app.get("/", c => c.text("Hono!"));
export default app;
```
Get started with `bun create` or follow Hono's [Bun quickstart](https://hono.dev/getting-started/bun).
```bash
$ bun create hono ./myapp
$ cd myapp
$ bun run start
```

View File

@@ -1,65 +0,0 @@
Bun supports `.jsx` and `.tsx` files out of the box. Bun's internal transpiler converts JSX syntax into vanilla JavaScript before execution.
```tsx#react.tsx
function Component(props: {message: string}) {
return (
<body>
<h1 style={{color: 'red'}}>{props.message}</h1>
</body>
);
}
console.log(<Component message="Hello world!" />);
```
Bun implements special logging for JSX to make debugging easier.
```bash
$ bun run react.tsx
<Component message="Hello world!" />
```
### Prop punning
The Bun runtime also supports "prop punning" for JSX. This is a shorthand syntax useful for assigning a variable to a prop with the same name.
```tsx
function Div(props: {className: string;}) {
const {className} = props;
// without punning
return <div className={className} />;
// with punning
return <div {className} />;
}
```
### Server-side rendering
To server-side render (SSR) React in an [HTTP server](https://bun.com/docs/api/http):
```tsx#ssr.tsx
import {renderToReadableStream} from 'react-dom/server';
function Component(props: {message: string}) {
return (
<body>
<h1 style={{color: 'red'}}>{props.message}</h1>
</body>
);
}
Bun.serve({
port: 4000,
async fetch() {
const stream = await renderToReadableStream(
<Component message="Hello from server!" />
);
return new Response(stream, {
headers: {'Content-Type': 'text/html'},
});
},
});
```
React `18.3` and later includes an [SSR optimization](https://github.com/facebook/react/pull/25597) that takes advantage of Bun's "direct" `ReadableStream` implementation.

View File

@@ -1,38 +0,0 @@
[Stric](https://github.com/bunsvr) is a minimalist, fast web framework for Bun.
```ts#index.ts
import { Router } from '@stricjs/router';
// Export the fetch handler and serve with Bun
export default new Router()
// Return 'Hi' on every request
.get('/', () => new Response('Hi'));
```
Stric provides support for [ArrowJS](https://www.arrow-js.com), a library for building reactive interfaces.
{% codetabs %}
```ts#src/App.ts
import { html } from '@stricjs/arrow/utils';
// Code inside this function can use web APIs
export function render() {
// Render a <p> element with text 'Hi'
html`<p>Hi</p>`;
};
// Set the path to handle
export const path = '/';
```
```ts#index.ts
import { PageRouter } from '@stricjs/arrow';
// Create a page router, build and serve directly
new PageRouter().serve();
```
{% /codetabs %}
For more info, see Stric's [documentation](https://stricjs.gitbook.io/docs).

85
docs/feedback.mdx Normal file
View File

@@ -0,0 +1,85 @@
---
title: Feedback
description: Share feedback, bug reports, and feature requests
mode: center
---
import Feedback from "/snippets/cli/feedback.mdx";
Whether you've found a bug, have a performance issue, or just want to suggest an improvement, here's how you can open a helpful issue:
<Callout icon="discord">
For general questions, please join our [Discord](https://discord.com/invite/CXdq2DP29u).
</Callout>
## Reporting Issues
<Steps>
<Step title="Upgrade Bun">
Try upgrading Bun to the latest version with `bun upgrade`. This might fix your problem without having to open an issue.
```bash terminal icon="terminal"
bun upgrade
```
You can also try the latest canary release, which includes the most recent changes and bug fixes that haven't been released in a stable version yet.
```bash terminal icon="terminal"
bun upgrade --canary
# To revert back to the stable
bun upgrade --stable
```
If the issue still persists after upgrading, continue to the next step.
</Step>
<Step title="Review Existing Issues">
First take a minute to check if the issue has already been reported. Don't open a new issue if it has already been reported, it saves time for everyone and helps us focus on fixing things faster.
- 🔍 [**Search existing issues**](https://github.com/oven-sh/bun/issues)
- 💬 [**Check discussions**](https://github.com/oven-sh/bun/discussions)
If you find a related issue, add a 👍 reaction or comment with extra details instead of opening a new one.
</Step>
<Step title="Report the Issue">
If no one has reported the issue, please open a new issue or suggest an improvement.
- 🐞 [**Report a Bug**](https://github.com/oven-sh/bun/issues/new?template=2-bug-report.yml)
- ⚡ [**Suggest an Improvement**](https://github.com/oven-sh/bun/issues/new?template=4-feature-request.yml)
Please provide as much detail as possible, including:
- A clear and concise title
- A code example or steps to reproduce the issue
- The version of Bun you are using (run `bun --version`)
- A detailed description of the issue (what happened, what you expected to happen, and what actually happened)
- The operating system and version you are using
<Note>
- For MacOS and Linux: copy the output of `uname -mprs`
- For Windows: copy the output of this command in the powershell console:
```powershell
"$([Environment]::OSVersion | ForEach-Object VersionString) $(if ([Environment]::Is64BitOperatingSystem) { "x64" } else { "x86" })"
```
</Note>
</Step>
</Steps>
The Bun team will review the issue and get back to you as soon as possible!
---
## Use `bun feedback`
Alternatively, you can use `bun feedback` to share feedback, bug reports, and feature requests directly with the Bun team.
```bash terminal icon="terminal"
bun feedback "Love the new release!"
bun feedback report.txt details.log
echo "please document X" | bun feedback --email you@example.com
```
You can provide feedback as text arguments, file paths, or piped input.
---
<Feedback />

View File

@@ -1,5 +1,7 @@
---
name: Convert an ArrayBuffer to an array of numbers
title: Convert an ArrayBuffer to an array of numbers
sidebarTitle: "ArrayBuffer to Array"
mode: center
---
To retrieve the contents of an `ArrayBuffer` as an array of numbers, create a [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) over of the buffer. and use the [`Array.from()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) method to convert it to an array.

Some files were not shown because too many files have changed in this diff Show More