Compare commits

...

116 Commits

Author SHA1 Message Date
Claude Bot
a3df1a8cfd fix(cli): support node --run when bun pretends to be node
When `bun run --bun` is used, child processes invoking `node` actually
run bun via a symlink. Node.js v22+ supports `node --run <script>` to
run package.json scripts, but bun's fake node mode silently ignored the
`--run` flag and tried to execute the script name as a file path instead.

Detect `--run` in the raw argv and delegate to `RunCommand.exec()` which
already handles package.json script resolution with pre/post scripts.

Closes #27074

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-17 08:12:11 +00:00
robobun
70b354aa04 fix(bundler): include CSS in all HTML entrypoints sharing a deduplicated CSS chunk (#27040) 2026-02-15 03:36:06 -08:00
Jarred Sumner
9d5a800c3d fix(napi,timers): callback scope (#27026) 2026-02-15 03:33:48 -08:00
Jarred Sumner
77ca318336 Reduce the number of closures in generated bundler code (#27022)
### Problem

The bundler's `__toESM` helper creates a new getter-wrapped proxy object
every time a CJS
module is imported. In a large app, a popular dependency like React can
be imported 600+
times — each creating a fresh object with ~44 getter properties. This
produces ~27K
unnecessary `GetterSetter` objects, ~25K closures, and ~25K
`JSLexicalEnvironment` scope
objects at startup.

Additionally, `__export` and `__exportValue` use `var`-scoped loop
variables captured by
setter closures, meaning all setters incorrectly reference the last
iterated key (a latent
  bug).

### Changes

1. **`__toESM`: add WeakMap cache** — deduplicate repeated wrappings of
the same CJS
module. Two caches (one per `isNodeMode` value) to handle both import
modes correctly.
2. **Replace closures with `.bind()`** — `() => obj[key]` becomes
`__accessProp.bind(obj,
key)`. BoundFunction is cheaper than Function + JSLexicalEnvironment,
and frees the for-in
  `JSPropertyNameEnumerator` from the closure scope.
3. **Fix var-scoping bug in `__export`/`__exportValue`** — setter
closures captured a
shared `var name` and would all modify the last iterated key. `.bind()`
eagerly captures
the correct key per iteration.
4. **`__toCommonJS`: `.map()` → `for..of`** — eliminates throwaway array
allocation.
5. **`__reExport`: single `getOwnPropertyNames` call** — was calling it
twice when
`secondTarget` was provided.

### Impact (measured on a ~23MB single-bundle app with 600+ React
imports)

| Metric | Before | After | Delta |
|--------|--------|-------|-------|
| **Total objects** | 745,985 | 664,001 | **-81,984 (-11%)** |
| **Heap size** | 115 MB | 111 MB | **-4 MB** |
| GetterSetter | 34,625 | 13,428 | -21,197 (-61%) |
| Function | 221,302 | 197,024 | -24,278 (-11%) |
| JSLexicalEnvironment | 70,101 | 44,633 | -25,468 (-36%) |
| Structure | 40,254 | 39,762 | -492 |
2026-02-15 00:36:57 -08:00
Jarred Sumner
337a9f7f2b fix(module): prevent crash when resolving bun:main before entry_po… (#27027)
…int.generate()

`ServerEntryPoint.source` defaults to `undefined`, and accessing its
`.contents` or `.path.text` fields before `generate()` has been called
causes a segfault. This happens when `bun:main` is resolved in contexts
where `entry_point.generate()` is skipped (HTML entry points) or never
called (test runner).

Add a `generated` flag to `ServerEntryPoint` and guard both access
sites:
- `getHardcodedModule()` in ModuleLoader.zig (returns null instead of
crashing)
- `_resolve()` in VirtualMachine.zig (falls through to normal
resolution)

### 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>
2026-02-14 12:11:41 -08:00
robobun
38f41dccdf fix(crypto): fix segfault in X509Certificate.issuerCertificate getter (#27025) 2026-02-14 05:58:41 -08:00
robobun
883e43c371 update(crypto): update root certificates to NSS 3.119; eliminate external HTTPS in tests (#27020) 2026-02-14 02:47:13 -08:00
Dylan Conway
cd17934207 fix(stripANSI): handle SIMD false positives for non-ANSI control chars (#27021)
The SIMD fast path in `findEscapeCharacter` matches bytes in `0x10-0x1F`
and `0x90-0x9F`, but `consumeANSI` only handles actual ANSI escape
introducers (`0x1b`, `0x9b`, `0x9d`, `0x90`, `0x98`, `0x9e`, `0x9f`).
For non-ANSI bytes like `0x16` (SYN), `consumeANSI` returns the same
pointer it received, causing an infinite loop in release builds and an
assertion failure in debug builds.

When a SIMD false positive is detected (`consumeANSI` returns the same
pointer), the byte is preserved in the output and scanning advances past
it.

Fixes #27014
2026-02-14 02:01:25 -08:00
robobun
f6d4ff6779 fix(http): validate statusMessage for CRLF to prevent HTTP response splitting (#26949)
## Summary

- Fixes HTTP response splitting vulnerability where `res.statusMessage`
could contain CRLF characters that were written directly to the socket,
allowing injection of arbitrary HTTP headers and response body
- Adds native-layer validation in `NodeHTTPResponse.zig` `writeHead()`
to reject status messages containing control characters (matching
Node.js's `checkInvalidHeaderChar` behavior)
- The `writeHead(code, msg)` API already validated via JS-side
`checkInvalidHeaderChar`, but direct property assignment
(`res.statusMessage = userInput`) followed by `res.end()` or
`res.write()` bypassed all validation

## Test plan

- [x] Verified vulnerability is reproducible: attacker can inject
`Set-Cookie` headers via `res.statusMessage = "OK\r\nSet-Cookie:
admin=true"`
- [x] Verified fix throws `ERR_INVALID_CHAR` TypeError when CRLF is
present in status message
- [x] Added 4 new tests covering: property assignment + `res.end()`,
property assignment + `res.write()`, explicit `writeHead()` rejection,
and valid status message passthrough
- [x] Tests fail with `USE_SYSTEM_BUN=1` (confirming they detect the
vulnerability) and pass with `bun bd test`
- [x] Existing Node.js compat test
`test-http-status-reason-invalid-chars.js` still passes
- [x] All 14 HTTP security tests pass
- [x] Full `node-http.test.ts` suite passes (77 pass, 1 pre-existing
skip, 1 pre-existing proxy 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>
2026-02-14 00:25:07 -08:00
robobun
2c173529fa fix(test): eliminate external HTTPS fetches and renew expired TLS certs (#27013)
## Summary

- **HTMLRewriter test**: Replaced `fetch("https://www.example.com/")`
with a local HTTP content server, eliminating dependency on external
HTTPS and system CA certificates
- **HTTPS agent test**: Replaced `https.request("https://example.com/")`
with a local TLS server using self-signed certs from harness
- **Expired certs**: Regenerated self-signed certificates in
`test/js/bun/http/fixtures/` and `test/regression/fixtures/` (were
expired since Sep 2024, now valid until 2036)

## Root cause

Tests fetching external HTTPS URLs (`https://example.com`,
`https://www.example.com`) fail on CI environments (Alpine Linux,
Windows) that lack system CA certificate bundles, producing
`UNABLE_TO_GET_ISSUER_CERT_LOCALLY` errors. This affected:
- `test/js/workerd/html-rewriter.test.js` (HTMLRewriter: async
replacement using fetch + Bun.serve)
-
`test/js/bun/test/parallel/test-https-should-work-when-sending-request-with-agent-false.ts`

## Test plan

- [x] `bun bd test test/js/workerd/html-rewriter.test.js` - 41 pass, 0
fail
- [x] `bun bd test test/js/workerd/html-rewriter.test.js -t "async
replacement using fetch"` - 1 pass
- [x] `bun bd
test/js/bun/test/parallel/test-https-should-work-when-sending-request-with-agent-false.ts`
- exits 0
- [x] `bun bd test test/js/bun/http/serve-listen.test.ts` - 27 pass, 0
fail (uses renewed certs)

🤖 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>
2026-02-13 20:45:06 -08:00
Dylan Conway
243fa45bec fix(shell): prevent use-after-free in builtin OutputTask callbacks inside $() (#26987)
## Summary

- Fixes use-after-free (ASAN use-after-poison) when shell builtins
(`ls`, `touch`, `mkdir`, `cp`) run inside command substitution `$(...)`
and encounter errors (e.g., permission denied)
- The `output_waiting` and `output_done` counters in the builtin exec
state went out of sync because `output_waiting` was only incremented for
async IO operations, while `output_done` was always incremented
- In command substitution, stdout is `.pipe` (sync) and stderr is `.fd`
(async), so a single OutputTask completing both writes could satisfy the
done condition while another OutputTask's async stderr write was still
pending in the IOWriter

The fix moves `output_waiting += 1` before the `needsIO()` check in all
four affected builtins so it's always incremented, matching
`output_done`.

## Test plan

- [x] `echo $(ls /tmp/*)` — no ASAN errors (previously crashed with
use-after-poison)
- [x] `echo $(touch /root/a /root/b ...)` — no ASAN errors
- [x] `echo $(mkdir /root/a /root/b ...)` — no ASAN errors
- [x] `ls /nonexistent` — still reports error and exits with code 1
- [x] `echo $(ls /tmp)` — still captures output correctly
- [x] Existing shell test suite: 292 pass, 52 fail (pre-existing), 83
todo — no regressions

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:40:49 -08:00
Dylan Conway
c19dcb3181 fix(shell): reject non-finite seq args and handle empty condexpr args (#26993)
## Summary
- **`seq inf` / `seq nan` / `seq -inf` hang**: `std.fmt.parseFloat`
accepts non-finite float values like `inf`, `nan`, `-inf`, but the loop
`while (current <= this._end)` never terminates when `_end` is infinity.
Now rejects non-finite values after parsing.
- **`[[ -d "" ]]` out-of-bounds panic**: Empty string expansion produces
no args in the args list, but `doStat()` unconditionally accesses
`args.items[0]`. Now checks `args.items.len == 0` before calling
`doStat()` and returns exit code 1 (path doesn't exist).

## Test plan
- [x] `seq inf`, `seq nan`, `seq -inf` return exit code 1 with "invalid
argument" instead of hanging
- [x] `[[ -d "" ]]` and `[[ -f "" ]]` return exit code 1 instead of
panicking
- [x] `seq 3` still works normally (produces 1, 2, 3)
- [x] `[[ -d /tmp ]]`, `[[ -f /etc/hostname ]]` still work correctly
- [x] Tests pass with `bun bd test`, seq tests fail with
`USE_SYSTEM_BUN=1`

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

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:01:40 -08:00
Jarred Sumner
c57af9df38 Fix websocket proxy ping crash (#26995)
### What does this PR do?

The `sendPong` fix alone wasn't sufficient. The bug only manifests with
**wss:// through HTTP proxy** (not ws://), because only that path uses
`initWithTunnel` with a detached socket.

**Two bugs were found and fixed:**

1. **`sendPong`/`sendCloseWithBody` socket checks**
(`src/http/websocket_client.zig`): Replaced `socket.isClosed() or
socket.isShutdown()` with `!this.hasTCP()` as originally proposed. Also
guarded `shutdownRead()` against detached sockets.

2. **Spurious 1006 during clean close** (`src/http/websocket_client.zig`
+ `WebSocketProxyTunnel.zig`): When `sendCloseWithBody` calls
`clearData()`, it shuts down the proxy tunnel. The tunnel's `onClose`
callback was calling `ws.fail(ErrorCode.ended)` which dispatched a 1006
abrupt close, overriding the clean 1000 close already in progress. Fixed
by adding `tunnel.clearConnectedWebSocket()` before `tunnel.shutdown()`
so the callback is a no-op.

### How did you verify your code works?

- `USE_SYSTEM_BUN=1`: Fails with `Unexpected close code: 1006`
- `bun bd test`: Passes with clean 1000 close
- Full proxy test suite: 25 pass, 4 skip, 0 fail
- Related fragmented/close tests: all passing

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-13 14:49:40 -08:00
SUZUKI Sosuke
3debd0a2d2 perf(structuredClone): remove unnecessary zero-fill for Int32 and Double array fast paths (#26989)
## What

Replace two-step `Vector<uint8_t>` zero-initialization + `memcpy` with
direct `std::span` copy construction in the `structuredClone` Int32 and
Double array fast paths.

## Why

The previous code allocated a zero-filled buffer and then immediately
overwrote it with `memcpy`. By constructing the `Vector` directly from a
`std::span`, we eliminate the redundant zero-fill and reduce the
operation to a single copy.

### Before
```cpp
Vector<uint8_t> buffer(byteSize, 0);
memcpy(buffer.mutableSpan().data(), data, byteSize);
```

### After
```cpp
Vector<uint8_t> buffer(std::span<const uint8_t> { reinterpret_cast<const uint8_t*>(data), byteSize });
```

## Test

`bun bd test test/js/web/structured-clone-fastpath.test.ts` — 91/92 pass
(1 pre-existing flaky memory test unrelated to this change).

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 23:50:54 -08:00
robobun
7afead629c fix(linker): defer dynamic import() of unknown node: modules to runtime (#26981)
## Summary

- Defer resolution of dynamic `import()` of unknown `node:` modules
(like `node:sqlite`) to runtime instead of failing at transpile time
- Fix use-after-poison in `addResolveError` by always duping `line_text`
from the source so Location data outlives the arena

Fixes #25707

## Root cause

When a CJS file is `require()`d, Bun's linker eagerly resolves all
import records, including dynamic `import()` expressions. For unknown
`node:` prefixed modules, `whenModuleNotFound` was only deferring
`.require` and `.require_resolve` to runtime — `.dynamic` imports fell
through to the error path, causing the entire `require()` to fail.

This broke Next.js builds with turbopack + `cacheComponents: true` +
Better Auth, because Kysely's dialect detection code uses
`import("node:sqlite")` inside a try/catch that gracefully handles the
module not being available.

Additionally, when the resolve error was generated, the
`Location.line_text` was a slice into arena-allocated source contents.
The arena is reset before `processFetchLog` processes the error, causing
a use-after-poison when `Location.clone` tries to dupe the freed memory.

## Test plan

- [x] New regression test in `test/regression/issue/25707.test.ts` with
3 cases:
- CJS require of file with `import("node:sqlite")` inside try/catch
(turbopack pattern)
  - CJS require of file with bare `import("node:sqlite")` (no try/catch)
  - Runtime error produces correct `ERR_UNKNOWN_BUILTIN_MODULE` code
- [x] Test fails with `USE_SYSTEM_BUN=1` (system bun v1.3.9)
- [x] Test passes with `bun bd test`
- [x] No ASAN use-after-poison crash on debug 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: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2026-02-12 14:47:31 -08:00
Jarred Sumner
9a72bbfae2 Update CLAUDE.md 2026-02-12 14:25:05 -08:00
robobun
7a801fcf93 fix(ini): prevent OOB read and UB on truncated/invalid UTF-8 in INI parser (#26947)
## Summary

- Fix out-of-bounds read in the INI parser's `prepareStr` function when
a multi-byte UTF-8 lead byte appears at the end of a value with
insufficient continuation bytes
- Fix undefined behavior when bare continuation bytes (0x80-0xBF) cause
`utf8ByteSequenceLength` to return 0, hitting an `unreachable` branch
(UB in ReleaseFast builds)
- Add bounds checking before accessing `val[i+1]`, `val[i+2]`,
`val[i+3]` in both escaped and non-escaped code paths

The vulnerability could be triggered by a crafted `.npmrc` file
containing truncated UTF-8 sequences. In release builds, this could
cause OOB heap reads (potential info leak) or undefined behavior.

## Test plan

- [x] Added 9 tests covering truncated 2/3/4-byte sequences, bare
continuation bytes, and escaped contexts
- [x] All 52 INI parser tests pass (`bun bd test
test/js/bun/ini/ini.test.ts`)
- [x] No regressions in npmrc tests (failures are pre-existing Verdaccio
connectivity issues)

🤖 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>
2026-02-12 00:28:44 -08:00
robobun
44541eb574 fix(sql): reject null bytes in connection parameters to prevent protocol injection (#26952)
## Summary

- Reject null bytes in `username`, `password`, `database`, and `path`
connection parameters for both PostgreSQL and MySQL to prevent wire
protocol parameter injection
- Both the Postgres and MySQL wire protocols use null-terminated strings
in their startup/handshake messages, so embedded null bytes in these
fields act as field terminators, allowing injection of arbitrary
protocol parameters (e.g. `search_path` for schema hijacking)
- The fix validates these fields immediately after UTF-8 conversion and
throws `InvalidArguments` error with a clear message if null bytes are
found

## Test plan

- [x] New test
`test/regression/issue/postgres-null-byte-injection.test.ts` verifies:
- Null bytes in username are rejected with an error before any data is
sent
- Null bytes in database are rejected with an error before any data is
sent
- Null bytes in password are rejected with an error before any data is
sent
  - Normal connections without null bytes still work correctly
- [x] Test verified to fail with `USE_SYSTEM_BUN=1` (unfixed bun) and
pass with `bun bd test` (fixed build)
- [x] Existing SQL tests pass (`adapter-env-var-precedence.test.ts`,
`postgres-stringbuilder-assertion-aggressive.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>
2026-02-12 00:27:00 -08:00
robobun
993be3f931 fix(plugin): set virtualModules to nullptr after delete in clearAll (#26940)
## Summary

- Fix double-free in `Bun.plugin.clearAll()` by setting `virtualModules
= nullptr` after `delete`
- In `jsFunctionBunPluginClear` (`BunPlugin.cpp:956`), `delete
global->onLoadPlugins.virtualModules` freed the pointer without
nullifying it. When the `OnLoad` destructor later runs (during Worker
termination or VM destruction), it checks `if (virtualModules)` — the
dangling non-null pointer passes the check and is deleted again,
corrupting the heap allocator.

## Test plan

- [ ] New test
`test/regression/issue/plugin-clearall-double-free.test.ts` spawns a
subprocess that registers a virtual module, calls
`Bun.plugin.clearAll()`, and exits with `BUN_DESTRUCT_VM_ON_EXIT=1` to
trigger the destructor path
- [ ] Verified the test fails on the system bun (pre-fix) with `pas
panic: deallocation did fail ... Alloc bit not set`
- [ ] Verified the test passes with the debug build (post-fix)
- [ ] Existing plugin tests (`test/js/bun/plugin/plugins.test.ts`) all
pass (29/29)

🤖 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>
2026-02-11 23:14:43 -08:00
robobun
a68393926b fix(ws): handle fragmented pong frames and validate control frame size (#26944)
## Summary

- Fix WebSocket client pong frame handler to properly handle payloads
split across TCP segments, preventing frame desync that could cause
protocol confusion
- Add missing RFC 6455 Section 5.5 validation: control frame payloads
must not exceed 125 bytes (pong handler lacked this check, unlike ping
and close handlers)

## Details

The pong handler (lines 652-663) had two issues:

1. **Frame desync on fragmented delivery**: When a pong payload was
split across TCP segments (`data.len < receive_body_remain`), the
handler consumed only the available bytes but unconditionally reset
`receive_state = .need_header` and `receive_body_remain = 0`. The
remaining payload bytes in the next TCP delivery were then
misinterpreted as WebSocket frame headers.

2. **Missing payload length validation**: Unlike the ping handler (line
615) and close handler (line 680), the pong handler did not validate the
7-bit payload length against the RFC 6455 limit of 125 bytes for control
frames.

The fix models the pong handler after the existing ping handler pattern:
track partial delivery state with a `pong_received` boolean, buffer
incoming data into `ping_frame_bytes`, and only reset to `need_header`
after the complete payload has been consumed.

## Test plan

- [x] New test `websocket-pong-fragmented.test.ts` verifies:
- Fragmented pong delivery (50-byte payload split into 2+48 bytes) does
not cause frame desync, and a subsequent text frame is received
correctly
- Pong frames with >125 byte payloads are rejected as invalid control
frames
- [x] Test fails with `USE_SYSTEM_BUN=1` (reproduces the bug) and passes
with `bun bd test`
- [x] Existing WebSocket tests pass: `websocket-client.test.ts`,
`websocket-close-fragmented.test.ts`,
`websocket-client-short-read.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>
2026-02-11 23:12:28 -08:00
robobun
e8a5f23385 fix(s3): reject CRLF characters in header values to prevent header injection (#26942)
## Summary

- Fixes HTTP header injection vulnerability in S3 client where
user-controlled options (`contentDisposition`, `contentEncoding`,
`type`) were passed to HTTP headers without CRLF validation
- Adds input validation at the JS-to-Zig boundary in
`src/s3/credentials.zig` that throws a `TypeError` if `\r` or `\n`
characters are detected
- An attacker could previously inject arbitrary headers (e.g.
`X-Amz-Security-Token`) by embedding `\r\n` in these string fields

## Test plan

- [x] Added `test/regression/issue/s3-header-injection.test.ts` with 6
tests:
  - CRLF in `contentDisposition` throws
  - CRLF in `contentEncoding` throws
  - CRLF in `type` (content-type) throws
  - Lone CR in `contentDisposition` throws
  - Lone LF in `contentDisposition` throws
  - Valid `contentDisposition` without CRLF still works correctly
- [x] Tests fail with `USE_SYSTEM_BUN=1` (confirming vulnerability
exists in current release)
- [x] Tests pass with `bun bd test` (confirming fix works)

🤖 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>
2026-02-11 23:02:39 -08:00
robobun
16b3e7cde7 fix(libarchive): use normalized path in mkdiratZ to prevent directory traversal (#26956)
## Summary

- Fix path traversal vulnerability in tarball directory extraction on
POSIX systems where `mkdiratZ` used the un-normalized `pathname` (raw
from tarball) instead of the normalized `path` variable, allowing `../`
components to escape the extraction root via kernel path resolution
- The Windows directory creation, symlink creation, and file creation
code paths already correctly used the normalized path — only the two
POSIX `mkdiratZ` calls were affected (lines 463 and 469)
- `bun install` is not affected because npm mode skips directory
entries; affected callers include `bun create`, GitHub tarball
extraction, and `compile_target`

## Test plan

- [x] Added regression test that crafts a tarball with
`safe_dir/../../escaped_dir/` directory entry and verifies it cannot
create directories outside the extraction root
- [x] Verified test **fails** with system bun (vulnerable) and
**passes** with debug build (fixed)
- [x] Full `archive.test.ts` suite passes (99/99 tests)
- [x] `symlink-path-traversal.test.ts` continues to pass (3/3 tests)

🤖 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>
2026-02-11 22:47:41 -08:00
robobun
4c32f15339 fix(sql): use constant-time comparison for SCRAM server signature (#26937)
## Summary

- Replace `bun.strings.eqlLong` with BoringSSL's `CRYPTO_memcmp` for
SCRAM-SHA-256 server signature verification in the PostgreSQL client
- The previous comparison (`eqlLong`) returned early on the first
mismatching byte, potentially leaking information about the expected
server signature via timing side-channel
- `CRYPTO_memcmp` is already used elsewhere in the codebase for
constant-time comparisons (CSRF tokens, `crypto.timingSafeEqual`,
KeyObject comparison)

## Test plan

- [x] `bun bd` compiles successfully
- [ ] Existing SCRAM-SHA-256 integration tests in
`test/js/sql/sql.test.ts` pass (require Docker/PostgreSQL)

🤖 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>
2026-02-11 22:45:47 -08:00
robobun
635034ee33 fix(shell): use-after-free in runFromJS when setupIOBeforeRun fails (#26920)
## Summary

- Fixes #26918 — segfault at address `0x28189480080` caused by
use-after-free in the shell interpreter
- When `setupIOBeforeRun()` fails (e.g., stdout handle unavailable on
Windows), the `runFromJS` error path called `deinitFromExec()` which
directly freed the GC-managed interpreter object with
`allocator.destroy(this)`. When the GC later swept and called
`deinitFromFinalizer()` on the already-freed memory, it caused a
segfault.
- Replaced `deinitFromExec()` with `derefRootShellAndIOIfNeeded(true)`
which properly cleans up runtime resources (IO handles, shell
environment) while leaving final object destruction to the GC finalizer
— matching the pattern already used in `finish()`.

## Test plan

- [x] Added regression test in `test/regression/issue/26918.test.ts`
that verifies the shell interpreter handles closed stdout gracefully
without crashing
- [x] Test passes with `bun bd test test/regression/issue/26918.test.ts`
- [ ] The actual crash is primarily reproducible on Windows where stdout
handles can be truly unavailable — CI Windows tests should validate the
fix

🤖 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>
2026-02-11 17:51:10 -08:00
robobun
3e792d0d2e fix(test): write JUnit reporter outfile when --bail triggers early exit (#26852)
## Summary
- When `--bail` caused an early exit after a test failure, the JUnit
reporter output file (`--reporter-outfile`) was never written because
`Global.exit()` was called before the normal completion path
- Extracted the JUnit write logic into a `writeJUnitReportIfNeeded()`
method on `CommandLineReporter` and call it in both bail exit paths
(test failure and unhandled rejection) as well as the normal completion
path

Closes #26851

## Test plan
- [x] Added regression test `test/regression/issue/26851.test.ts` with
two cases:
  - Single failing test file with `--bail` produces JUnit XML output
- Multiple test files where bail triggers on second file still writes
the report
- [x] Verified test fails with system bun (`USE_SYSTEM_BUN=1`)
- [x] Verified test passes with `bun bd 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>
2026-02-11 17:41:45 -08:00
robobun
b7d505b6c1 deflake: make HMR rapid edits test event-driven (#26890)
## Summary
- Add `expectMessageEventually(value)` to the bake test harness `Client`
class — waits for a specific message to appear, draining any
intermediate messages that arrived before it
- Rewrite "hmr handles rapid consecutive edits" test to use raw
`Bun.write` + sleep for intermediate edits and `expectMessageEventually`
for the final assertion, avoiding flaky failures when HMR batches
updates non-deterministically across platforms

Fixes flaky failure on Windows where an extra "render 10" message
arrived after `expectMessage` consumed its expected messages but before
client disposal.

## Test plan
- [x] `bun bd test test/bake/dev-and-prod.test.ts` — all 12 tests pass
- [x] Ran the specific test multiple times to confirm no flakiness

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

Co-authored-by: Alistair Smith <alistair@anthropic.com>
2026-02-11 16:05:25 -08:00
Dylan Conway
50e478dcdc fix(crypto): correct method and constructor names mangled by number renamer (#26876)
## Problem

The bundler's number renamer was mangling `.name` properties on crypto
class prototype methods and constructors:

- `hash.update.name` → `"update2"` instead of `"update"`
- `verify.verify.name` → `"verify2"` instead of `"verify"`
- `cipher.update.name` → `"update3"` instead of `"update"`
- `crypto.Hash.name` → `"Hash2"` instead of `"Hash"`

### Root causes

1. **Named function expressions on prototypes** collided with other
bindings after scope flattening (e.g. `Verify.prototype.verify =
function verify(...)` collided with the imported `verify`)
2. **Block-scoped constructor declarations** (`Hash`, `Hmac`) got
renamed when the bundler hoisted them out of block scope
3. **Shared function declarations** in the Cipher/Decipher block all got
numeric suffixes (`update3`, `final2`, `setAutoPadding2`, etc.)

## Fix

- Use `Object.assign` with object literals for prototype methods —
object literal property keys correctly infer `.name` and aren't subject
to the renamer
- Remove unnecessary block scopes around `Hash` and `Hmac` constructors
so they stay at module level and don't get renamed
- Inline `Cipheriv` methods and copy references to `Decipheriv`

## Tests

Added comprehensive `.name` tests for all crypto classes: Hash, Hmac,
Sign, Verify, Cipheriv, Decipheriv, DiffieHellman, ECDH, plus factory
functions and constructor names.
2026-02-10 23:06:22 -08:00
robobun
e8f73601c0 fix(compile): use remaining buffer in standalone POSIX write loop (#26882)
## What does this PR do?

Fixes the write loop in `StandaloneModuleGraph.inject()` for POSIX
targets (the `else` branch handling ELF/Linux standalone binaries) to
pass `remain` instead of `bytes` to `Syscall.write()`.

## Problem

The write loop that appends the bundled module graph to the end of the
executable uses a standard partial-write retry pattern, but passes the
full `bytes` buffer on every iteration instead of the remaining portion:

```zig
var remain = bytes;
while (remain.len > 0) {
    switch (Syscall.write(cloned_executable_fd, bytes)) {   // bug: should be 'remain'
        .result => |written| remain = remain[written..],
        ...
    }
}
```

If a partial write occurs, the next iteration re-writes from the start
of the buffer instead of continuing where it left off, corrupting the
output binary. The analogous read loop elsewhere in the same file
already correctly uses `remain`.

## Fix

One-character change: `bytes` → `remain` in the `Syscall.write()` call.

## How did you verify your code works?

- `bun bd` compiles successfully
- `bun bd test test/bundler/bun-build-compile.test.ts` — 4/4 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: Alistair Smith <alistair@anthropic.com>
2026-02-10 23:04:46 -08:00
robobun
ba6e84fecd fix(compile): seek to start of file before EXDEV cross-device copy (#26883)
## What does this PR do?

Fixes `bun build --compile` producing an all-zeros binary when the
output directory is on a different filesystem than the temp directory.
This is common in Docker containers, Gitea runners, and other
environments using overlayfs.

## Problem

When `inject()` finishes writing the modified executable to the temp
file, the file descriptor's offset is at EOF. If the subsequent
`renameat()` to the output path fails with `EXDEV` (cross-device — the
temp file and output dir are on different filesystems), the code falls
back to `copyFileZSlowWithHandle()`, which:

1. Calls `fallocate()` to pre-allocate the output file to the correct
size (filled with zeros)
2. Calls `bun.copyFile(in_handle, out_handle)` — but `in_handle`'s
offset is at EOF
3. `copy_file_range` / `sendfile` / `read` all use the current file
offset (EOF), read 0 bytes, and return immediately
4. Result: output file is the correct size but entirely zeros

This explains user reports of `bun build --compile
--target=bun-darwin-arm64` producing invalid binaries that `file`
identifies as "data" rather than a Mach-O executable.

## Fix

Seek the input fd to offset 0 in `copyFileZSlowWithHandle` before
calling `bun.copyFile`.

## How did you verify your code works?

- `bun bd` compiles successfully
- `bun bd test test/bundler/bun-build-compile.test.ts` — 6/6 pass
- Added tests that verify compiled binaries have valid executable
headers and produce correct output
- Manually verified cross-compilation: `bun build --compile
--target=bun-darwin-arm64` produces a valid Mach-O binary

🤖 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>
2026-02-10 22:32:31 -08:00
SUZUKI Sosuke
e29e830a25 perf(path): use pre-built Structure for path.parse() result objects (#26865)
## Summary

Optimize `path.parse()` by caching a pre-built JSC Structure for the
result object. Instead of creating a new empty object and performing 5
`putDirect` calls (each triggering a Structure transition), we now use
`constructEmptyObject` with the cached Structure and write values
directly via `putDirectOffset`.

## What changed

- **`ZigGlobalObject.h/cpp`**: Added `m_pathParsedObjectStructure` as a
`LazyPropertyOfGlobalObject<Structure>` with fixed property offsets for
`{root, dir, base, ext, name}`.
- **`Path.cpp`**: Added `PathParsedObject__create` extern "C" factory
function that constructs the object using the pre-built Structure and
`putDirectOffset`.
- **`path.zig`**: Replaced `toJSObject()` implementation to call the C++
factory function instead of `createEmptyObject` + 5x `.put()`.
- **`bench/snippets/path-parse.mjs`**: Added benchmark for
`path.parse()`.

This follows the same pattern used by `JSSocketAddressDTO` and
`m_jsonlParseResultStructure`.

## Benchmark results (Apple M4 Max)

| Benchmark | Before (1.3.9) | After | Speedup |
|---|---|---|---|
| `posix.parse("/home/user/dir/file.txt")` | 266.71 ns | 119.62 ns |
**2.23x** |
| `posix.parse("/home/user/dir/")` | 239.10 ns | 91.46 ns | **2.61x** |
| `posix.parse("file.txt")` | 232.55 ns | 89.20 ns | **2.61x** |
| `posix.parse("/root")` | 246.75 ns | 92.68 ns | **2.66x** |
| `posix.parse("")` | 152.19 ns | 20.72 ns | **7.34x** |
| `win32.parse("/home/user/dir/file.txt")` | 260.08 ns | 118.12 ns |
**2.20x** |
| `win32.parse("/home/user/dir/")` | 234.35 ns | 93.47 ns | **2.51x** |
| `win32.parse("file.txt")` | 224.19 ns | 80.56 ns | **2.78x** |
| `win32.parse("/root")` | 241.20 ns | 88.23 ns | **2.73x** |
| `win32.parse("")` | 160.39 ns | 24.20 ns | **6.63x** |

**~2.2x–2.8x faster** for typical paths, **~7x faster** for empty
strings.

## GC Safety

- `LazyPropertyOfGlobalObject<Structure>` is automatically visited via
`FOR_EACH_GLOBALOBJECT_GC_MEMBER`.
- JSValues created by `createUTF8ForJS` are protected by JSC's
conservative stack scanning during the factory function call.

## Test

All 116 existing path tests pass (`bun bd test test/js/node/path/`).

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-02-10 22:32:08 -08:00
robobun
4c205486d6 fix(test): update valkey test snapshots for Redis 8 error message format (#26878)
## Summary
- Update inline error snapshots in valkey reliability tests to match
Redis 8's changed error message format
- Redis 8 (`redis:8-alpine` in our test Docker container) no longer
appends `, with args beginning with: ` when an unknown command has no
arguments

## Root cause
Redis commit
[`25f780b6`](25f780b662)
([PR #14690](https://github.com/redis/redis/pull/14690)) changed
`commandCheckExistence()` in `src/server.c` to only append `, with args
beginning with: ` when there are actual arguments (`c->argc >= 2`).
Previously it was always appended, producing a dangling `, with args
beginning with: ` even with zero arguments.

## Changes
- `test/js/valkey/reliability/protocol-handling.test.ts`: Updated
`SYNTAX-ERROR` snapshot (no args case)
- `test/js/valkey/reliability/error-handling.test.ts`: Updated
`undefined` and `123` snapshots (no args cases)

## Test plan
- [ ] Verify `protocol-handling.test.ts` passes in CI (was failing on
every attempt as shown in #26869 / build #36831)
- [ ] Verify `error-handling.test.ts` passes in CI

🤖 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>
2026-02-10 16:30:55 -08:00
Alistair Smith
099b5e430c feat(test): add --retry flag and emit separate testcase entries for retries in JUnit XML (#26866)
#### (Copies commits from #26447)

## Summary
- Add a global `--retry <N>` flag to `bun test` that sets a default
retry count for all tests (overridable by per-test `{ retry: N }`). Also
configurable via `[test] retry = N` in bunfig.toml.
- When a test passes after one or more retries, the JUnit XML reporter
emits a separate `<testcase>` entry for each failed attempt (with
`<failure>`), followed by the final passing `<testcase>`. This gives
flaky test detection tools per-attempt timing and result data using
standard JUnit XML that all CI systems can parse.

## Test plan
- `bun bd test test/js/junit-reporter/junit.test.js` — verifies separate
`<testcase>` entries appear in JUnit XML for tests that pass after retry
- `bun bd test test/cli/test/retry-flag.test.ts` — verifies the
`--retry` CLI flag applies a default retry count to all tests

## Changelog
<!-- CHANGELOG:START -->
- Added `--retry <N>` flag to `bun test` to set a default retry count
for all tests
- Added `[test] retry` option to bunfig.toml
- JUnit XML reporter now emits separate `<testcase>` entries for each
retry attempt, providing CI visibility into flaky tests
<!-- CHANGELOG:END -->

---------

Co-authored-by: Chris Lloyd <chrislloyd@anthropic.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 10:58:21 -08:00
Przemysław Rekucki
746771d495 fix(bake): queue pending HMR scripts for reuse (#19736) (#23995)
## Summary

Fixes "Unknown HMR script" error during rapid consecutive edits in HMR

## Test plan
- [x] Basic consecutive HMR edits work correctly

---------

Co-authored-by: Alistair Smith <alistair@anthropic.com>
2026-02-10 01:53:07 -08:00
Dylan Conway
ae50b05b50 2026-02-09 22:40:52 -08:00
robobun
ead4a8c45d fix(fs): properly handle file: URL strings in fs.watch and fs.watchFile (#26859)
## Summary
- Convert `file:` URL strings to filesystem paths via
`Bun.fileURLToPath()` in the JS layer for both `fs.watch` and
`fs.watchFile`/`fs.unwatchFile`
- Handles percent-decoding (e.g. `%20` → space) and proper URL parsing,
which the previous naive `slice[6..]` stripping in Zig could not do
- Zig-level `file://` stripping is left unchanged; the JS layer now
resolves file URLs before they reach native code

## Test plan
- [x] New test: `fs.watch` with `file:` URL string containing
`%20`-encoded spaces
- [x] New test: `fs.watchFile` with `file:` URL string containing
`%20`-encoded spaces
- [x] Both tests fail with `USE_SYSTEM_BUN=1` and pass with `bun bd
test`
- [x] Existing `fs.watch` "should work with url" test (URL object) still
passes
- [x] Full `fs.watchFile` suite passes (6 pass, 1 skip, 0 fail)

🤖 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>
2026-02-09 22:22:22 -08:00
Jarred Sumner
ce715b5a0f feat(transpiler): implement TC39 standard ES decorators lowering (#26436)
## Summary

- Implement complete lowering of TC39 stage-3 standard ES decorators
(the non-legacy variant used when tsconfig has no
`experimentalDecorators`).
- Passes all 147 esbuild decorator tests and 22 additional Bun-specific
tests (191 total, 0 failures).
- Supports method, getter, setter, field, auto-accessor, private member,
and class decorators in both statement and expression positions, with
proper evaluation order, class binding semantics, and decorator
metadata.

Fixes #4122
Fixes #20206
Fixes #14529
Fixes #6051

## What's implemented

| Feature | Details |
|---|---|
| Method/getter/setter decorators | Static and instance, public and
private |
| Field decorators | Initializer replacement + extra initializers via
`__runInitializers` |
| Auto-accessor (`accessor` keyword) | Lowered to WeakMap storage +
getter/setter pair |
| Private member decorators | WeakMap/WeakSet lowering with
`__privateGet`/`__privateSet` |
| Class decorators | Statement and expression positions |
| Class expression decorators | Comma-expression lowering (no IIFE) |
| Decorator metadata | `Symbol.metadata` support via
`__decoratorMetadata` |
| Evaluation order | All decorator expressions + computed keys evaluated
in source order per TC39 spec |
| Class binding semantics | Separate inner/outer class name bindings
(element vs class decorator closures) |
| Static block extraction | `this` replaced with class name ref when
moved to suffix |
| Computed property keys | Pre-evaluated into temp variables for correct
ordering |

## Runtime helpers

Added to `src/runtime.js` and registered in `src/runtime.zig`:
- `__decoratorStart(base)` — creates decorator context array
- `__decorateElement(array, flags, name, decorators, target, extra)` —
applies decorators to a class element
- `__decoratorMetadata(array, target)` — sets `Symbol.metadata` on the
class
- `__runInitializers(array, flags, self, value)` — runs
initializer/extra-initializer arrays

## Test plan

- [x] `bun bd test
test/bundler/transpiler/es-decorators-esbuild.test.ts` — **147/147
pass** (esbuild's full decorator test suite)
- [x] `bun bd test test/bundler/transpiler/es-decorators.test.ts` —
**22/22 pass**
- [x] `bun bd test test/bundler/transpiler/decorators.test.ts` — **22/22
pass** (legacy decorators still work)
- [x] E2E runtime verification of method, field, accessor, class,
private, and expression decorators

🤖 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>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2026-02-09 22:03:54 -08:00
SUZUKI Sosuke
fa78d2b408 perf(structuredClone): add fast path for arrays containing simple objects (#26818)
## Summary

Adds a **DenseArray fast path** for `structuredClone` / `postMessage`
that completely skips byte-buffer serialization when an
`ArrayWithContiguous` array contains **flat objects** (whose property
values are only primitives or strings).

This builds on #26814 which added fast paths for Int32/Double/Contiguous
arrays of primitives and strings. The main remaining slow case was
**arrays of objects** — the most common real-world pattern (e.g.
`[{name: "Alice", age: 30}, {name: "Bob", age: 25}]`). Previously, these
fell back to the full serialization path because the Contiguous fast
path rejected non-string cell elements.

## How it works

### Serialization
The existing Contiguous array handler is extended to recognize object
elements that pass `isObjectFastPathCandidate` (FinalObject, no
getters/setters, no indexed properties, all enumerable). For qualifying
objects, properties are collected into a `SimpleCloneableObject` struct
(reusing the existing `SimpleInMemoryPropertyTableEntry` type). The
result is stored as a `FixedVector<DenseArrayElement>` where
`DenseArrayElement = std::variant<JSValue, String,
SimpleCloneableObject>`.

If no object elements are found, the existing `SimpleArray` path is used
(no regression).

### Deserialization
A **Structure cache** avoids repeated Structure transitions when the
array contains many same-shape objects (the common case). The first
object is built via `constructEmptyObject` + `putDirect`, and its final
Structure + Identifiers are cached. Subsequent objects with matching
property names are created directly with `JSFinalObject::create(vm,
cachedStructure)`, skipping all transitions.

Safety guards:
- Cache is only used when property count AND all property names match
- Cache is disabled when `outOfLineCapacity() > 0` (properties exceed
`maxInlineCapacity`), since `JSFinalObject::create` cannot allocate a
butterfly

### Fallback conditions

| Condition | Behavior |
|-----------|----------|
| Elements are only primitives/strings | SimpleArray (existing) |
| Elements include `isObjectFastPathCandidate` objects | **DenseArray
(NEW)** |
| Object property value is an object/array | Fallback to normal path |
| Elements include Date, RegExp, Map, Set, ArrayBuffer, etc. | Fallback
to normal path |
| Array has holes | Fallback to normal path |

## Benchmarks

Apple M4 Max, release build vs system Bun v1.3.8 and Node.js v24.12:

| Benchmark | Node.js v24.12 | Bun v1.3.8 | **This PR** | vs Bun | vs
Node |

|-----------|---------------|------------|-------------|--------|---------|
| `[10 objects]` | 2.83 µs | 2.72 µs | **1.56 µs** | **1.7x** | **1.8x**
|
| `[100 objects]` | 24.51 µs | 25.98 µs | **14.11 µs** | **1.8x** |
**1.7x** |

## Test coverage

28 new edge-case tests covering:
- **Property value variants**: empty objects, special numbers (NaN,
Infinity, -0), null/undefined values, empty string keys, boolean-only
values, numeric string keys
- **Structure cache correctness**: alternating shapes, objects
interleaved with primitives, >maxInlineCapacity properties (100+), 1000
same-shape objects (stress test), repeated clone independence
- **Fallback correctness**: array property values, nested objects,
Date/RegExp/Map/Set/ArrayBuffer elements, getters, non-enumerable
properties, `Object.create(null)`, class instances
- **Frozen/sealed**: clones are mutable regardless of source
- **postMessage via MessageChannel**: mixed arrays with objects, empty
object arrays

## Changed files

- `src/bun.js/bindings/webcore/SerializedScriptValue.h` —
`SimpleCloneableObject`, `DenseArrayElement`, `FastPath::DenseArray`,
factory/constructor/member
- `src/bun.js/bindings/webcore/SerializedScriptValue.cpp` — serialize,
deserialize, `computeMemoryCost`
- `test/js/web/structured-clone-fastpath.test.ts` — 28 new tests
- `bench/snippets/structuredClone.mjs` — object array benchmarks

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-02-09 21:54:41 -08:00
SUZUKI Sosuke
b7475d8768 fix(buffer): return fixed-length view from slice on resizable ArrayBuffer (#26822)
## Summary

Follow-up to #26819 ([review
comment](https://github.com/oven-sh/bun/pull/26819#discussion_r2781484939)).
Fixes `Buffer.slice()` / `Buffer.subarray()` on resizable `ArrayBuffer`
/ growable `SharedArrayBuffer` to return a **fixed-length view** instead
of a length-tracking view.

## Problem

The resizable/growable branch was passing `std::nullopt` to
`JSUint8Array::create()`, which creates a length-tracking view. When the
underlying buffer grows, the sliced view's length would incorrectly
expand:

```js
const rab = new ArrayBuffer(10, { maxByteLength: 20 });
const buf = Buffer.from(rab);
const sliced = buf.slice(0, 5);
sliced.length; // 5

rab.resize(20);
sliced.length; // was 10 (wrong), now 5 (correct)
```

Node.js specifies that `Buffer.slice()` always returns a fixed-length
view (verified on Node.js v22).

## Fix

Replace `std::nullopt` with `newLength` in the
`isResizableOrGrowableShared()` branch of
`jsBufferPrototypeFunction_sliceBody`.

## Test

Added a regression test that creates a `Buffer` from a resizable
`ArrayBuffer`, slices it, resizes the buffer, and verifies the slice
length doesn't change.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 04:48:20 -08:00
Jarred Sumner
4494170f74 perf(event_loop): avoid eventfd wakeup for setImmediate on POSIX (#26821)
### What does this PR do?

Instead of calling event_loop.wakeup() (which writes to the eventfd)
when there are pending immediate tasks, use a zero timeout in
getTimeout() so epoll/kqueue returns immediately. This avoids the
overhead of the eventfd write/read cycle on each setImmediate iteration.

On Windows, continue to call .wakeup() since that's cheap for libuv.

Verified with strace: system bun makes ~44k eventfd writes for a 5s
setImmediate loop, while this change makes 0.


### How did you verify your code works?

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-09 04:47:52 -08:00
SUZUKI Sosuke
9484218ba4 perf(buffer): move Buffer.slice/subarray to native C++ with int32 fast path (#26819)
## Summary

Move `Buffer.slice()` / `Buffer.subarray()` from a JS builtin to a
native C++ implementation, eliminating the `adjustOffset` closure
allocation and JS→C++ constructor overhead on every call. Additionally,
add an int32 fast path that skips `toNumber()` (which can invoke
`valueOf`/`Symbol.toPrimitive`) when arguments are already int32—the
common case for calls like `buf.slice(0, 10)`.

## Changes

- **`src/bun.js/bindings/JSBuffer.cpp`**: Add
`jsBufferPrototypeFunction_sliceBody` with `adjustSliceOffsetInt32` /
`adjustSliceOffsetDouble` helpers. Update prototype hash table entries
from `BuiltinGeneratorType` to `NativeFunctionType` for both `slice` and
`subarray`.
- **`src/js/builtins/JSBufferPrototype.ts`**: Remove the JS `slice`
function (was lines 667–687).
- **`bench/snippets/buffer-slice.mjs`**: Add mitata benchmark.

## Benchmark (Apple M4 Max)

| Benchmark | Before (v1.3.8) | After | Speedup |
|---|---|---|---|
| `Buffer(64).slice()` | 27.19 ns | **14.56 ns** | **1.87x** |
| `Buffer(1024).slice()` | 27.84 ns | **14.62 ns** | **1.90x** |
| `Buffer(1M).slice()` | 29.20 ns | **14.89 ns** | **1.96x** |
| `Buffer(64).slice(10)` | 30.26 ns | **16.01 ns** | **1.89x** |
| `Buffer(1024).slice(10, 100)` | 30.92 ns | **18.32 ns** | **1.69x** |
| `Buffer(1024).slice(-100, -10)` | 28.82 ns | **17.37 ns** | **1.66x**
|
| `Buffer(1024).subarray(10, 100)` | 28.67 ns | **16.32 ns** | **1.76x**
|

**~1.7–1.9x faster** across all cases. All 449 buffer tests pass.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 01:46:33 -08:00
robobun
2a5e8ef38c fix(kqueue): fix incorrect filter comparison causing excessive CPU on macOS (#26812)
## Summary

Fixes the remaining kqueue filter comparison bug in
`packages/bun-usockets/src/eventing/epoll_kqueue.c` that caused
excessive CPU usage with network requests on macOS:

- **`us_loop_run_bun_tick` filter comparison (line 302-303):** kqueue
filter values (`EVFILT_READ=-1`, `EVFILT_WRITE=-2`) were compared using
bitwise AND (`&`) instead of equality (`==`). Since these are signed
negative integers (not bitmasks), `(-2) & (-1)` = `-2` (truthy), meaning
every `EVFILT_WRITE` event was also misidentified as `EVFILT_READ`. This
was already fixed in `us_loop_run` (by PR #25475) but the same bug
remained in `us_loop_run_bun_tick`, which is the primary event loop
function used by Bun.

This is a macOS-only issue (Linux uses epoll, which is unaffected).

Closes #26811

## Test plan

- [x] Added regression test at `test/regression/issue/26811.test.ts`
that makes concurrent HTTPS POST requests
- [x] Test passes with `bun bd test test/regression/issue/26811.test.ts`
- [ ] Manual verification on macOS: run the reporter's [repro
script](https://gist.github.com/jkoppel/d26732574dfcdcc6bfc4958596054d2e)
and confirm CPU usage stays low

🤖 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>
2026-02-09 00:52:17 -08:00
robobun
a84f12b816 Use edge-triggered epoll for eventfd wakeups (#26815)
## Summary

- Switch both eventfd wakeup sites (Zig IO watcher loop and usockets
async) to edge-triggered (`EPOLLET`) epoll mode, eliminating unnecessary
`read()` syscalls on every event loop wakeup
- Add `EAGAIN`/`EINTR` overflow handling in `us_internal_async_wakeup`,
matching libuv's approach ([commit
`e5cb1d3d`](https://github.com/libuv/libuv/commit/e5cb1d3d))

With edge-triggered mode, each `write()` to the eventfd produces a new
edge event regardless of the current counter value, so draining the
counter via `read()` is unnecessary. The counter will never overflow in
practice (~18 quintillion wakeups), but overflow handling is included
defensively.

### Files changed

- **`src/io/io.zig`** — Add `EPOLL.ET` to eventfd registration, replace
drain `read()` with `continue`
- **`packages/bun-usockets/src/eventing/epoll_kqueue.c`** — Set
`leave_poll_ready = 1` for async callbacks, upgrade to `EPOLLET` via
`EPOLL_CTL_MOD`, add `EAGAIN`/`EINTR` handling in wakeup write

## Test plan

- [x] Verified with `strace -f -e trace=read,eventfd2` that eventfd
reads are fully eliminated after the change (0 reads on the eventfd fd)
- [x] Confirmed remaining 8-byte reads in traces are timerfd reads
(legitimate, required)
- [x] Stress tested with 50 concurrent async tasks (1000 total
`Bun.sleep(1)` iterations) — all completed correctly
- [x] `LinuxWaker.wait()` (used by `BundleThread` as a blocking sleep)
is intentionally unchanged

🤖 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>
2026-02-09 00:36:30 -08:00
SUZUKI Sosuke
0f43ea9bec perf(structuredClone): add fast path for root-level dense arrays (#26814)
## Summary

Add a fast path for `structuredClone` and `postMessage` when the root
value is a dense array of primitives or strings. This bypasses the full
`CloneSerializer`/`CloneDeserializer` machinery by keeping data in
native C++ structures instead of serializing to a byte stream.

**Important:** This optimization only applies when the root value passed
to `structuredClone()` / `postMessage()` is an array. Nested arrays
within objects still go through the normal serialization path.

## Implementation

Three tiers of array fast paths, checked in order:

| Tier | Indexing Type | Strategy | Applies When |
|------|--------------|----------|--------------|
| **Tier 1** | `ArrayWithInt32` | `memcpy` butterfly data | Dense int32
array, no holes, no named properties |
| **Tier 2** | `ArrayWithDouble` | `memcpy` butterfly data | Dense
double array, no holes, no named properties |
| **Tier 3** | `ArrayWithContiguous` | Copy elements into
`FixedVector<variant<JSValue, String>>` | Dense array of
primitives/strings, no holes, no named properties |

All tiers fall through to the normal serialization path when:
- The array has holes that must forward to the prototype
- The array has named properties (e.g., `arr.foo = "bar"`) — checked via
`structure->maxOffset() != invalidOffset`
- Elements contain non-primitive, non-string values (objects, arrays,
etc.)
- The context requires wire-format serialization (storage, cross-process
transfer)

### Deserialization

- **Tier 1/2:** Allocate a new `Butterfly` via `vm.auxiliarySpace()`,
`memcpy` data back, create array with `JSArray::createWithButterfly()`.
Falls back to normal deserialization if `isHavingABadTime` (forced
ArrayStorage mode).
- **Tier 3:** Pre-convert elements to `JSValue` (including `jsString()`
allocation), then use `JSArray::tryCreateUninitializedRestricted()` +
`initializeIndex()`.

## Benchmarks

Apple M4 Max, comparing system Bun 1.3.8 vs this branch (release build):

| Benchmark | Before | After | Speedup |
|-----------|--------|-------|---------|
| `structuredClone([10 numbers])` | 308.71 ns | 40.38 ns | **7.6x** |
| `structuredClone([100 numbers])` | 1.62 µs | 86.87 ns | **18.7x** |
| `structuredClone([1000 numbers])` | 13.79 µs | 544.56 ns | **25.3x** |
| `structuredClone([10 strings])` | 642.38 ns | 307.38 ns | **2.1x** |
| `structuredClone([100 strings])` | 5.67 µs | 2.57 µs | **2.2x** |
| `structuredClone([10 mixed])` | 446.32 ns | 198.35 ns | **2.3x** |
| `structuredClone(nested array)` | 1.84 µs | 1.79 µs | 1.0x (not
eligible) |
| `structuredClone({a: 123})` | 95.98 ns | 100.07 ns | 1.0x (no
regression) |

Int32 arrays see the largest gains (up to 25x) since they use a direct
`memcpy` of butterfly memory. String/mixed arrays see ~2x improvement.
No performance regression on non-eligible inputs.

## Bug Fix

Also fixes a correctness bug where arrays with named properties (e.g.,
`arr.foo = "bar"`) would lose those properties when going through the
array fast path. Added a `structure->maxOffset() != invalidOffset` guard
to fall back to normal serialization for such arrays.

Fixed a minor double-counting issue in `computeMemoryCost` where
`JSValue` elements in `SimpleArray` were counted both by `byteSize()`
and individually.

## Test Plan

38 tests in `test/js/web/structured-clone-fastpath.test.ts` covering:

- Basic array types: empty, numbers, strings, mixed primitives, special
numbers (`-0`, `NaN`, `Infinity`)
- Large arrays (10,000 elements)
- Tier 2: double arrays, Int32→Double transition
- Deep clone independence verification
- Named properties on Int32, Double, and Contiguous arrays
- `postMessage` via `MessageChannel` for Int32, Double, and mixed arrays
- Edge cases: frozen/sealed arrays, deleted elements (holes), `length`
extension, single-element arrays
- Prototype modification (custom prototype, indexed prototype properties
with holes)
- `Array` subclass identity loss (per spec)
- `undefined`-only and `null`-only arrays
- Multiple independent clones from the same source

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-02-08 21:36:59 -08:00
Jarred Sumner
0889897a1c Revert "feat(bundler): add configurable CJS→ESM unwrapping via unwrapCJSToESM"
This reverts commit e3c25260ed.
2026-02-08 19:49:26 -08:00
Jarred Sumner
68f2ea4b95 Fix release script 2026-02-08 01:39:10 -08:00
Jarred Sumner
d4ebfd9771 Bump 2026-02-08 01:32:25 -08:00
Jarred Sumner
e3c25260ed feat(bundler): add configurable CJS→ESM unwrapping via unwrapCJSToESM
Add `minify.unwrapCJSToESM` JS API option and `--unwrap-cjs-to-esm` CLI
flag to force CJS-to-ESM conversion for specific packages, eliminating
the `__commonJS` wrapper. Supports wildcard patterns (e.g. `"@scope/*"`).
User entries extend the default React family list.

Also removes the react/react-dom version check that gated conversion,
and fixes `packageName()` to handle scoped packages (`@scope/pkg`).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 01:32:10 -08:00
Alistair Smith
1bded85718 types: Enable --splitting with compile (#26796)
### What does this PR do?

Enables --splitting with compile

### How did you verify your code works?

Bun types integration test fixture updates
2026-02-07 13:39:18 -08:00
Dylan Conway
cf6cdbbbad Revert "Mimalloc v3 update (#26379)" (#26783)
This reverts commit c63415c9c9.

### What does this PR do?

### How did you verify your code works?
2026-02-06 18:05:17 -08:00
robobun
89d2b1cd0b fix(websocket): add missing incPendingActivityCount() in blob binaryType case (#26670)
## Summary

- Fix crash ("Pure virtual function called!") when WebSocket client
receives binary data with `binaryType = "blob"` and no event listener
attached
- Add missing `incPendingActivityCount()` call before `postTask` in the
Blob case of `didReceiveBinaryData`
- Add regression test for issue #26669

## Root Cause

The Blob case in `didReceiveBinaryData` (WebSocket.cpp:1324-1331) was
calling `decPendingActivityCount()` inside the `postTask` callback
without a matching `incPendingActivityCount()` beforehand. This bug was
introduced in #21471 when Blob support was added.

The ArrayBuffer and NodeBuffer cases correctly call
`incPendingActivityCount()` before `postTask`, but the Blob case was
missing this call.

## Test plan

- [x] New regression test verifies WebSocket with `binaryType = "blob"`
doesn't crash on ping frames
- [x] `bun bd test test/regression/issue/26669.test.ts` passes

Fixes #26669

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Ciro Spaciari MacBook <ciro@anthropic.com>
2026-02-05 20:39:19 -08:00
Jarred Sumner
2019a1b11d Bump WebKit 2026-02-05 20:09:39 -08:00
SUZUKI Sosuke
6c70ce2485 Update WebKit to 7bc2f97e28353062bb54776ce01e4c2ff24c35cc (#26769)
### What does this PR do?

### How did you verify your code works?
2026-02-05 17:58:30 -08:00
SUZUKI Sosuke
0e386c4168 fix(stringWidth): correct width for Thai/Lao spacing vowels (#26728)
## Summary

`Bun.stringWidth` was incorrectly treating Thai SARA AA (U+0E32), SARA
AM (U+0E33), and their Lao equivalents (U+0EB2, U+0EB3) as zero-width
characters.

## Root Cause

In `src/string/immutable/visible.zig`, the range check for Thai/Lao
combining marks was too broad:
- Thai: `0xe31 <= cp <= 0xe3a` included U+0E32 and U+0E33
- Lao: `0xeb1 <= cp <= 0xebc` included U+0EB2 and U+0EB3

According to Unicode (UCD Grapheme_Break property), these are **spacing
vowels** (Grapheme_Base), not combining marks.

## Changes

- **`src/string/immutable/visible.zig`**: Exclude U+0E32, U+0E33,
U+0EB2, U+0EB3 from zero-width ranges
- **`test/js/bun/util/stringWidth.test.ts`**: Add tests for Thai and Lao
spacing vowels

## Before/After

| Character | Before | After |
|-----------|--------|-------|
| `\u0E32` (SARA AA) | 0 | 1 |
| `\u0E33` (SARA AM) | 0 | 1 |
| `คำ` (common Thai word) | 1 | 2 |
| `\u0EB2` (Lao AA) | 0 | 1 |
| `\u0EB3` (Lao AM) | 0 | 1 |

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-02-05 17:31:15 -08:00
Alistair Smith
e5cd034e9a Define seed in crc32 types (#26754)
### What does this PR do?

Fixes #26711 

### How did you verify your code works?

bun-types.test.ts integration test
2026-02-05 06:41:25 -08:00
Dylan Conway
45b9d1baba Revert "fix(bindgen): prevent use-after-free for optional string argu… (#26742)
…ments (#26717)"

This reverts commit 315e822866.

### 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>
2026-02-04 19:38:12 -08:00
Ciro Spaciari
0ad562d3bd fix(http2) Fix SSLWrapper and allow injecting connections in Http2SecureServer (#26539)
### What does this PR do?

Enables the `net.Server → Http2SecureServer` connection upgrade pattern
used by libraries like
[http2-wrapper](https://github.com/szmarczak/http2-wrapper),
[crawlee](https://github.com/apify/crawlee), and custom HTTP/2 proxy
servers. This pattern works by accepting raw TCP connections on a
`net.Server` and forwarding them to an `Http2SecureServer` via
`h2Server.emit('connection', rawSocket)`.

#### Bug fixes

**SSLWrapper use-after-free (Zig)**

Two use-after-free bugs in `ssl_wrapper.zig` are fixed:

1. **`flush()` stale pointer** — `flush()` captured the `ssl` pointer
*before* calling `handleTraffic()`, which can trigger a close callback
that frees the SSL object via `deinit`. The pointer was then used after
being freed. Fix: read `this.ssl` *after* `handleTraffic()` returns.

2. **`handleReading()` null dereference** — `handleReading()` called
`triggerCloseCallback()` after `triggerDataCallback()` without checking
whether the data callback had already closed the connection. This led to
a null function pointer dereference. Fix: check `this.ssl == null ||
this.flags.closed_notified` before calling the close callback.

### How did you verify your code works?

- Added **13 in-process tests** (`node-http2-upgrade.test.mts`) covering
the `net.Server → Http2SecureServer` upgrade path:
  - GET/POST requests through upgraded connections
  - Sequential requests sharing a single H2 session
  - `session` event emission
  - Concurrent clients with independent sessions
  - Socket close ordering (rawSocket first vs session first) — no crash
  - ALPN protocol negotiation (`h2`)
  - Varied status codes (200, 302, 404)
  - Client disconnect mid-response (stream destroyed early)
  - Three independent clients producing three distinct sessions
- Tests use `node:test` + `node:assert` and **pass in both Bun and
Node.js**
- Ported `test-http2-socket-close.js` from the Node.js test suite,
verifying no segfault when the raw socket is destroyed before the H2
session is closed

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-02-04 19:23:29 -08:00
Ciro Spaciari
63a323a511 fix(http): don't enter tunnel mode for proxy-style absolute URLs in request line (#26737)
## Summary

Fixes a bug where sequential HTTP requests with proxy-style absolute
URLs (e.g. `GET http://example.com/path HTTP/1.1`) hang on the 2nd+
request when using keep-alive connections.

## Root Cause

In `packages/bun-uws/src/HttpParser.h`, the parser was treating
proxy-style absolute URLs identically to `CONNECT` method requests —
setting `isConnectRequest = true` and entering tunnel mode. This flag
was never reset between requests on the same keep-alive connection, so
the 2nd+ request was swallowed as raw tunnel data instead of being
parsed as HTTP.

## Fix

3-line change in `HttpParser.h:569`:
- **`isConnect`**: Now only matches actual `CONNECT` method requests
(removed `isHTTPorHTTPSPrefixForProxies` from the condition)
- **`isProxyStyleURL`**: New variable that detects `http://`/`https://`
prefixes and accepts them as valid request targets — without triggering
tunnel mode

## Who was affected

- Any Bun HTTP server (`Bun.serve()` or `node:http createServer`)
receiving proxy-style requests on keep-alive connections
- HTTP proxy servers built with Bun could only handle one request per
connection
- Bun's own HTTP client making sequential requests through an HTTP proxy
backed by a Bun server

## Test

Added `test/js/node/http/node-http-proxy-url.test.ts` with 3 test cases:
1. Sequential GET requests with absolute URL paths
2. Sequential POST requests with absolute URL paths
3. Mixed normal and proxy-style URLs

Tests run under both Node.js and Bun for compatibility verification.

-  Fails with system bun (2/3 tests timeout on 2nd request)
-  Passes with debug build (3/3 tests pass)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-02-04 19:23:18 -08:00
星星魔法术
af76296637 fix(docs): update runtime/markdown page Callout component (#26729)
### What does this PR do?
Fix #26727 
fix the Page Not Found bug 
### How did you verify your code works?
I run the development server:
```bash
mint dev
```

<img width="1287" height="823" alt="Markdown"
src="https://github.com/user-attachments/assets/555716b4-1aee-46bd-b066-1e00986b3923"
/>
2026-02-03 22:59:12 -08:00
Dylan Conway
d1047c2cf1 fix ci (#26703)
### What does this PR do?

### How did you verify your code works?
2026-02-03 22:18:40 -08:00
robobun
315e822866 fix(bindgen): prevent use-after-free for optional string arguments (#26717)
## Summary
- Fix a use-after-free bug in the bindgen code generator where string
arguments with default values would have their underlying WTF::String
destroyed before the BunString was used
- The issue occurred because for optional string parameters with
defaults, a WTF::String was created inside an `if` block, converted to
BunString, then the if block closed and destroyed the WTF::String while
the BunString was still in use
- This manifested as a segfault in `Bun.stringWidth()` and potentially
other functions using optional string arguments

## Details

The crash stack trace showed:
```
Segmentation fault at address 0x31244B0F0
visible.zig:888: string.immutable.visible.visible.visibleUTF16WidthFn
BunObject.zig:1371: bindgen_BunObject_dispatchStringWidth1
GeneratedBindings.cpp:242: bindgen_BunObject_jsStringWidth
```

The generated code before this fix looked like:
```cpp
BunString argStr;
if (!arg0.value().isUndefinedOrNull()) {
    WTF::String wtfString_0 = WebCore::convert<...>(...);
    argStr = Bun::toString(wtfString_0);
}  // <-- wtfString_0 destroyed here!
// ... argStr used later, pointing to freed memory
```

The fix declares the WTF::String holder outside the if block:
```cpp
BunString argStr;
WTF::String wtfStringHolder_0;  // Lives until function returns
if (!arg0.value().isUndefinedOrNull()) {
    wtfStringHolder_0 = WebCore::convert<...>(...);
}
if (!wtfStringHolder_0.isEmpty()) argStr = Bun::toString(wtfStringHolder_0);
// argStr now points to valid memory
```

This fix applies to both:
- Direct string function arguments with defaults (e.g.,
`t.DOMString.default("")`)
- Dictionary fields with string defaults

## Test plan
- [x] Existing `stringWidth.test.ts` tests pass (105 tests)
- [x] Manual testing with GC stress shows no crashes
- [x] `os.userInfo()` with encoding option works correctly

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 17:44:13 -08:00
Andrew Johnston
7f498a2e07 chore: improve markdown to html perf (#26644)
### What does this PR do?

I was looking at the [recent
support](https://github.com/oven-sh/bun/pull/26440) for markdown and did
some benchmarking against
[bindings](https://github.com/just-js/lo/blob/main/lib/md4c/api.js) i
created for my `lo` runtime to `md4c`. In some cases, Bun is quite a bit
slower, so i did a bit of digging and came up with this change. It uses
`indexOfAny` which should utilise `SIMD` where it's available to scan
ahead in the payload for characters that need escaping.

In
[benchmarks](https://gist.github.com/billywhizz/397f7929a8920c826c072139b695bb68#file-results-md)
I have done this results in anywhere from `3%` to `~15%` improvement in
throughput. The bigger the payload and the more space between entities
the bigger the gain afaict, which would make sense.

### How did you verify your code works?

It passes `test/js/bun/md/*.test.ts` running locally. Only tested on
macos. Can test on linux but I assume that will happen in CI anyway?

## main


![bun-main](https://github.com/user-attachments/assets/8b173b34-1f20-4e52-bb67-bb8b7e5658f3)

## patched


![bun-patch](https://github.com/user-attachments/assets/26bb600c-234c-4903-8f70-32f167481156)
2026-02-03 00:51:25 -08:00
Dylan Conway
5d4b1821f3 [publish images] test windows aarch64 CI (#26701)
### What does this PR do?

### How did you verify your code works?
2026-02-02 23:25:13 -08:00
Dylan Conway
41de7a3bfb [publish images] Upgrade LLVM toolchain from 19.1.7 to 21.1.8 (#26667)
## Summary
- Update LLVM version references across build scripts, Dockerfiles, CI,
Nix configs, and documentation
- Fix LLVM 21 `-Wcharacter-conversion` errors in WebKit bindings:
- `EncodingTables.h`: pragma for intentional char32_t/char16_t
comparisons
- `TextCodecCJK.cpp`: widen `gb18030AsymmetricEncode` param to char32_t
- `URLPatternParser`: widen `isValidNameCodepoint` param to char32_t,
cast for `startsWith`
- Fix `__libcpp_verbose_abort` noexcept mismatch (LLVM 21 uses
`_NOEXCEPT`)
- Fix dangling pointer in `BunJSCModule.h` (`toCString` temporary
lifetime)
- Remove `useMathSumPreciseMethod` (removed upstream in JSC)

**Before merging:** Merge https://github.com/oven-sh/WebKit/pull/153
first, then update `WEBKIT_VERSION` in `cmake/tools/SetupWebKit.cmake`
to point to the merged commit.

## Test plan
- [ ] Build bun debug on macOS with LLVM 21
- [ ] Build bun on Linux (glibc)
- [ ] Build bun on Linux (musl)
- [ ] Build bun on Windows
- [ ] Run test suite

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>
2026-02-02 23:12:21 -08:00
Chris Lloyd
d23312d3f6 feat(test): add Symbol.dispose support to mock/spyOn (#26692)
## Summary

- Add `[Symbol.dispose]` to mock function prototype, aliased to
`mockRestore`
- Enables `using spy = spyOn(obj, "method")` to auto-restore when
leaving scope
- Works for both `spyOn()` and `mock()`

Addresses #6040 — gives users a clean way to scope spy lifetimes instead
of manually calling `mockRestore()` or relying on `afterEach`.

### Example

```ts
import { spyOn, expect, test } from "bun:test";

test("auto-restores spy", () => {
  const obj = { method: () => "original" };

  {
    using spy = spyOn(obj, "method").mockReturnValue("mocked");
    expect(obj.method()).toBe("mocked");
  }

  // automatically restored
  expect(obj.method()).toBe("original");
});
```

## Test plan

- `bun bd test test/js/bun/test/mock-disposable.test.ts` — 3 tests pass
- Verified tests fail with `USE_SYSTEM_BUN=1`
2026-02-02 17:39:36 -08:00
SUZUKI Sosuke
de8c754c6a perf(markdown): cache tag strings in React renderer (#26668)
## Summary

Cache frequently-used HTML tag strings (div, p, h1-h6, etc.) in
`GlobalObject` using `LazyProperty<JSGlobalObject, JSString>` instead of
creating new JSStrings on every React element creation in
`Bun.markdown.react()`.

## Changes

- Added `BunMarkdownTagStrings.h/.cpp` with 30 cached tag strings
- Modified `MarkdownObject.zig` to use cached strings via C API
- Integrated with `ZigGlobalObject` for proper GC visiting

## Benchmark Results

All benchmarks performed on Apple M4 Max with release builds.

### mitata Benchmark (Bun.markdown.react)

| Size | Main | Feature | Improvement |
|------|------|---------|-------------|
| small (121 chars) | 3.20 µs | 2.30 µs | **28% faster** |
| medium (1039 chars) | 15.09 µs | 14.02 µs | **7% faster** |
| large (20780 chars) | 288.48 µs | 267.14 µs | **7.4% faster** |

### Heap Profile

| Metric | Main | Feature | Improvement |
|--------|------|---------|-------------|
| Heap size | 500.7 KB | 469.7 KB | **6% reduction** |
| Object count | 12,000 | 10,315 | **14% reduction** |
| String count | 4,248 | 2,563 | **40% reduction** |
| String size | 97.1 KB | 65.8 KB | **32% reduction** |

### HTTP Request Benchmark (ab -n 10000 -c 20)

| Metric | Main | Feature | Improvement |
|--------|------|---------|-------------|
| Requests/sec | 7,710 | 8,174 | **6% faster** |
| Time/request | 2.59 ms | 2.45 ms | **5% faster** |
| p99 latency | 6 ms | 3 ms | **50% improvement** |

## Technical Details

The optimization uses JSC's `LazyProperty` pattern (similar to
`BunCommonStrings` and `BunHttp2CommonStrings`) to lazily initialize and
cache tag strings on first use. This avoids repeated
`bun.String.createUTF8ForJS` calls which allocate new JSStrings for the
same tag names on every markdown element.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-02-02 17:08:39 -08:00
Jarred Sumner
27e1363a66 Make GC release access skip interval configurable (#26699)
## Summary
- Make `defaultRemainingRunsUntilSkipReleaseAccess` configurable at
runtime instead of a compile-time constant
- Add `BUN_GC_RUNS_UNTIL_SKIP_RELEASE_ACCESS` environment variable to
control how many idle event loop iterations pass before skipping JSC
heap `releaseAccess` calls in `onBeforeWait`
- Default remains 10, matching the previous hardcoded value

## Test plan
- [ ] Verify default behavior is unchanged (no env var set, value is 10)
- [ ] Verify `BUN_GC_RUNS_UNTIL_SKIP_RELEASE_ACCESS=0` causes release
access to be skipped every iteration
- [ ] Verify `BUN_GC_RUNS_UNTIL_SKIP_RELEASE_ACCESS=100` delays skipping
for 100 idle iterations
- [ ] Verify negative values are ignored (default is preserved)
- [ ] Verify non-numeric values are ignored (default is preserved)

## Changelog
<!-- CHANGELOG:START -->
<!-- CHANGELOG:END -->

🤖 Generated with [Claude Code](https://claude.com/claude-code) (0%
3-shotted by claude)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 17:07:20 -08:00
SUZUKI Sosuke
eba4da23e6 perf: skip Event creation in AbortSignal.abort() when no listeners (#26686)
## Summary

This is a tiny optimization that skips creating and dispatching an Event
object when `AbortSignal.abort()` is called with no registered
listeners.

## Changes

When there are no listeners (no `addEventListener` or `onabort`), we now
check `hasEventListeners()` before creating the Event, avoiding:
- Event object allocation (~112 bytes)
- EventPath creation
- dispatchEvent overhead (hash map lookups, method calls)

## Performance

Improvement for the no-listener case:
- **~6% faster** in micro-benchmarks
- ~16ms saved per 1M `abort()` calls (271ms → 255ms)

| Case | Before | After | Improvement |
|------|--------|-------|-------------|
| no listener | 271 ms | 255 ms | ~6% |
| with listener | 368 ms | 370 ms | (same) |

## Why this is safe

The optimization has no observable side effects because:
- `dispatchEvent` is called from C++, not observable via JS
monkey-patching
- Without listeners, no code can obtain a reference to the Event object
- All internal state (`aborted`, `reason`) is set correctly regardless

## Test Plan

- Existing AbortController/AbortSignal tests pass
- Added mitata benchmark: `bench/snippets/abort-signal.mjs`
2026-02-02 14:01:25 -08:00
robobun
ddefa11070 fix(fs): handle '.' path normalization on Windows (#26634)
## Summary
- Fix path normalization for "." on Windows where `normalizeStringBuf`
was incorrectly stripping it to an empty string
- This caused `existsSync('.')`, `statSync('.')`, and other fs
operations to fail on Windows

## Test plan
- Added regression test `test/regression/issue/26631.test.ts` that tests
`existsSync`, `exists`, `statSync`, and `stat` for both `.` and `..`
paths
- All tests pass locally with `bun bd test
test/regression/issue/26631.test.ts`
- Verified code compiles on all platforms with `bun run zig:check-all`

Fixes #26631

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 00:33:59 -08:00
Dylan Conway
35f8154319 bump versions 2026-01-31 17:38:23 -08:00
robobun
9d68ec882a require --compile for ESM bytecode (#26624)
## Summary
- Add validation to require `--compile` when using ESM bytecode
- Update documentation to clarify ESM bytecode requirements

## Why
ESM module resolution is two-phase: (1) analyze imports/exports, (2)
evaluate. Without `--compile`, there's no `module_info` embedded, so JSC
must still parse the file for module analysis even with bytecode -
causing a double-parse deopt.

## Changes
- **CLI**: Error when `--bytecode --format=esm` is used without
`--compile`
- **JS API**: Error when `bytecode: true, format: 'esm'` is used without
`compile: true`
- **Docs**: Update bytecode.mdx, executables.mdx, index.mdx to clarify
requirements
- **Types**: Update JSDoc for bytecode option in bun.d.ts

## Test plan
```bash
# Should error
bun build ./test.js --bytecode --format=esm --outdir=./out
# error: ESM bytecode requires --compile. Use --format=cjs for bytecode without --compile.

# Should work
bun build ./test.js --bytecode --format=esm --compile --outfile=./mytest
bun build ./test.js --bytecode --format=cjs --outdir=./out
```

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-31 17:35:03 -08:00
Dylan Conway
1337f5dba4 add --cpu-prof-interval flag (#26620)
Adds `--cpu-prof-interval` to configure the CPU profiler sampling
interval in microseconds (default: 1000), matching Node.js's
`--cpu-prof-interval` flag.

```sh
bun --cpu-prof --cpu-prof-interval 500 index.js
```

- Parsed as `u32`, truncated to `c_int` when passed to JSC's
`SamplingProfiler::setTimingInterval`
- Invalid values silently fall back to the default (1000μs)
- Warns if used without `--cpu-prof` or `--cpu-prof-md`

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 16:59:03 -08:00
robobun
56b5be4ba4 fix(shell): prevent double-free during GC finalization (#26626)
## Summary

Fixes #26625

This fixes a segmentation fault that occurred on Windows x64 when the GC
finalizer tried to free shell interpreter resources that were already
partially freed during normal shell completion.

- Added explicit `cleanup_state` enum to track resource ownership state
- `needs_full_cleanup`: Nothing cleaned up yet, finalizer must clean
everything
- `runtime_cleaned`: `finish()` already cleaned IO/shell, finalizer
skips those
- Early return in `#derefRootShellAndIOIfNeeded()` when already cleaned
- Explicit state-based cleanup in `deinitFromFinalizer()`

The vulnerability existed on all platforms but was most reliably
triggered on Windows with high GC pressure (many concurrent shell
commands).

## Test plan

- [x] Build passes (`bun bd`)
- [x] New regression test added (`test/regression/issue/26625.test.ts`)
- [x] Existing shell tests pass (same 4 pre-existing failures, no new
failures)


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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2026-01-31 16:57:59 -08:00
Dylan Conway
6c119d608e Simplify bun run build:local to auto-build JSC (#26645)
## Summary

- `bun run build:local` now handles everything: configuring JSC,
building JSC, and building Bun in a single command on all platforms
(macOS, Linux, Windows). Previously required manually running `bun run
jsc:build:debug`, deleting a duplicate `InspectorProtocolObjects.h`
header, and then running the Bun build separately.
- Incremental JSC rebuilds: JSC is built via `add_custom_target` that
delegates to JSC's inner Ninja, which tracks WebKit source file changes
and only rebuilds what changed. `ninja -Cbuild/debug-local` also works
after the first build.
- Cross-platform support:
  - macOS: Uses system ICU automatically
- Linux: Uses system ICU via find_package instead of requiring bundled
static libs
- Windows: Builds ICU from source automatically (only when libs don't
already exist), sets up static CRT and ICU naming conventions

### Changes
- cmake/tools/SetupWebKit.cmake: Replace the old WEBKIT_LOCAL block
(which just set include paths and assumed JSC was pre-built) with full
JSC configure + build integration for all platforms
- cmake/targets/BuildBun.cmake: Add jsc as a build dependency, use
system ICU on Linux for local builds, handle bmalloc linking for local
builds
- CONTRIBUTING.md / docs/project/contributing.mdx: Simplify "Building
WebKit locally" docs from ~15 lines of manual steps to 3 lines

## Test plan

- [x] macOS arm64: clean build, incremental rebuild, WebKit source
change rebuild
- [x] Windows x64: clean build with ICU, incremental rebuild with ICU
skip
- [x] Linux x64: build with system ICU via find_package
- [x] No duplicate InspectorProtocolObjects.h errors
- [x] build/debug-local/bun-debug --version works

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

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-31 16:52:51 -08:00
Ciro Spaciari
a14a89ca95 fix(proxy): respect NO_PROXY for explicit proxy options in fetch and ws (#26608)
### What does this PR do?

Extract NO_PROXY checking logic from getHttpProxyFor into a reusable
isNoProxy method on the env Loader. This allows both fetch() and
WebSocket to check NO_PROXY even when a proxy is explicitly provided via
the proxy option (not just via http_proxy env var).

Changes:
- env_loader.zig: Extract isNoProxy() from getHttpProxyFor()
- FetchTasklet.zig: Check isNoProxy() before using explicit proxy
- WebSocket.cpp: Check Bun__isNoProxy() before using explicit proxy
- virtual_machine_exports.zig: Export Bun__isNoProxy for C++ access
- Add NO_PROXY tests for both fetch and WebSocket proxy paths

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

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-01-30 16:20:45 -08:00
robobun
a5246344fa fix(types): Socket.reload() now correctly expects { socket: handler } (#26291)
## Summary
- Fix type definition for `Socket.reload()` to match runtime behavior
- The runtime expects `{ socket: handler }` but types previously
accepted just `handler`

## Test plan
- [x] Added regression test `test/regression/issue/26290.test.ts`
- [x] Verified test passes with `bun bd test`

Fixes #26290

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

---------

Co-authored-by: Alistair Smith <hi@alistair.sh>
2026-01-30 13:23:04 -08:00
robobun
f648483fe7 fix(types): add missing SIMD variants to Bun.Build.CompileTarget type (#26248)
## Summary

- Adds missing SIMD variants to the `Build.Target` TypeScript type
- The runtime accepts targets like `bun-linux-x64-modern` but TypeScript
was rejecting them
- Generalized the type to use `${Architecture}` template where possible

## Test plan

- [x] Added regression test in `test/regression/issue/26247.test.ts`
that validates all valid target combinations type-check correctly
- [x] Verified with `bun bd test test/regression/issue/26247.test.ts`

Fixes #26247

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

---------

Co-authored-by: Alistair Smith <hi@alistair.sh>
2026-01-30 13:13:28 -08:00
ddmoney420
01fa61045f fix(types): add missing bun-linux-x64-${SIMD} compile target type (#26607)
## Summary

- Adds missing `bun-linux-x64-baseline` and `bun-linux-x64-modern`
compile target types
- These targets are supported by the Bun CLI but were missing from the
TypeScript type definitions

## Changes

Added `bun-linux-x64-${SIMD}` to the `CompileTarget` type union, which
expands to:
- `bun-linux-x64-baseline`
- `bun-linux-x64-modern`

## Test plan

- [x] TypeScript should now accept `target: 'bun-linux-x64-modern'`
without type errors

Closes #26247

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-01-30 12:21:11 -08:00
Alistair Smith
71ce550cfa esm bytecode (#26402)
### 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 <noreply@anthropic.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-01-30 01:38:45 -08:00
robobun
8f61adf494 Harden chunked encoding parser (#26594)
## Summary
- Improve handling of fragmented chunk data in the HTTP parser
- Add test coverage for edge cases

## Test plan
- [x] New tests pass
- [x] Existing tests pass

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 01:18:39 -08:00
Dylan Conway
b4b7cc6d78 fix multi-run.test.ts on windows (#26590)
### What does this PR do?

fixes https://github.com/oven-sh/bun/issues/26597

### How did you verify your code works?

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-29 23:35:53 -08:00
SUZUKI Sosuke
3feea91087 ci: add QEMU JIT stress tests when WebKit is updated (#26589)
## Summary

Add a CI step that runs JSC JIT stress tests under QEMU when
`SetupWebKit.cmake` is modified. This complements #26571 (basic baseline
CPU verification) by also testing JIT-generated code.

## Motivation

PR #26571 added QEMU-based verification that catches illegal
instructions in:
- Startup code
- Static initialization
- Basic interpreter execution

However, JIT compilers (DFG, FTL, Wasm BBQ/OMG) generate code at runtime
that could emit AVX or LSE instructions even if the compiled binary
doesn't. The JSC stress tests from #26380 exercise all JIT tiers through
hot loops that trigger tier-up.

## How it works

1. Detects if `cmake/tools/SetupWebKit.cmake` is modified in the PR
2. If WebKit changes are detected, runs `verify-jit-stress-qemu.sh`
after the build
3. Executes all 78 JIT stress test fixtures under QEMU with restricted
CPU features:
   - x64: `qemu-x86_64 -cpu Nehalem` (SSE4.2, no AVX)
   - aarch64: `qemu-aarch64 -cpu cortex-a53` (ARMv8.0-A, no LSE)
4. Any SIGILL from JIT-generated code fails the build

## Platforms tested

| Target | CPU Model | What it catches |
|---|---|---|
| `linux-x64-baseline` | Nehalem | JIT emitting AVX/AVX2/AVX512 |
| `linux-x64-musl-baseline` | Nehalem | JIT emitting AVX/AVX2/AVX512 |
| `linux-aarch64` | Cortex-A53 | JIT emitting LSE atomics, SVE |
| `linux-aarch64-musl` | Cortex-A53 | JIT emitting LSE atomics, SVE |

## Timeout

The step has a 30-minute timeout since QEMU emulation is ~10-50x slower
than native. This only runs on WebKit update PRs, so it won't affect
most CI runs.

## Refs

- #26380 - Added JSC JIT stress tests
- #26571 - Added basic QEMU baseline verification
2026-01-29 21:12:36 -08:00
Jarred Sumner
bb4d5b9af5 feat(cli/run): add --parallel and --sequential for running multiple scripts with workspace support (#26551)
## Summary

Adds `bun run --parallel` and `bun run --sequential` — new flags for
running multiple package.json scripts concurrently or sequentially with
Foreman-style prefixed output. Includes full `--filter`/`--workspaces`
integration for running scripts across workspace packages.

### Usage

```bash
# Run "build" and "test" concurrently from the current package.json
bun run --parallel build test

# Run "build" and "test" sequentially with prefixed output
bun run --sequential build test

# Glob-matched script names
bun run --parallel "build:*"

# Run "build" in all workspace packages concurrently
bun run --parallel --filter '*' build

# Run "build" in all workspace packages sequentially
bun run --sequential --workspaces build

# Glob-matched scripts across all packages
bun run --parallel --filter '*' "build:*"

# Multiple scripts across all packages
bun run --parallel --filter '*' build lint test

# Continue running even if one package fails
bun run --parallel --no-exit-on-error --filter '*' test

# Skip packages missing the script
bun run --parallel --workspaces --if-present build
```

## How it works

### Output format

Each script's stdout/stderr is prefixed with a colored, padded label:

```
build | compiling...
test  | running suite...
lint  | checking files...
```

### Label format

- **Without `--filter`/`--workspaces`**: labels are just the script name
→ `build | output`
- **With `--filter`/`--workspaces`**: labels are `package:script` →
`pkg-a:build | output`
- **Fallback**: if a package.json has no `name` field, the relative path
from the workspace root is used (e.g., `packages/my-pkg:build`)

### Execution model

- **`--parallel`**: all scripts start immediately, output is interleaved
with prefixes
- **`--sequential`**: scripts run one at a time in order, each waiting
for the previous to finish
- **Pre/post scripts** (`prebuild`/`postbuild`) are grouped with their
main script and run in dependency order within each group
- By default, a failure kills all remaining scripts.
`--no-exit-on-error` lets all scripts finish.

### Workspace integration

The workspace branch in `multi_run.zig` uses a two-pass approach for
deterministic ordering:

1. **Collect**: iterate workspace packages using
`FilterArg.PackageFilterIterator` (same infrastructure as
`filter_run.zig`), filtering with `FilterArg.FilterSet`, collecting
matched packages with their scripts, PATH, and cwd.
2. **Sort**: sort matched packages by name (tiebreak by directory path)
for deterministic ordering — filesystem iteration order from the glob
walker is nondeterministic.
3. **Build configs**: for each sorted package, expand script names
(including globs like `build:*`) against that package's scripts map,
creating `ScriptConfig` entries with `pkg:script` labels and per-package
cwd/PATH.

### Behavioral consistency with `filter_run.zig`

| Behavior | `filter_run.zig` | `multi_run.zig` (this PR) |
|----------|-------------------|---------------------------|
| `--workspaces` skips root package | Yes | Yes |
| `--workspaces` errors on missing script | Yes | Yes |
| `--if-present` silently skips missing | Yes | Yes |
| `--filter` without `--workspaces` includes root | Yes (if matches) |
Yes (if matches) |
| Pre/post script chains | Per-package | Per-package |
| Per-package cwd | Yes | Yes |
| Per-package PATH (`node_modules/.bin`) | Yes | Yes |

### Key implementation details

- Each workspace package script runs in its own package directory with
its own `node_modules/.bin` PATH
- `dirpath` from the glob walker is duped to avoid use-after-free when
the iterator's arena is freed between patterns
- `addScriptConfigs` takes an optional `label_prefix` parameter — `null`
for single-package mode, package name for workspace mode
- `MultiRunProcessHandle` is registered in the `ProcessExitHandler`
tagged pointer union in `process.zig`

## Files changed

| File | Change |
|------|--------|
| `src/cli/multi_run.zig` | New file: process management, output
routing, workspace integration, dependency ordering |
| `src/cli.zig` | Dispatch to `MultiRun.run()` for
`--parallel`/`--sequential`, new context fields |
| `src/cli/Arguments.zig` | Parse `--parallel`, `--sequential`,
`--no-exit-on-error` flags |
| `src/bun.js/api/bun/process.zig` | Register `MultiRunProcessHandle` in
`ProcessExitHandler` tagged pointer union |
| `test/cli/run/multi-run.test.ts` | 118 tests (102 core + 16 workspace
integration) |
| `docs/pm/filter.mdx` | Document `--parallel`/`--sequential` +
`--filter`/`--workspaces` combination |
| `docs/snippets/cli/run.mdx` | Add `--parallel`, `--sequential`,
`--no-exit-on-error` parameter docs |

## Test plan

All 118 tests pass with debug build (`bun bd test
test/cli/run/multi-run.test.ts`). The 16 new workspace tests all fail
with system bun (`USE_SYSTEM_BUN=1`), confirming they test new
functionality.

### Workspace integration tests (16 tests)

1. `--parallel --filter='*'` runs script in all packages
2. `--parallel --filter='pkg-a'` runs only in matching package
3. `--parallel --workspaces` matches all workspace packages
4. `--parallel --filter='*'` with glob expands per-package scripts
5. `--sequential --filter='*'` runs in sequence (deterministic order)
6. Workspace + failure aborts other scripts
7. Workspace + `--no-exit-on-error` lets all finish
8. `--workspaces` skips root package
9. Each workspace script runs in its own package directory (cwd
verification)
10. Multiple script names across workspaces (`build` + `test`)
11. Pre/post scripts work per workspace package
12. `--filter` skips packages without the script (no error)
13. `--workspaces` errors when a package is missing the script
14. `--workspaces --if-present` skips missing scripts silently
15. Labels are padded correctly across workspace packages
16. Package without `name` field uses relative path as label

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2026-01-29 20:20:39 -08:00
Dylan Conway
adc1a6b05c Fix aarch64 SIGILL: disable mimalloc LSE atomics + update WebKit + QEMU verification (#26586)
Fixes illegal instruction (SIGILL) crashes on ARMv8.0 aarch64 CPUs
(Cortex-A53, Raspberry Pi 4, AWS a1 instances).

## Root cause

Upstream mimalloc force-enables `MI_OPT_ARCH` on arm64, which adds
`-march=armv8.1-a` and emits LSE atomic instructions (`casa`, `swpa`,
`ldaddl`). These are not available on ARMv8.0 CPUs.

## Fix

- Pass `MI_NO_OPT_ARCH=ON` to mimalloc on aarch64 (has priority over
`MI_OPT_ARCH` in mimalloc's CMake)
- Update WebKit to autobuild-596e48e22e3a1090e5b802744a7938088b1ea860
which explicitly passes `-march` flags to the WebKit build

## Verification

Includes QEMU-based baseline CPU verification CI steps (#26571) that
catch these regressions automatically.
2026-01-29 17:18:57 -08:00
Dylan Conway
8a11a03297 [publish images] 2026-01-29 16:04:44 -08:00
Dylan Conway
baea21f0c7 ci: add QEMU-based baseline CPU verification steps (#26571)
## Summary

Add CI steps that verify baseline builds don't use CPU instructions
beyond their target. Uses QEMU user-mode emulation with restricted CPU
features — any illegal instruction causes SIGILL and fails the build.

## Platforms verified

| Build Target | QEMU Command | What it catches |
|---|---|---|
| `linux-x64-baseline` (glibc) | `qemu-x86_64 -cpu Nehalem` | AVX, AVX2,
AVX512 |
| `linux-x64-musl-baseline` | `qemu-x86_64 -cpu Nehalem` | AVX, AVX2,
AVX512 |
| `linux-aarch64` (glibc) | `qemu-aarch64 -cpu cortex-a35` | LSE
atomics, SVE, dotprod |
| `linux-aarch64-musl` | `qemu-aarch64 -cpu cortex-a35` | LSE atomics,
SVE, dotprod |

## How it works

Each verify step:
1. Downloads the built binary artifact from the `build-bun` step
2. Installs `qemu-user-static` on-the-fly (dnf/apk/apt-get)
3. Runs two smoke tests under QEMU with restricted CPU features:
   - `bun --version` — validates startup, linker, static init code
   - `bun -e eval` — validates JSC initialization and basic execution
4. Hard fails on SIGILL (exit code 132)

The verify step runs in the build group after `build-bun`, with a
5-minute timeout.

## Known issue this will surface

**mimalloc on aarch64**: Built with `MI_OPT_ARCH=ON` which adds
`-march=armv8.1-a`, enabling LSE atomics. This will SIGILL on
Cortex-A35/A53 CPUs. The aarch64 verify steps are expected to fail
initially, confirming the test catches real issues. Fix can be done
separately in `cmake/targets/BuildMimalloc.cmake`.
2026-01-29 15:53:34 -08:00
Jarred Sumner
209923a65c Update markdown.mjs 2026-01-29 13:00:10 -08:00
Jarred Sumner
cd4d98338c some benchmarks 2026-01-29 12:38:05 -08:00
Dylan Conway
b64edcb490 Update WebKit (#26549)
### What does this PR do?

Includes
9a2cc42ae1

Fixes #https://github.com/oven-sh/bun/issues/26525

### How did you verify your code works?

CI

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2026-01-29 01:22:53 -08:00
Jarred Sumner
4feede90f5 Add missing docs 2026-01-29 08:11:50 +01:00
Dylan Conway
fc4624c672 fix(node:vm): propagate async context tracking flag to NodeVMGlobalObject (#26542)
When a `SyntheticModule` callback was wrapped in an `AsyncContextFrame`
on the main globalObject (where async context tracking is enabled),
evaluating it on a `NodeVMGlobalObject` would crash because the tracking
flag wasn't propagated.

`AsyncContextFrame::call` checks `isAsyncContextTrackingEnabled()` to
decide whether to unwrap the frame — without the flag, it takes the fast
path and tries to call the `AsyncContextFrame` wrapper directly, which
is not callable.

The async context data (`m_asyncContextData`) was already shared between
parent and `NodeVMGlobalObject`, but the tracking flag was missing. This
adds propagation of `isAsyncContextTrackingEnabled` alongside the data.

**Repro:** `react-email` v5.2.5 preview server crashes when rendering a
template because it imports `node:async_hooks` (enabling async context
tracking) and uses `node:vm` `SyntheticModule` for module evaluation.

Fixes #26540

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-28 21:40:55 -08:00
Jarred Sumner
1bfe5c6b37 feat(md): Zig markdown parser with Bun.markdown API (#26440)
## Summary

- Port md4c (CommonMark-compliant markdown parser) from C to Zig under
`src/md/`
- Three output modes:
  - `Bun.markdown.html(input, options?)` — render to HTML string
- `Bun.markdown.render(input, callbacks?)` — render with custom
callbacks for each element
- `Bun.markdown.react(input, options?)` — render to a React Fragment
element, directly usable as a component return value
- React element creation uses a cached JSC Structure with
`putDirectOffset` for fast allocation
- Component overrides in `react()`: pass tag names as options keys to
replace default HTML elements with custom components
- GFM extensions: tables, strikethrough, task lists, permissive
autolinks, disallowed raw HTML tag filter
- Wire up `.md` as a bundler loader (via explicit `{ type: "md" }`)

## JavaScript API

### `Bun.markdown.html(input, options?)`

Renders markdown to an HTML string:

```js
const html = Bun.markdown.html("# Hello **world**");
// "<h1>Hello <strong>world</strong></h1>\n"

Bun.markdown.html("## Hello", { headingIds: true });
// '<h2 id="hello">Hello</h2>\n'
```

### `Bun.markdown.render(input, callbacks?)`

Renders markdown with custom JavaScript callbacks for each element. Each
callback receives children as a string and optional metadata, and
returns a string:

```js
// Custom HTML with classes
const html = Bun.markdown.render("# Title\n\nHello **world**", {
  heading: (children, { level }) => `<h${level} class="title">${children}</h${level}>`,
  paragraph: (children) => `<p>${children}</p>`,
  strong: (children) => `<b>${children}</b>`,
});

// ANSI terminal output
const ansi = Bun.markdown.render("# Hello\n\n**bold**", {
  heading: (children) => `\x1b[1;4m${children}\x1b[0m\n`,
  paragraph: (children) => children + "\n",
  strong: (children) => `\x1b[1m${children}\x1b[22m`,
});

// Strip all formatting
const text = Bun.markdown.render("# Hello **world**", {
  heading: (children) => children,
  paragraph: (children) => children,
  strong: (children) => children,
});
// "Hello world"

// Return null to omit elements
const result = Bun.markdown.render("# Title\n\n![logo](img.png)\n\nHello", {
  image: () => null,
  heading: (children) => children,
  paragraph: (children) => children + "\n",
});
// "Title\nHello\n"
```

Parser options can be included alongside callbacks:

```js
Bun.markdown.render("Visit www.example.com", {
  link: (children, { href }) => `[${children}](${href})`,
  paragraph: (children) => children,
  permissiveAutolinks: true,
});
```

### `Bun.markdown.react(input, options?)`

Returns a React Fragment element — use it directly as a component return
value:

```tsx
// Use as a component
function Markdown({ text }: { text: string }) {
  return Bun.markdown.react(text);
}

// With custom components
function Heading({ children }: { children: React.ReactNode }) {
  return <h1 className="title">{children}</h1>;
}
const element = Bun.markdown.react("# Hello", { h1: Heading });

// Server-side rendering
import { renderToString } from "react-dom/server";
const html = renderToString(Bun.markdown.react("# Hello **world**"));
// "<h1>Hello <strong>world</strong></h1>"
```

#### React 18 and older

By default, `react()` uses `Symbol.for('react.transitional.element')` as
the `$$typeof` symbol, which is what React 19 expects. For React 18 and
older, pass `reactVersion: 18`:

```tsx
const el = Bun.markdown.react("# Hello", { reactVersion: 18 });
```

### Component Overrides

Tag names can be overridden in `react()`:

```tsx
Bun.markdown.react(input, {
  h1: MyHeading,      // block elements
  p: CustomParagraph,
  a: CustomLink,      // inline elements
  img: CustomImage,
  pre: CodeBlock,
  // ... h1-h6, p, blockquote, ul, ol, li, pre, hr, html,
  //     table, thead, tbody, tr, th, td,
  //     em, strong, a, img, code, del, math, u, br
});
```

Boolean values are ignored (not treated as overrides), so parser options
like `{ strikethrough: true }` don't conflict with component overrides.

### Options

```js
Bun.markdown.html(input, {
  tables: true,              // GFM tables (default: true)
  strikethrough: true,       // ~~deleted~~ (default: true)
  tasklists: true,           // - [x] items (default: true)
  headingIds: true,          // Generate id attributes on headings
  autolinkHeadings: true,    // Wrap heading content in <a> tags
  tagFilter: false,          // GFM disallowed HTML tags
  wikiLinks: false,          // [[wiki]] links
  latexMath: false,          // $inline$ and $$display$$
  underline: false,          // __underline__ (instead of <strong>)
  // ... and more
});
```

## Architecture

### Parser (`src/md/`)

The parser is split into focused modules using Zig's delegation pattern:

| Module | Purpose |
|--------|---------|
| `parser.zig` | Core `Parser` struct, state, and re-exported method
delegation |
| `blocks.zig` | Block-level parsing: document processing, line
analysis, block start/end |
| `containers.zig` | Container management: blockquotes, lists, list
items |
| `inlines.zig` | Inline parsing: emphasis, code spans, HTML tags,
entities |
| `links.zig` | Link/image resolution, reference links, autolink
rendering |
| `autolinks.zig` | Permissive autolink detection (www, url, email) |
| `line_analysis.zig` | Line classification: headings, fences, HTML
blocks, tables |
| `ref_defs.zig` | Reference definition parsing and lookup |
| `render_blocks.zig` | Block rendering dispatch (code, HTML, table
blocks) |
| `html_renderer.zig` | HTML renderer implementing `Renderer` VTable |
| `types.zig` | Shared types: `Renderer` VTable, `BlockType`,
`SpanType`, `TextType`, etc. |

### Renderer Abstraction

Parsing is decoupled from output via a `Renderer` VTable interface:

```zig
pub const Renderer = struct {
    ptr: *anyopaque,
    vtable: *const VTable,

    pub const VTable = struct {
        enterBlock: *const fn (...) void,
        leaveBlock: *const fn (...) void,
        enterSpan:  *const fn (...) void,
        leaveSpan:  *const fn (...) void,
        text:       *const fn (...) void,
    };
};
```

Four renderers are implemented:
- **`HtmlRenderer`** (`src/md/html_renderer.zig`) — produces HTML string
output
- **`JsCallbackRenderer`** (`src/bun.js/api/MarkdownObject.zig`) — calls
JS callbacks for each element, accumulates string output
- **`ParseRenderer`** (`src/bun.js/api/MarkdownObject.zig`) — builds
React element AST with `MarkedArgumentBuffer` for GC safety
- **`JSReactElement`** (`src/bun.js/bindings/JSReactElement.cpp`) — C++
fast path for React element creation using cached JSC Structure +
`putDirectOffset`

## Test plan

- [x] 792 spec tests pass (CommonMark, GFM tables, strikethrough,
tasklists, permissive autolinks, GFM tag filter, wiki links, coverage,
regressions)
- [x] 114 API tests pass (`html()`, `render()`, `react()`,
`renderToString` integration, component overrides)
- [x] 58 GFM compatibility tests pass

```
bun bd test test/js/bun/md/md-spec.test.ts       # 792 pass
bun bd test test/js/bun/md/md-render-api.test.ts  # 114 pass
bun bd test test/js/bun/md/gfm-compat.test.ts     # 58 pass
```

🤖 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>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
Co-authored-by: SUZUKI Sosuke <sosuke@bun.com>
Co-authored-by: robobun <robobun@oven.sh>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Kirill Markelov <kerusha.chubko@gmail.com>
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
Co-authored-by: Alistair Smith <hi@alistair.sh>
2026-01-28 20:24:02 -08:00
robobun
aded701d1d feat(build): add --metafile-md CLI option for LLM-friendly bundle analysis (#26441)
## Summary

- Adds `--metafile-md` CLI option to `bun build` that generates a
markdown visualization of the module graph
- Designed to help Claude and other LLMs analyze bundle composition,
identify bloat, and understand dependency chains
- Reuses existing metafile JSON generation code as a post-processing
step

## Features

The generated markdown includes:

1. **Quick Summary** - Module counts, sizes, ESM/CJS breakdown,
output/input ratio
2. **Largest Input Files** - Sorted by size to identify potential bloat
3. **Entry Point Analysis** - Shows bundle size, exports, CSS bundles,
and bundled modules
4. **Dependency Chains** - Most commonly imported modules and reverse
dependencies
5. **Full Module Graph** - Complete import/export info for each module
6. **Raw Data for Searching** - Grep-friendly markers in code blocks:
   - `[MODULE:]`, `[SIZE:]`, `[IMPORT:]`, `[IMPORTED_BY:]`
   - `[ENTRY:]`, `[EXTERNAL:]`, `[NODE_MODULES:]`

## Usage

```bash
# Default filename (meta.md)
bun build entry.js --metafile-md --outdir=dist

# Custom filename
bun build entry.js --metafile-md=analysis.md --outdir=dist

# Both JSON and markdown
bun build entry.js --metafile=meta.json --metafile-md=meta.md --outdir=dist
```

## Example Output

See sample output: https://gist.github.com/example (will add)

## Test plan

- [x] Test default filename (`meta.md`)
- [x] Test custom filename
- [x] Test both `--metafile` and `--metafile-md` together
- [x] Test summary metrics
- [x] Test module format info (ESM/CJS)
- [x] Test external imports
- [x] Test exports list
- [x] Test bundled modules table
- [x] Test CSS bundle reference
- [x] Test import kinds (static, dynamic, require)
- [x] Test commonly imported modules
- [x] Test largest files sorting (bloat analysis)
- [x] Test output/input ratio
- [x] Test grep-friendly raw data section
- [x] Test entry point markers
- [x] Test external import markers
- [x] Test node_modules markers

All 17 new tests pass.

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2026-01-28 18:01:39 -08:00
Dylan Conway
7ebfdf97a8 fix(npm): remove shebang from placeholder scripts to fix npm i -g bun on Windows (#26517)
## Summary
- Removes the `#!/bin/sh` shebang from placeholder `bin/bun.exe` and
`bin/bunx.exe` scripts in the npm package
- Fixes `npm i -g bun` being completely broken on Windows since v1.3.7

## Problem
PR #26259 added a `#!/bin/sh` shebang to the placeholder scripts to show
a helpful error when postinstall hasn't run. However, npm's `cmd-shim`
reads shebangs to generate `.ps1`/`.cmd` wrappers **before** postinstall
runs, and bakes the interpreter path into them. On Windows, the wrappers
referenced `/bin/sh` which doesn't exist, causing:

```
& "/bin/sh$exe"  "$basedir/node_modules/bun/bin/bun.exe" $args
   ~~~~~~~~~~~~~
The term '/bin/sh.exe' is not recognized...
```

Even after postinstall successfully replaced the placeholder with the
real binary, the stale wrappers still tried to invoke `/bin/sh`.

## Fix
Remove the shebang. Without it, `cmd-shim` generates a direct invocation
wrapper that works after postinstall replaces the placeholder. On Unix,
bash/zsh still execute shebang-less files as shell scripts via ENOEXEC
fallback, so the helpful error message is preserved.

## Test plan
- [x] `bun bd test test/regression/issue/24329.test.ts` passes (2/2
tests)
- Manually verify `npm i -g bun` works on Windows

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

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-28 00:00:50 -08:00
SUZUKI Sosuke
4cd3b241bc Upgrade WebKit to cc5e0bddf7ea (#26526)
Upgrade WebKit from `0e6527f24783ea83` to `cc5e0bddf7eae1d8` (77
commits)

This brings in the latest changes from oven-sh/WebKit (2026-01-27).
2026-01-27 23:33:47 -08:00
robobun
cae67a17e2 chore: update mimalloc to latest dev3 (#26519)
## Summary
- Updates oven-sh/mimalloc bun-dev3 branch to latest upstream
microsoft/mimalloc dev3 (ffa38ab8)
- Merged 12 new commits from upstream

### Key upstream changes included:
- fix re-initialization of threads on macOS
- add lock for sub-pagemap allocations
- fix peak commit stat
- fix use of continue in bitmap find_and_clear (fixes rare case of not
finding space while it exists)

## Test plan
- [ ] CI passes
- [ ] Memory allocation tests pass

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 23:33:00 -08:00
robobun
a394063a7d refactor(test): use container-based postgres_tls for TLS SQL tests (#26518)
## Summary
- Refactors `tls-sql.test.ts` to use `describeWithContainer` with a
local Docker container instead of external Neon secrets
- Updates `postgres_tls` service to build from Dockerfile (fixes SSL key
permission issues)
- Fixes pg_hba.conf to allow local socket connections for init scripts

## Test plan
- [x] Verified tests pass locally with `bun bd test
test/js/sql/tls-sql.test.ts` (30 tests pass)
- [ ] CI passes on x64 Linux (arm64 Docker tests are currently disabled)

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 23:32:39 -08:00
Jarred Sumner
c9ebb17921 Bump 2026-01-27 17:06:36 -08:00
Dylan Conway
2f510724a9 fix(napi): return napi_function for AsyncContextFrame in napi_typeof (#26511)
## Summary
- `napi_typeof` was returning `napi_object` for `AsyncContextFrame`
values, which are internally callable JSObjects
- Native addons that check callback types (e.g. encore.dev's runtime)
would fail with `expect Function, got: Object` and panic
- Added a `jsDynamicCast<AsyncContextFrame*>` check before the final
`napi_object` fallback to correctly report these values as
`napi_function`

Closes #25933

## Test plan
- [x] Verify encore.dev + supertokens reproduction from the issue no
longer panics
- [ ] Existing napi tests continue to pass

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-27 13:35:15 -08:00
robobun
9a16f4c345 fix(http2): correct canReceiveData logic per RFC 7540 (#26491)
## Summary

- Fixed inverted logic in `canReceiveData` function in HTTP/2 stream
state handling
- Added gRPC streaming tests to verify correct behavior

## Problem

The `canReceiveData` function had completely inverted logic that
reported incorrect `remoteClose` status:

| Stream State | Before (Wrong) | After (Correct) |
|--------------|----------------|-----------------|
| OPEN | `false` (can't receive) | `true` (can receive) |
| HALF_CLOSED_LOCAL | `false` (can't receive) | `true` (can receive from
remote) |
| HALF_CLOSED_REMOTE | `true` (can receive) | `false` (remote closed) |
| CLOSED | `true` (can receive) | `false` (stream done) |

Per RFC 7540 Section 5.1:
- In `HALF_CLOSED_LOCAL` state, the local endpoint has sent END_STREAM
but can still **receive** data from the remote peer
- In `HALF_CLOSED_REMOTE` state, the remote endpoint has sent END_STREAM
so no more data will be received

## Test plan

- [x] Added gRPC streaming tests covering unary, server streaming,
client streaming, and bidirectional streaming calls
- [x] Verified HTTP/2 test suite passes (same or fewer failures than
before)
- [x] Verified gRPC test suite improves (7 failures vs 9 failures before
+ 2 errors)

Closes #20875

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 10:29:34 -08:00
robobun
ba426210c2 fix(shell): handle ".", "", "./" in cwd() by using process.cwd() (#26461)
## Summary
- Fix `$`...`.cwd(".")` causing ENOENT error with path ending in
"undefined"
- The same fix applies to `.cwd("")` and `.cwd("./")`
- Falls back to `process.cwd()` when `defaultCwd` is undefined

Closes #26460

## Test plan
- [x] Added regression test in `test/regression/issue/26460.test.ts`
- [x] Verified test fails with `USE_SYSTEM_BUN=1` (reproduces the bug)
- [x] Verified test passes with `bun bd test` (fix works)

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 16:04:45 -08:00
Dylan Conway
bd63fb9ef6 fix: BUN_OPTIONS bare flags getting trailing whitespace (#26464)
## Summary

Fix a bug in `appendOptionsEnv` where bare flags (no `=`) that aren't
the last option get a trailing space appended, causing the argument
parser to not recognize them.

For example, `BUN_OPTIONS="--cpu-prof --cpu-prof-dir=profiles"` would
parse `--cpu-prof` as `"--cpu-prof "` (trailing space), so CPU profiling
was never enabled.

## Root Cause

When `appendOptionsEnv` encounters a `--flag` followed by whitespace, it
advances past the whitespace looking for a possible quoted value (e.g.
`--flag "quoted"`). If no quote is found and there's no `=`, it falls
through without resetting `j`, so the emitted argument includes the
trailing whitespace.

## Fix

Save `end_of_flag = j` after scanning the flag name. Add an `else`
branch that resets `j = end_of_flag` when no value (quote or `=`) is
found after the whitespace. This is a 3-line change.

Also fixes a separate bug in `BunCPUProfiler.zig` where `--cpu-prof-dir`
with an absolute path would hit a debug assertion (`path.append` on an
already-rooted path with an absolute input). Changed to `path.join`
which handles both relative and absolute paths correctly.

## Tests

- `test/cli/env/bun-options.test.ts`: Two new tests verifying
`--cpu-prof --cpu-prof-dir=<abs-path>` produces a `.cpuprofile` file,
for both normal and standalone compiled executables.
2026-01-26 14:02:36 -08:00
robobun
9d6ef0af1d fix(fetch): preserve header case when sending HTTP requests (#26425)
## Summary
- Fixes #26422
- Preserve HTTP header case when sending requests (e.g., `Content-Type`
instead of `content-type`)
- HTTP headers are technically case-insensitive per RFC 7230, but many
APIs expect specific casing

## Test plan
- [x] Added tests that verify headers are sent with proper case on the
wire
- [x] Tests use raw TCP sockets to capture actual HTTP wire format
- [x] Tests fail with system Bun (lowercase headers), pass with fixed
build

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 11:15:33 -08:00
robobun
d08e4bae09 fix(http2): prevent extra empty DATA frame on write()+end() pattern (#26410)
## Summary

- Fixes an issue where calling `req.write(data)` followed by `req.end()`
on an HTTP/2 stream would send **three** DATA frames instead of **two**
- This caused AWS ALB and other strict HTTP/2 servers to reject the
connection with `NGHTTP2_FRAME_SIZE_ERROR` (error code 6)

## Root Cause

The `Http2Stream.end()` method was creating an empty buffer
(`Buffer.alloc(0)`) when called without data:

```javascript
if (!chunk) {
  chunk = Buffer.alloc(0);
}
return super.end(chunk, encoding, callback);
```

This empty buffer was then passed to the Duplex stream's `end()`, which
triggered `_write()` with the empty buffer before calling `_final()`.
This resulted in:

1. DATA frame with actual data (from `_write`)
2. Empty DATA frame without END_STREAM (from the extra `_write` with
empty buffer)
3. Empty DATA frame with END_STREAM (from `_final`)

The second empty DATA frame was unnecessary and violated some strict
HTTP/2 implementations.

## Fix

Remove the unnecessary empty buffer creation. The Duplex stream's
`end()` method already handles the no-data case correctly by calling
`_final()` directly without calling `_write()`.

## Test plan

- [x] Manually verified with ConnectRPC client and AWS ALB endpoint
- [x] Added regression test
`test/regression/issue/25589-write-end.test.ts`
- [x] Existing HTTP/2 tests pass
- [x] Existing gRPC tests pass

Fixes #25589

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-26 11:09:03 -08:00
Dylan Conway
b59c77a6e7 feat: add native JSON5 parser (Bun.JSON5) (#26439)
## Summary

- Adds `Bun.JSON5.parse()` and `Bun.JSON5.stringify()` as built-in APIs
- Adds `.json5` file support in the module resolver and bundler
- Parser uses a scanner/parser split architecture with a labeled switch
pattern (like the YAML parser) — the scanner produces typed tokens, the
parser never touches source bytes directly
- 430+ tests covering the official JSON5 test suite, escape sequences,
numbers, comments, whitespace (including all Unicode whitespace types),
unquoted/reserved-word keys, unicode identifiers, deeply nested
structures, garbage input, error messages, and stringify behavior

<img width="659" height="610" alt="Screenshot 2026-01-25 at 12 19 57 AM"
src="https://github.com/user-attachments/assets/e300125a-f197-4cad-90ed-e867b6232a01"
/>

## Test plan

- [x] `bun bd test test/js/bun/json5/json5.test.ts` — 317 tests
- [x] `bun bd test test/js/bun/json5/json5-test-suite.test.ts` — 113
tests from the official JSON5 test suite
- [x] `bun bd test test/js/bun/resolve/json5/json5.test.js` — .json5
module resolution

closes #3175

🤖 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>
2026-01-26 10:52:35 -08:00
SUZUKI Sosuke
6130aa8168 Add benchmark for [...set] (#26452)
### What does this PR do?

Adds benchmark for `[...set]`

### How did you verify your code works?

### Results

**Bun 1.3.6** 

```
clk: ~3.77 GHz
cpu: Apple M4 Max
runtime: bun 1.3.6 (arm64-darwin)

benchmark                   avg (min … max) p75   p99    (min … top 1%)
------------------------------------------- -------------------------------
[...set] - integers (10)      51.70 ns/iter  51.16 ns   █▄
                     (45.17 ns … 121.75 ns)  87.65 ns ▁▁██▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
[...set] - integers (100)    394.07 ns/iter 394.41 ns   █▇▂
                    (378.73 ns … 443.39 ns) 437.51 ns ▂████▆▄▂▁▁▁▁▂▃▃▄▂▂▁▂▁
[...set] - strings (10)       53.86 ns/iter  53.66 ns  █
                     (50.72 ns … 115.85 ns)  89.37 ns ▃█▆▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
[...set] - strings (100)     422.12 ns/iter 422.80 ns    ▅██▄
                    (392.35 ns … 977.34 ns) 481.31 ns ▂▂▅████▇▃▂▁▂▃▄▄▃▃▁▁▁▁
[...set] - objects (10)       54.07 ns/iter  54.33 ns  █▇
                      (49.83 ns … 98.49 ns)  87.07 ns ▂██▇▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
[...set] - objects (100)     446.81 ns/iter 441.72 ns  █
                    (397.71 ns … 954.87 ns) 824.61 ns ▂█▃▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
```

**Bun 1.3.7 canary**

```
clk: ~3.82 GHz
cpu: Apple M4 Max
runtime: bun 1.3.7 (arm64-darwin)

benchmark                   avg (min … max) p75   p99    (min … top 1%)
------------------------------------------- -------------------------------
[...set] - integers (10)       4.71 ns/iter   4.62 ns  █▄
                       (3.88 ns … 48.91 ns)  11.42 ns ▂██▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
[...set] - integers (100)     42.52 ns/iter  42.70 ns    █
                      (35.70 ns … 88.03 ns)  74.86 ns ▃█▂██▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
[...set] - strings (10)        6.02 ns/iter   5.86 ns       ▇█
                       (3.99 ns … 49.43 ns)   8.89 ns ▁▁▁▁▁▂██▆▃▃▂▁▁▁▁▁▁▁▁▁
[...set] - strings (100)      56.81 ns/iter  55.91 ns    █
                      (48.70 ns … 96.89 ns)  88.48 ns ▁▁▃█▇▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
[...set] - objects (10)        6.15 ns/iter   6.10 ns       █▃
                       (4.14 ns … 66.32 ns)   9.31 ns ▁▁▁▁▂███▆▅▃▂▁▁▁▁▁▁▁▁▁
[...set] - objects (100)      57.47 ns/iter  56.67 ns    ▆█
                     (47.52 ns … 110.06 ns)  93.39 ns ▁▁▃██▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
```

**Node 24.12.0**

```
clk: ~3.30 GHz
cpu: Apple M4 Max
runtime: node 24.12.0 (arm64-darwin)

benchmark                   avg (min … max) p75   p99    (min … top 1%)
------------------------------------------- -------------------------------
[...set] - integers (10)      28.19 ns/iter  13.03 ns █
                       (10.87 ns … 9.37 µs) 129.01 ns █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
[...set] - integers (100)    159.41 ns/iter  96.19 ns █
                       (80.87 ns … 8.42 µs)   1.98 µs █▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
[...set] - strings (10)       20.13 ns/iter  13.56 ns █
                       (10.92 ns … 3.82 µs) 105.83 ns █▅▂▁▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
[...set] - strings (100)     138.56 ns/iter  92.29 ns █
                      (80.63 ns … 10.17 µs)   1.09 µs █▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
[...set] - objects (10)       16.43 ns/iter  12.40 ns  █
                       (11.07 ns … 5.99 µs)  39.03 ns ▄█▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
[...set] - objects (100)     108.58 ns/iter  97.82 ns  █
                       (80.83 ns … 2.99 µs) 298.93 ns ▂█▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
```

**Summary**

```zig
  ┌────────────────┬────────────────┬───────────────┬─────────┐
  │   Benchmark    │ Before (1.3.6) │ After (1.3.7) │ Speedup │
  ├────────────────┼────────────────┼───────────────┼─────────┤
  │ integers (10)  │ 51.70 ns       │ 4.71 ns       │ 11.0x   │
  ├────────────────┼────────────────┼───────────────┼─────────┤
  │ integers (100) │ 394.07 ns      │ 42.52 ns      │ 9.3x    │
  ├────────────────┼────────────────┼───────────────┼─────────┤
  │ strings (10)   │ 53.86 ns       │ 6.02 ns       │ 8.9x    │
  ├────────────────┼────────────────┼───────────────┼─────────┤
  │ strings (100)  │ 422.12 ns      │ 56.81 ns      │ 7.4x    │
  ├────────────────┼────────────────┼───────────────┼─────────┤
  │ objects (10)   │ 54.07 ns       │ 6.15 ns       │ 8.8x    │
  ├────────────────┼────────────────┼───────────────┼─────────┤
  │ objects (100)  │ 446.81 ns      │ 57.47 ns      │ 7.8x    │
  └────────────────┴────────────────┴───────────────┴─────────┘
```
2026-01-26 00:25:51 -08:00
SUZUKI Sosuke
a595fe1cca test: add JSC JIT stress tests from WebKit (#26380)
## Summary

This PR adds 78 stress tests that exercise JSC's JIT compilation tiers.
The tests are ported from WebKit's `JSTests/stress/` and
`JSTests/wasm/stress/` directories, covering all five JIT tiers:

- **FTL** (41 tests): math intrinsics, string ops, regexp, arguments,
exceptions, try-catch, property access, OSR, tail calls
- **DFG** (14 tests): SSA, type conversion, strength reduction,
arguments, internal functions, try-catch, class constructors
- **Allocation sinking / OSR / LICM** (6 tests): varargs, loop
unrolling, LICM
- **Wasm BBQ** (11 tests): fused-if register alloc, OSR with exceptions,
ipint-bbq OSR, tail calls
- **Wasm OMG** (6 tests): recompile, OSR stack slots, tail call clobber

Each test exercises hot loops that trigger JIT tier-up, verifying
correctness of JIT-compiled code.

## Motivation

The goal is to improve stability on platforms that Bun supports but are
not covered by WebKit's EWS (Early Warning System). By running these JIT
stress tests across all CI platforms, we can catch JIT-related
regressions that would otherwise go unnoticed.

## Licensing

Since the test fixtures are derived from WebKit's `JSTests/`, a
`LICENSE` file is included in the test directory with the BSD 2-Clause
license per WebKit's contribution policy.

## Next Steps

As a follow-up, we are considering running these tests specifically
under CPU emulation (without AVX) on baseline builds, to verify that
JIT-generated code does not emit AVX instructions on platforms that do
not support them.

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2026-01-26 00:21:34 -08:00
Kirill Markelov
799907362f Fix hash map use-after-free in macro (#26451)
### What does this PR do?
Fixes use after free of a pointer taken from a hash map inside of
`.Promise` branch
Fixes https://github.com/oven-sh/bun/issues/24505

### How did you verify your code works?
Tested on [my minimal
repro](https://github.com/oven-sh/bun/issues/24505#issuecomment-3797984659),
and also on the repro in [this
issue](https://github.com/oven-sh/bun/issues/24505#issue-3603294746)
Didn't include test cases in code because the repro is still flaky and
involves heavy libs to reproduce
2026-01-26 00:19:58 -08:00
robobun
2c0721eabe docs(test): update static-initializers.test.ts comments to reflect mimalloc v3 (#26454)
## Summary
- Updates the docstring in static-initializers.test.ts which incorrectly
said "exactly one static initializer" - the test actually expects 2
initializers for both arm64 and x64 since the mimalloc v3 update
- Added a comment explaining that mimalloc v3 adds a static initializer
on arm64

## Background
The test file was updated in c63415c9c9 (Mimalloc v3 update) to expect 2
static initializers on arm64 (changed from 1 to 2), but the comments
were not updated to reflect this change. This PR updates the
documentation to accurately describe the expected behavior.

## Test plan
- [x] No functional changes - documentation only

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 00:19:45 -08:00
SUZUKI Sosuke
02680b69bf fix(lint): remove unused variables in readline and ConsoleObject (#26455)
### What does this PR do?

Just fixes lint errors

### How did you verify your code works?
2026-01-26 00:19:25 -08:00
SUZUKI Sosuke
7c50164987 fix(build-jsc): enable REMOTE_INSPECTOR for macOS release builds (#26453)
### What does this PR do?

  Move `-DENABLE_REMOTE_INSPECTOR=ON` from the debug-only flags to the
  macOS common flags so it applies to all build configurations (debug,
  release, lto). This was already the case for Linux and Windows.

  Without this, `build:release:local` fails because BunDebugger.cpp and
InspectorLifecycleAgent.cpp unconditionally use JSC inspector APIs that
  are only available when REMOTE_INSPECTOR is enabled.

### How did you verify your code works?

Build locally
2026-01-26 00:19:11 -08:00
Dylan Conway
a553fda32b fix(napi): fix use-after-free in property names and external buffer lifetime (#26450)
## Summary

- **PROPERTY_NAME_FROM_UTF8 use-after-free:** The macro used
`StringImpl::createWithoutCopying` for ASCII strings, which left
dangling pointers in JSC's atom string table when the caller freed the
input buffer (e.g. napi-rs `CString`). Fixed by using
`Identifier::fromString` which copies only when inserting into the atom
table, but never retains a reference to the caller's buffer.

- **napi_create_external_buffer data lifetime:** `finalize_cb` was
attached via `addFinalizer` (tied to GC of the `JSUint8Array` view)
instead of the `ArrayBuffer` destructor. Extracting `.buffer` and
letting the Buffer get GC'd would free the backing data while the
`ArrayBuffer` still referenced it. Fixed by attaching the destructor to
the `ArrayBuffer` via `createFromBytes`, using an armed
`NapiExternalBufferDestructor` to safely handle the
`JSUint8Array::create` error path.

Closes #26446
Closes #26423

## Test plan

- [x] Added regression test `test_napi_get_named_property_copied_string`
-- strdup/free cycles with GC to reproduce the atom table dangling
pointer
- [x] Added regression test `test_external_buffer_data_lifetime` --
extracts ArrayBuffer, drops Buffer, GCs, verifies data is intact
- [x] Both tests pass with `bun bd test` and match Node.js output via
`checkSameOutput`
- [x] Verified `test_external_buffer_data_lifetime` fails without the
fix (data corrupted) and passes on Node.js
- [x] Verified impit reproducer from #26423 works correctly with the fix

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-25 20:11:52 -08:00
Dylan Conway
f87fa27fac Update WebKit (#26449)
### What does this PR do?
Updates WebKit to
6e287faaed
### How did you verify your code works?
2026-01-25 18:43:55 -08:00
Dylan Conway
4071624edd Update WebKit (#26381)
### What does this PR do?
Updates WebKit to
5b6a0ac49b
### How did you verify your code works?

---------

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: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 10:38:13 -08:00
robobun
bfe40e8760 fix(cmake): use BUILDKITE_BUILD_NUMBER to avoid 302 redirect (#26409)
## What does this PR do?

Fixes CMake "No jobs found" error during the build-bun step in CI by
using `BUILDKITE_BUILD_NUMBER` instead of `BUILDKITE_BUILD_ID` (UUID)
for the Buildkite API URL.

### Problem

When `BUN_LINK_ONLY=ON`, `SetupBuildkite.cmake` fetches build info from
the Buildkite API to download artifacts from earlier build steps
(build-cpp, build-zig).

The `BUILDKITE_BUILD_ID` environment variable contains a UUID (e.g.,
`019bee3e-da45-4e9f-b4d8-4bdb5aeac0ac`). When this UUID is used in the
URL, Buildkite returns a **302 redirect** to the numeric build number
URL (e.g., `/builds/35708`).

CMake's `file(DOWNLOAD)` command **does not follow HTTP redirects**, so
the downloaded file is empty. Parsing the empty JSON yields 0 jobs,
triggering the fatal error:

```
CMake Error at cmake/tools/SetupBuildkite.cmake:67 (message):
  No jobs found:
  https://buildkite.com/bun/bun/builds/019bee3e-da45-4e9f-b4d8-4bdb5aeac0ac
```

### Solution

Prefer `BUILDKITE_BUILD_NUMBER` (numeric, e.g., `35708`) when available,
which doesn't redirect. This environment variable is automatically set
by Buildkite.

## How did you verify your code works?

- Verified UUID URL returns 302: `curl -sS -w '%{http_code}'
"https://buildkite.com/bun/bun/builds/019bee3e-da45-4e9f-b4d8-4bdb5aeac0ac"`
→ `302`
- Verified numeric URL returns 200 with JSON: `curl -sS -H "Accept:
application/json" "https://buildkite.com/bun/bun/builds/35708"` → valid
JSON with jobs array

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 23:54:33 -08:00
github-actions[bot]
bcaae48a95 deps: update lolhtml to v2.7.1 (#26430)
## What does this PR do?

Updates lolhtml to version v2.7.1

Compare:
d64457d9ff...e9e16dca48

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

Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2026-01-24 23:54:09 -08:00
robobun
6b3403a2b4 ci: fix update workflows creating duplicate PRs (#26433)
## Summary
- Fixed all `update-*.yml` workflows that were creating duplicate PRs
every week

## Problem
The update workflows (libarchive, zstd, cares, etc.) were using `${{
github.run_number }}` in the branch name, e.g.:
```yaml
branch: deps/update-libarchive-${{ github.run_number }}
```

This caused a new unique branch to be created on every workflow run, so
the `peter-evans/create-pull-request` action couldn't detect existing
PRs and would create duplicates.

**Evidence:** There are currently 8+ open duplicate PRs for libarchive
alone:
- #26432 deps: update libarchive to v3.8.5 (deps/update-libarchive-56)
- #26209 deps: update libarchive to v3.8.5 (deps/update-libarchive-55)
- #25955 deps: update libarchive to v3.8.5 (deps/update-libarchive-54)
- etc.

## Solution
Changed all workflows to use static branch names, e.g.:
```yaml
branch: deps/update-libarchive
```

This allows the action to:
1. Detect if an existing branch/PR already exists
2. Update the existing PR with new changes instead of creating a new one
3. Properly use `delete-branch: true` when the PR is merged

## Files Changed
- `.github/workflows/update-cares.yml`
- `.github/workflows/update-hdrhistogram.yml`
- `.github/workflows/update-highway.yml`
- `.github/workflows/update-libarchive.yml`
- `.github/workflows/update-libdeflate.yml`
- `.github/workflows/update-lolhtml.yml`
- `.github/workflows/update-lshpack.yml`
- `.github/workflows/update-root-certs.yml`
- `.github/workflows/update-sqlite3.yml`
- `.github/workflows/update-vendor.yml`
- `.github/workflows/update-zstd.yml`

## Test plan
- [x] Verified the change is syntactically correct
- [ ] Wait for next scheduled run of any workflow to verify it updates
existing PR instead of creating a new one

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 23:53:50 -08:00
526 changed files with 63314 additions and 3213 deletions

View File

@@ -1,5 +1,5 @@
ARG LLVM_VERSION="19"
ARG REPORTED_LLVM_VERSION="19.1.7"
ARG LLVM_VERSION="21"
ARG REPORTED_LLVM_VERSION="21.1.8"
ARG OLD_BUN_VERSION="1.1.38"
ARG BUILDKITE_AGENT_TAGS="queue=linux,os=linux,arch=${TARGETARCH}"
@@ -26,7 +26,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
wget curl git python3 python3-pip ninja-build \
software-properties-common apt-transport-https \
ca-certificates gnupg lsb-release unzip \
libxml2-dev ruby ruby-dev bison gawk perl make golang ccache \
libxml2-dev ruby ruby-dev bison gawk perl make golang ccache qemu-user-static \
&& add-apt-repository ppa:ubuntu-toolchain-r/test \
&& apt-get update \
&& apt-get install -y gcc-13 g++-13 libgcc-13-dev libstdc++-13-dev \

View File

@@ -109,12 +109,12 @@ 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.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: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.23" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.23" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.23" },
{ os: "windows", arch: "x64", release: "2019" },
{ os: "windows", arch: "x64", baseline: true, release: "2019" },
// TODO: Enable when Windows ARM64 CI runners are ready
// TODO: Re-enable when Windows ARM64 VS component installation is resolved on Buildkite runners
// { os: "windows", arch: "aarch64", release: "2019" },
];
@@ -133,9 +133,9 @@ const testPlatforms = [
{ os: "linux", arch: "aarch64", distro: "ubuntu", release: "25.04", tier: "latest" },
{ os: "linux", arch: "x64", distro: "ubuntu", release: "25.04", tier: "latest" },
{ os: "linux", arch: "x64", baseline: true, distro: "ubuntu", release: "25.04", 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: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.23", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.23", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.23", tier: "latest" },
{ os: "windows", arch: "x64", release: "2019", tier: "oldest" },
{ os: "windows", arch: "x64", release: "2019", baseline: true, tier: "oldest" },
// TODO: Enable when Windows ARM64 CI runners are ready
@@ -304,6 +304,13 @@ function getCppAgent(platform, options) {
};
}
// Cross-compile Windows ARM64 from x64 runners
if (os === "windows" && arch === "aarch64") {
return getEc2Agent({ ...platform, arch: "x64" }, options, {
instanceType: "c7i.4xlarge",
});
}
return getEc2Agent(platform, options, {
instanceType: arch === "aarch64" ? "c8g.4xlarge" : "c7i.4xlarge",
});
@@ -326,8 +333,10 @@ function getLinkBunAgent(platform, options) {
}
if (os === "windows") {
return getEc2Agent(platform, options, {
instanceType: arch === "aarch64" ? "r8g.large" : "r7i.large",
// Cross-compile Windows ARM64 from x64 runners
const agentPlatform = arch === "aarch64" ? { ...platform, arch: "x64" } : platform;
return getEc2Agent(agentPlatform, options, {
instanceType: "r7i.large",
});
}
@@ -345,7 +354,7 @@ function getZigPlatform() {
arch: "aarch64",
abi: "musl",
distro: "alpine",
release: "3.22",
release: "3.23",
};
}
@@ -456,6 +465,17 @@ function getBuildCommand(target, options, label) {
return `bun run build:${buildProfile}`;
}
/**
* Get extra flags needed when cross-compiling Windows ARM64 from x64.
* Applied to C++ and link steps (not Zig, which has its own toolchain handling).
*/
function getWindowsArm64CrossFlags(target) {
if (target.os === "windows" && target.arch === "aarch64") {
return " --toolchain windows-aarch64";
}
return "";
}
/**
* @param {Platform} platform
* @param {PipelineOptions} options
@@ -463,6 +483,8 @@ function getBuildCommand(target, options, label) {
*/
function getBuildCppStep(platform, options) {
const command = getBuildCommand(platform, options);
const crossFlags = getWindowsArm64CrossFlags(platform);
return {
key: `${getTargetKey(platform)}-build-cpp`,
label: `${getTargetLabel(platform)} - build-cpp`,
@@ -476,7 +498,7 @@ function getBuildCppStep(platform, options) {
// We used to build the C++ dependencies and bun in separate steps.
// However, as long as the zig build takes longer than both sequentially,
// it's cheaper to run them in the same step. Can be revisited in the future.
command: [`${command} --target bun`, `${command} --target dependencies`],
command: [`${command}${crossFlags} --target bun`, `${command}${crossFlags} --target dependencies`],
};
}
@@ -533,7 +555,110 @@ function getLinkBunStep(platform, options) {
ASAN_OPTIONS: "allow_user_segv_handler=1:disable_coredump=0:detect_leaks=0",
...getBuildEnv(platform, options),
},
command: `${getBuildCommand(platform, options, "build-bun")} --target bun`,
command: `${getBuildCommand(platform, options, "build-bun")}${getWindowsArm64CrossFlags(platform)} --target bun`,
};
}
/**
* Returns the artifact triplet for a platform, e.g. "bun-linux-aarch64" or "bun-linux-x64-musl-baseline".
* Matches the naming convention in cmake/targets/BuildBun.cmake.
* @param {Platform} platform
* @returns {string}
*/
function getTargetTriplet(platform) {
const { os, arch, abi, baseline } = platform;
let triplet = `bun-${os}-${arch}`;
if (abi === "musl") {
triplet += "-musl";
}
if (baseline) {
triplet += "-baseline";
}
return triplet;
}
/**
* Returns true if a platform needs QEMU-based baseline CPU verification.
* x64 baseline builds verify no AVX/AVX2 instructions snuck in.
* aarch64 builds verify no LSE/SVE instructions snuck in.
* @param {Platform} platform
* @returns {boolean}
*/
function needsBaselineVerification(platform) {
const { os, arch, baseline } = platform;
if (os !== "linux") return false;
return (arch === "x64" && baseline) || arch === "aarch64";
}
/**
* @param {Platform} platform
* @param {PipelineOptions} options
* @returns {Step}
*/
function getVerifyBaselineStep(platform, options) {
const { arch } = platform;
const targetKey = getTargetKey(platform);
const archArg = arch === "x64" ? "x64" : "aarch64";
return {
key: `${targetKey}-verify-baseline`,
label: `${getTargetLabel(platform)} - verify-baseline`,
depends_on: [`${targetKey}-build-bun`],
agents: getLinkBunAgent(platform, options),
retry: getRetry(),
cancel_on_build_failing: isMergeQueue(),
timeout_in_minutes: 5,
command: [
`buildkite-agent artifact download '*.zip' . --step ${targetKey}-build-bun`,
`unzip -o '${getTargetTriplet(platform)}.zip'`,
`unzip -o '${getTargetTriplet(platform)}-profile.zip'`,
`chmod +x ${getTargetTriplet(platform)}/bun ${getTargetTriplet(platform)}-profile/bun-profile`,
`./scripts/verify-baseline-cpu.sh --arch ${archArg} --binary ${getTargetTriplet(platform)}/bun`,
`./scripts/verify-baseline-cpu.sh --arch ${archArg} --binary ${getTargetTriplet(platform)}-profile/bun-profile`,
],
};
}
/**
* Returns true if the PR modifies SetupWebKit.cmake (WebKit version changes).
* JIT stress tests under QEMU should run when WebKit is updated to catch
* JIT-generated code that uses unsupported CPU instructions.
* @param {PipelineOptions} options
* @returns {boolean}
*/
function hasWebKitChanges(options) {
const { changedFiles = [] } = options;
return changedFiles.some(file => file.includes("SetupWebKit.cmake"));
}
/**
* Returns a step that runs JSC JIT stress tests under QEMU.
* This verifies that JIT-compiled code doesn't use CPU instructions
* beyond the baseline target (no AVX on x64, no LSE on aarch64).
* @param {Platform} platform
* @param {PipelineOptions} options
* @returns {Step}
*/
function getJitStressTestStep(platform, options) {
const { arch } = platform;
const targetKey = getTargetKey(platform);
const archArg = arch === "x64" ? "x64" : "aarch64";
return {
key: `${targetKey}-jit-stress-qemu`,
label: `${getTargetLabel(platform)} - jit-stress-qemu`,
depends_on: [`${targetKey}-build-bun`],
agents: getLinkBunAgent(platform, options),
retry: getRetry(),
cancel_on_build_failing: isMergeQueue(),
// JIT stress tests are slow under QEMU emulation
timeout_in_minutes: 30,
command: [
`buildkite-agent artifact download '*.zip' . --step ${targetKey}-build-bun`,
`unzip -o '${getTargetTriplet(platform)}.zip'`,
`chmod +x ${getTargetTriplet(platform)}/bun`,
`./scripts/verify-jit-stress-qemu.sh --arch ${archArg} --binary ${getTargetTriplet(platform)}/bun`,
],
};
}
@@ -774,6 +899,7 @@ function getBenchmarkStep() {
* @property {Platform[]} [buildPlatforms]
* @property {Platform[]} [testPlatforms]
* @property {string[]} [testFiles]
* @property {string[]} [changedFiles]
*/
/**
@@ -1075,6 +1201,8 @@ async function getPipeline(options = {}) {
buildImages || publishImages
? [...buildPlatforms, ...testPlatforms]
.filter(({ os }) => os !== "darwin")
// Windows ARM64 cross-compiles from x64 runners, no separate image needed
.filter(({ os, arch }) => !(os === "windows" && arch === "aarch64"))
.map(platform => [getImageKey(platform), platform])
: [],
);
@@ -1126,6 +1254,14 @@ async function getPipeline(options = {}) {
steps.push(getBuildZigStep(target, options));
steps.push(getLinkBunStep(target, options));
if (needsBaselineVerification(target)) {
steps.push(getVerifyBaselineStep(target, options));
// Run JIT stress tests under QEMU when WebKit is updated
if (hasWebKitChanges(options)) {
steps.push(getJitStressTestStep(target, options));
}
}
return getStepWithDependsOn(
{
key: getTargetKey(target),
@@ -1223,6 +1359,7 @@ async function main() {
console.log(`- PR is only docs, skipping tests!`);
return;
}
options.changedFiles = allFiles;
}
startGroup("Generating pipeline...");

View File

@@ -219,9 +219,8 @@ function create_release() {
bun-windows-x64-profile.zip
bun-windows-x64-baseline.zip
bun-windows-x64-baseline-profile.zip
# TODO: Enable when Windows ARM64 CI runners are ready
# bun-windows-aarch64.zip
# bun-windows-aarch64-profile.zip
bun-windows-aarch64.zip
bun-windows-aarch64-profile.zip
)
function upload_artifact() {

View File

@@ -33,8 +33,8 @@ The workflow runs all three formatters simultaneously:
#### 3. Tool Installation
##### Clang-format-19
- Installs ONLY `clang-format-19` package (not the entire LLVM toolchain)
##### Clang-format-21
- Installs ONLY `clang-format-21` package (not the entire LLVM toolchain)
- Uses `--no-install-recommends --no-install-suggests` to skip unnecessary packages
- Quiet installation with `-qq` and `-o=Dpkg::Use-Pty=0`

View File

@@ -10,8 +10,8 @@ on:
merge_group:
env:
BUN_VERSION: "1.3.2"
LLVM_VERSION: "19.1.7"
LLVM_VERSION_MAJOR: "19"
LLVM_VERSION: "21.1.8"
LLVM_VERSION_MAJOR: "21"
jobs:
autofix:

View File

@@ -88,7 +88,7 @@ jobs:
commit-message: "deps: update c-ares to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
title: "deps: update c-ares to ${{ steps.check-version.outputs.tag }}"
delete-branch: true
branch: deps/update-cares-${{ github.run_number }}
branch: deps/update-cares
body: |
## What does this PR do?

View File

@@ -91,7 +91,7 @@ jobs:
commit-message: "deps: update hdrhistogram to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
title: "deps: update hdrhistogram to ${{ steps.check-version.outputs.tag }}"
delete-branch: true
branch: deps/update-hdrhistogram-${{ github.run_number }}
branch: deps/update-hdrhistogram
body: |
## What does this PR do?

View File

@@ -107,7 +107,7 @@ jobs:
commit-message: "deps: update highway to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
title: "deps: update highway to ${{ steps.check-version.outputs.tag }}"
delete-branch: true
branch: deps/update-highway-${{ github.run_number }}
branch: deps/update-highway
body: |
## What does this PR do?

View File

@@ -88,7 +88,7 @@ jobs:
commit-message: "deps: update libarchive to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
title: "deps: update libarchive to ${{ steps.check-version.outputs.tag }}"
delete-branch: true
branch: deps/update-libarchive-${{ github.run_number }}
branch: deps/update-libarchive
body: |
## What does this PR do?

View File

@@ -88,7 +88,7 @@ jobs:
commit-message: "deps: update libdeflate to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
title: "deps: update libdeflate to ${{ steps.check-version.outputs.tag }}"
delete-branch: true
branch: deps/update-libdeflate-${{ github.run_number }}
branch: deps/update-libdeflate
body: |
## What does this PR do?

View File

@@ -100,7 +100,7 @@ jobs:
commit-message: "deps: update lolhtml to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
title: "deps: update lolhtml to ${{ steps.check-version.outputs.tag }}"
delete-branch: true
branch: deps/update-lolhtml-${{ github.run_number }}
branch: deps/update-lolhtml
body: |
## What does this PR do?

View File

@@ -105,7 +105,7 @@ jobs:
commit-message: "deps: update lshpack to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
title: "deps: update lshpack to ${{ steps.check-version.outputs.tag }}"
delete-branch: true
branch: deps/update-lshpack-${{ github.run_number }}
branch: deps/update-lshpack
body: |
## What does this PR do?

View File

@@ -74,7 +74,7 @@ jobs:
```
${{ env.changed_files }}
```
branch: certs/update-root-certs-${{ github.run_number }}
branch: certs/update-root-certs
base: main
delete-branch: true
labels:

View File

@@ -83,7 +83,7 @@ jobs:
commit-message: "deps: update sqlite to ${{ steps.check-version.outputs.latest }}"
title: "deps: update sqlite to ${{ steps.check-version.outputs.latest }}"
delete-branch: true
branch: deps/update-sqlite-${{ steps.check-version.outputs.latest }}
branch: deps/update-sqlite
body: |
## What does this PR do?

View File

@@ -68,7 +68,7 @@ jobs:
commit-message: "deps: update ${{ matrix.package }} to ${{ steps.check-version.outputs.latest }} (${{ steps.check-version.outputs.latest }})"
title: "deps: update ${{ matrix.package }} to ${{ steps.check-version.outputs.latest }}"
delete-branch: true
branch: deps/update-${{ matrix.package }}-${{ github.run_number }}
branch: deps/update-${{ matrix.package }}
body: |
## What does this PR do?

View File

@@ -88,7 +88,7 @@ jobs:
commit-message: "deps: update zstd to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
title: "deps: update zstd to ${{ steps.check-version.outputs.tag }}"
delete-branch: true
branch: deps/update-zstd-${{ github.run_number }}
branch: deps/update-zstd
body: |
## What does this PR do?

View File

@@ -35,7 +35,7 @@ $ sudo pacman -S base-devel cmake git go libiconv libtool make ninja pkg-config
```
```bash#Fedora
$ 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)'
$ sudo dnf install cargo clang21 llvm21 lld21 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
@@ -90,17 +90,17 @@ Our build scripts will automatically detect and use `ccache` if available. You c
## 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:
Bun requires LLVM 21.1.8 (`clang` is part of LLVM). This version is enforced by the build system — mismatching versions will cause memory allocation failures at runtime. In most cases, you can install LLVM through your system package manager:
{% codetabs group="os" %}
```bash#macOS (Homebrew)
$ brew install llvm@19
$ brew install llvm@21
```
```bash#Ubuntu/Debian
$ # LLVM has an automatic installation script that is compatible with all versions of Ubuntu
$ wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 19 all
$ wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 21 all
```
```bash#Arch
@@ -112,17 +112,17 @@ $ sudo dnf install llvm clang lld-devel
```
```bash#openSUSE Tumbleweed
$ sudo zypper install clang19 lld19 llvm19
$ sudo zypper install clang21 lld21 llvm21
```
{% /codetabs %}
If none of the above solutions apply, you will have to install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-19.1.7).
If none of the above solutions apply, you will have to install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-21.1.8).
Make sure Clang/LLVM 19 is in your path:
Make sure Clang/LLVM 21 is in your path:
```bash
$ which clang-19
$ which clang-21
```
If not, run this to manually add it:
@@ -131,13 +131,13 @@ If not, run this to manually add it:
```bash#macOS (Homebrew)
# use fish_add_path if you're using fish
# use path+="$(brew --prefix llvm@19)/bin" if you are using zsh
$ export PATH="$(brew --prefix llvm@19)/bin:$PATH"
# use path+="$(brew --prefix llvm@21)/bin" if you are using zsh
$ export PATH="$(brew --prefix llvm@21)/bin:$PATH"
```
```bash#Arch
# use fish_add_path if you're using fish
$ export PATH="$PATH:/usr/lib/llvm19/bin"
$ export PATH="$PATH:/usr/lib/llvm21/bin"
```
{% /codetabs %}
@@ -259,18 +259,13 @@ $ git clone https://github.com/oven-sh/WebKit vendor/WebKit
# Check out the commit hash specified in `set(WEBKIT_VERSION <commit_hash>)` in cmake/tools/SetupWebKit.cmake
$ git -C vendor/WebKit checkout <commit_hash>
# Make a debug build of JSC. This will output build artifacts in ./vendor/WebKit/WebKitBuild/Debug
# Optionally, you can use `bun run jsc:build` for a release build
$ bun run jsc:build:debug && rm vendor/WebKit/WebKitBuild/Debug/JavaScriptCore/DerivedSources/inspector/InspectorProtocolObjects.h
# After an initial run of `make jsc-debug`, you can rebuild JSC with:
$ cmake --build vendor/WebKit/WebKitBuild/Debug --target jsc && rm vendor/WebKit/WebKitBuild/Debug/JavaScriptCore/DerivedSources/inspector/InspectorProtocolObjects.h
# Build bun with the local JSC build
# Build bun with the local JSC build — this automatically configures and builds JSC
$ bun run build:local
```
Using `bun run build:local` will build Bun in the `./build/debug-local` directory (instead of `./build/debug`), you'll have to change a couple of places to use this new directory:
`bun run build:local` handles everything: configuring JSC, building JSC, and building Bun. On subsequent runs, JSC will incrementally rebuild if any WebKit sources changed. `ninja -Cbuild/debug-local` also works after the first build, and will build Bun+JSC.
The build output goes to `./build/debug-local` (instead of `./build/debug`), so you'll need to update a couple of places:
- The first line in [`src/js/builtins.d.ts`](/src/js/builtins.d.ts)
- The `CompilationDatabase` line in [`.clangd` config](/.clangd) should be `CompilationDatabase: build/debug-local`
@@ -281,7 +276,7 @@ Note that the WebKit folder, including build artifacts, is 8GB+ in size.
If you are using a JSC debug build and using VScode, make sure to run the `C/C++: Select a Configuration` command to configure intellisense to find the debug headers.
Note that if you change make changes to our [WebKit fork](https://github.com/oven-sh/WebKit), you will also have to change [`SetupWebKit.cmake`](/cmake/tools/SetupWebKit.cmake) to point to the commit hash.
Note that if you make changes to our [WebKit fork](https://github.com/oven-sh/WebKit), you will also have to change [`SetupWebKit.cmake`](/cmake/tools/SetupWebKit.cmake) to point to the commit hash.
## Troubleshooting
@@ -304,7 +299,7 @@ The issue may manifest when initially running `bun setup` as Clang being unable
```
The C++ compiler
"/usr/bin/clang++-19"
"/usr/bin/clang++-21"
is not able to compile a simple test program.
```

2
LATEST
View File

@@ -1 +1 @@
1.3.6
1.3.9

View File

@@ -18,9 +18,13 @@
"fast-glob": "3.3.1",
"fastify": "^5.0.0",
"fdir": "^6.1.0",
"mitata": "^1.0.25",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"marked": "^17.0.1",
"mitata": "1.0.20",
"react": "^19",
"react-dom": "^19",
"react-markdown": "^9.0.3",
"remark": "^15.0.1",
"remark-html": "^16.0.1",
"string-width": "7.1.0",
"strip-ansi": "^7.1.0",
"tar": "^7.4.3",
@@ -150,18 +154,36 @@
"@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.3.35", "", { "os": "win32", "cpu": "x64" }, "sha512-/RvphT4WfuGfIK84Ha0dovdPrKB1bW/mc+dtdmhv2E3EGkNc5FoueNwYmXWRimxnU7X0X7IkcRhyKB4G5DeAmg=="],
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="],
"@types/fs-extra": ["@types/fs-extra@11.0.4", "", { "dependencies": { "@types/jsonfile": "*", "@types/node": "*" } }, "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ=="],
"@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
"@types/jsonfile": ["@types/jsonfile@6.1.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ=="],
"@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
"@types/minimist": ["@types/minimist@1.2.5", "", {}, "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag=="],
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
"@types/node": ["@types/node@18.19.8", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-g1pZtPhsvGVTwmeVoexWZLTQaOvXwoSq//pTL0DHeNzUDrFnir4fgETdhjhIxjVnN+hKOuh98+E1eMLnUXstFg=="],
"@types/ps-tree": ["@types/ps-tree@1.1.6", "", {}, "sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ=="],
"@types/react": ["@types/react@19.2.10", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw=="],
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
"@types/which": ["@types/which@3.0.3", "", {}, "sha512-2C1+XoY0huExTbs8MQv1DuS5FS86+SEjdM9F/+GS61gg5Hqbtj8ZiDSx8MfWcyei907fIPbfPGCOrNUTnVHY1g=="],
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
"abstract-logging": ["abstract-logging@2.0.1", "", {}, "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="],
"ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
@@ -176,6 +198,8 @@
"avvio": ["avvio@9.1.0", "", { "dependencies": { "@fastify/error": "^4.0.0", "fastq": "^1.17.1" } }, "sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw=="],
"bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
"benchmark": ["benchmark@2.1.4", "", { "dependencies": { "lodash": "^4.17.4", "platform": "^1.3.3" } }, "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ=="],
"braces": ["braces@3.0.2", "", { "dependencies": { "fill-range": "^7.0.1" } }, "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A=="],
@@ -184,8 +208,18 @@
"caniuse-lite": ["caniuse-lite@1.0.30001456", "", {}, "sha512-XFHJY5dUgmpMV25UqaD4kVq2LsiaU5rS8fb0f17pCoXQiQslzmFgnfOxfvo1bTpTqf7dwG/N/05CnLCnOEKmzA=="],
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
"chalk": ["chalk@5.3.0", "", {}, "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w=="],
"character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="],
"character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="],
"character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="],
"character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="],
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
"color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
@@ -196,18 +230,26 @@
"color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
"comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
"convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="],
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
"cross-spawn": ["cross-spawn@7.0.3", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w=="],
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
"debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="],
"decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="],
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
"devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="],
"dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="],
"duplexer": ["duplexer@0.1.2", "", {}, "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg=="],
@@ -262,12 +304,16 @@
"escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
"estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="],
"event-stream": ["event-stream@3.3.4", "", { "dependencies": { "duplexer": "~0.1.1", "from": "~0", "map-stream": "~0.1.0", "pause-stream": "0.0.11", "split": "0.3", "stream-combiner": "~0.0.4", "through": "~2.3.1" } }, "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g=="],
"eventemitter3": ["eventemitter3@5.0.0", "", {}, "sha512-riuVbElZZNXLeLEoprfNYoDSwTBRR44X3mnhdI1YcnENpWTCsTTVZ2zFuqQcpoyqPQIUXdiPEU0ECAq0KQRaHg=="],
"execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
@@ -318,20 +364,44 @@
"has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
"hast-util-sanitize": ["hast-util-sanitize@5.0.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "unist-util-position": "^5.0.0" } }, "sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg=="],
"hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="],
"hast-util-to-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="],
"hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="],
"html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
"html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="],
"human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
"ignore": ["ignore@5.3.0", "", {}, "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg=="],
"inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="],
"ipaddr.js": ["ipaddr.js@2.2.0", "", {}, "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA=="],
"is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="],
"is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="],
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
"is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
"is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="],
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
"is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
"is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
@@ -352,16 +422,76 @@
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
"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=="],
"longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"map-stream": ["map-stream@0.1.0", "", {}, "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g=="],
"marked": ["marked@17.0.1", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg=="],
"mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA=="],
"mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="],
"mdast-util-mdx-jsx": ["mdast-util-mdx-jsx@3.2.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q=="],
"mdast-util-mdxjs-esm": ["mdast-util-mdxjs-esm@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg=="],
"mdast-util-phrasing": ["mdast-util-phrasing@4.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" } }, "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w=="],
"mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="],
"mdast-util-to-markdown": ["mdast-util-to-markdown@2.1.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA=="],
"mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="],
"merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
"micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="],
"micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="],
"micromark-factory-destination": ["micromark-factory-destination@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA=="],
"micromark-factory-label": ["micromark-factory-label@2.0.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg=="],
"micromark-factory-space": ["micromark-factory-space@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg=="],
"micromark-factory-title": ["micromark-factory-title@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw=="],
"micromark-factory-whitespace": ["micromark-factory-whitespace@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ=="],
"micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="],
"micromark-util-chunked": ["micromark-util-chunked@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA=="],
"micromark-util-classify-character": ["micromark-util-classify-character@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q=="],
"micromark-util-combine-extensions": ["micromark-util-combine-extensions@2.0.1", "", { "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg=="],
"micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@2.0.2", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw=="],
"micromark-util-decode-string": ["micromark-util-decode-string@2.0.1", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ=="],
"micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="],
"micromark-util-html-tag-name": ["micromark-util-html-tag-name@2.0.1", "", {}, "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA=="],
"micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q=="],
"micromark-util-resolve-all": ["micromark-util-resolve-all@2.0.1", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg=="],
"micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="],
"micromark-util-subtokenize": ["micromark-util-subtokenize@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA=="],
"micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="],
"micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="],
"micromatch": ["micromatch@4.0.5", "", { "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" } }, "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA=="],
"mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
@@ -372,7 +502,7 @@
"minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="],
"mitata": ["mitata@1.0.25", "", {}, "sha512-0v5qZtVW5vwj9FDvYfraR31BMDcRLkhSFWPTLaxx/Z3/EvScfVtAAWtMI2ArIbBcwh7P86dXh0lQWKiXQPlwYA=="],
"mitata": ["mitata@1.0.20", "", {}, "sha512-oHWYGX5bi4wGT/1zrhiZAEzqTV14Vq6/PUTW8WK0b3YHBBQcZz2QFm+InHhjnD0I7B6CMtwdGt2K0938r7YTdQ=="],
"ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
@@ -388,6 +518,8 @@
"onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="],
"parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
@@ -408,18 +540,32 @@
"process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="],
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
"ps-tree": ["ps-tree@1.2.0", "", { "dependencies": { "event-stream": "=3.3.4" }, "bin": { "ps-tree": "./bin/ps-tree.js" } }, "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="],
"react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],
"react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
"react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="],
"react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
"react-markdown": ["react-markdown@9.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-xaijuJB0kzGiUdG7nc2MOMDUDBWPyGAjZtUrow9XxUeua8IqeP+VlIfAZ3bphpcLTnSZXz6z9jcVC/TCwbfgdw=="],
"real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="],
"remark": ["remark@15.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A=="],
"remark-html": ["remark-html@16.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "hast-util-sanitize": "^5.0.0", "hast-util-to-html": "^9.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0" } }, "sha512-B9JqA5i0qZe0Nsf49q3OXyGvyXuZFDzAP2iOFLEumymuYJITVpiH1IgsTEwTpdptDmZlMDMWeDmSawdaJIGCXQ=="],
"remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="],
"remark-rehype": ["remark-rehype@11.1.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw=="],
"remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="],
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
"ret": ["ret@0.5.0", "", {}, "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw=="],
@@ -434,7 +580,7 @@
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
"scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
"secure-json-parse": ["secure-json-parse@4.0.0", "", {}, "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA=="],
@@ -454,6 +600,8 @@
"sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="],
"space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="],
"split": ["split@0.3.3", "", { "dependencies": { "through": "2" } }, "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA=="],
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
@@ -462,10 +610,16 @@
"string-width": ["string-width@7.1.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw=="],
"stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="],
"strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
"strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
"style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="],
"style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="],
"supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
"tar": ["tar@7.5.2", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg=="],
@@ -482,12 +636,32 @@
"toad-cache": ["toad-cache@3.7.0", "", {}, "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw=="],
"trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
"trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="],
"undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
"unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="],
"unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="],
"unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
"unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="],
"unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="],
"universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
"update-browserslist-db": ["update-browserslist-db@1.0.10", "", { "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "browserslist-lint": "cli.js" } }, "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ=="],
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
"vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
"web-streams-polyfill": ["web-streams-polyfill@3.3.2", "", {}, "sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ=="],
"webpod": ["webpod@0.0.2", "", { "bin": { "webpod": "dist/index.js" } }, "sha512-cSwwQIeg8v4i3p4ajHhwgR7N6VyxAf+KYSSsY6Pd3aETE+xEU4vbitz7qQkB0I321xnhDdgtxuiSfk5r/FVtjg=="],
@@ -500,6 +674,8 @@
"yaml": ["yaml@2.3.4", "", {}, "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA=="],
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
"zx": ["zx@7.2.3", "", { "dependencies": { "@types/fs-extra": "^11.0.1", "@types/minimist": "^1.2.2", "@types/node": "^18.16.3", "@types/ps-tree": "^1.1.2", "@types/which": "^3.0.0", "chalk": "^5.2.0", "fs-extra": "^11.1.1", "fx": "*", "globby": "^13.1.4", "minimist": "^1.2.8", "node-fetch": "3.3.1", "ps-tree": "^1.2.0", "webpod": "^0", "which": "^3.0.0", "yaml": "^2.2.2" }, "bin": { "zx": "build/cli.js" } }, "sha512-QODu38nLlYXg/B/Gw7ZKiZrvPkEsjPN3LQ5JFXM7h0JvwhEdPNNl+4Ao1y4+o3CLNiDUNcwzQYZ4/Ko7kKzCMA=="],
"@babel/generator/@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.2", "", { "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.9" } }, "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A=="],
@@ -518,6 +694,8 @@
"npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
"@babel/highlight/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
"@babel/highlight/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],

15
bench/json5/bun.lock Normal file
View File

@@ -0,0 +1,15 @@
{
"lockfileVersion": 1,
"configVersion": 1,
"workspaces": {
"": {
"name": "json5-benchmark",
"dependencies": {
"json5": "^2.2.3",
},
},
},
"packages": {
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
}
}

88
bench/json5/json5.mjs Normal file
View File

@@ -0,0 +1,88 @@
import JSON5 from "json5";
import { bench, group, run } from "../runner.mjs";
const isBun = typeof Bun !== "undefined" && Bun.JSON5;
function sizeLabel(n) {
if (n >= 1024 * 1024) return `${(n / 1024 / 1024).toFixed(1)}MB`;
if (n >= 1024) return `${(n / 1024).toFixed(0)}KB`;
return `${n}B`;
}
// -- parse inputs --
const smallJson5 = `{
// User profile
name: "John Doe",
age: 30,
email: 'john@example.com',
active: true,
}`;
function generateLargeJson5(count) {
const lines = ["{\n // Auto-generated dataset\n items: [\n"];
for (let i = 0; i < count; i++) {
lines.push(` {
id: ${i},
name: 'item_${i}',
value: ${(Math.random() * 1000).toFixed(2)},
hex: 0x${i.toString(16).toUpperCase()},
active: ${i % 2 === 0},
tags: ['tag_${i % 10}', 'category_${i % 5}',],
// entry ${i}
},\n`);
}
lines.push(" ],\n total: " + count + ",\n status: 'complete',\n}\n");
return lines.join("");
}
const largeJson5 = generateLargeJson5(6500);
// -- stringify inputs --
const smallObject = {
name: "John Doe",
age: 30,
email: "john@example.com",
active: true,
};
const largeObject = {
items: Array.from({ length: 10000 }, (_, i) => ({
id: i,
name: `item_${i}`,
value: +(Math.random() * 1000).toFixed(2),
active: i % 2 === 0,
tags: [`tag_${i % 10}`, `category_${i % 5}`],
})),
total: 10000,
status: "complete",
};
const stringify = isBun ? Bun.JSON5.stringify : JSON5.stringify;
// -- parse benchmarks --
group(`parse small (${sizeLabel(smallJson5.length)})`, () => {
if (isBun) bench("Bun.JSON5.parse", () => Bun.JSON5.parse(smallJson5));
bench("json5.parse", () => JSON5.parse(smallJson5));
});
group(`parse large (${sizeLabel(largeJson5.length)})`, () => {
if (isBun) bench("Bun.JSON5.parse", () => Bun.JSON5.parse(largeJson5));
bench("json5.parse", () => JSON5.parse(largeJson5));
});
// -- stringify benchmarks --
group(`stringify small (${sizeLabel(stringify(smallObject).length)})`, () => {
if (isBun) bench("Bun.JSON5.stringify", () => Bun.JSON5.stringify(smallObject));
bench("json5.stringify", () => JSON5.stringify(smallObject));
});
group(`stringify large (${sizeLabel(stringify(largeObject).length)})`, () => {
if (isBun) bench("Bun.JSON5.stringify", () => Bun.JSON5.stringify(largeObject));
bench("json5.stringify", () => JSON5.stringify(largeObject));
});
await run();

7
bench/json5/package.json Normal file
View File

@@ -0,0 +1,7 @@
{
"name": "json5-benchmark",
"version": "1.0.0",
"dependencies": {
"json5": "^2.2.3"
}
}

View File

@@ -14,14 +14,18 @@
"fast-glob": "3.3.1",
"fastify": "^5.0.0",
"fdir": "^6.1.0",
"mitata": "^1.0.25",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"marked": "^17.0.1",
"mitata": "1.0.20",
"react": "^19",
"react-dom": "^19",
"react-markdown": "^9.0.3",
"remark": "^15.0.1",
"remark-html": "^16.0.1",
"string-width": "7.1.0",
"wrap-ansi": "^9.0.0",
"strip-ansi": "^7.1.0",
"tar": "^7.4.3",
"tinycolor2": "^1.6.0",
"wrap-ansi": "^9.0.0",
"zx": "^7.2.3"
},
"scripts": {

View File

@@ -0,0 +1,110 @@
// Benchmark for AbortController/AbortSignal abort() performance
// Tests the optimization of skipping Event creation when no listeners are registered
import { bench, group, run } from "../runner.mjs";
// Warmup: ensure JIT compilation
for (let i = 0; i < 1000; i++) {
const controller = new AbortController();
controller.abort();
}
group("AbortController.abort()", () => {
bench("no listener", () => {
const controller = new AbortController();
controller.abort();
});
bench("with addEventListener", () => {
const controller = new AbortController();
controller.signal.addEventListener("abort", () => {});
controller.abort();
});
bench("with onabort property", () => {
const controller = new AbortController();
controller.signal.onabort = () => {};
controller.abort();
});
bench("with 3 listeners", () => {
const controller = new AbortController();
controller.signal.addEventListener("abort", () => {});
controller.signal.addEventListener("abort", () => {});
controller.signal.addEventListener("abort", () => {});
controller.abort();
});
});
group("AbortSignal static methods", () => {
bench("AbortSignal.abort() - pre-aborted", () => {
const signal = AbortSignal.abort();
// Signal is already aborted, no event dispatch needed
});
bench("AbortSignal.any([]) - empty array", () => {
const signal = AbortSignal.any([]);
});
bench("AbortSignal.any([signal, signal]) - 2 signals", () => {
const a = new AbortController();
const b = new AbortController();
const signal = AbortSignal.any([a.signal, b.signal]);
});
bench("AbortSignal.any() then abort - no listener", () => {
const a = new AbortController();
const b = new AbortController();
const signal = AbortSignal.any([a.signal, b.signal]);
a.abort();
});
bench("AbortSignal.any() then abort - with listener", () => {
const a = new AbortController();
const b = new AbortController();
const signal = AbortSignal.any([a.signal, b.signal]);
signal.addEventListener("abort", () => {});
a.abort();
});
});
group("AbortController creation only", () => {
bench("new AbortController()", () => {
const controller = new AbortController();
});
bench("new AbortController() + access signal", () => {
const controller = new AbortController();
const signal = controller.signal;
});
});
group("AbortSignal.timeout()", () => {
// Note: These don't actually wait for timeout, just measure creation overhead
bench("AbortSignal.timeout(1000) creation", () => {
const signal = AbortSignal.timeout(1000);
});
bench("AbortSignal.timeout(0) creation", () => {
const signal = AbortSignal.timeout(0);
});
});
group("abort with reason", () => {
bench("abort() with no reason", () => {
const controller = new AbortController();
controller.abort();
});
bench("abort() with string reason", () => {
const controller = new AbortController();
controller.abort("cancelled");
});
bench("abort() with Error reason", () => {
const controller = new AbortController();
controller.abort(new Error("cancelled"));
});
});
await run();

View File

@@ -0,0 +1,38 @@
// @runtime bun,node
import { bench, group, run } from "../runner.mjs";
const small = Buffer.alloc(64, 0x42);
const medium = Buffer.alloc(1024, 0x42);
const large = Buffer.alloc(1024 * 1024, 0x42);
group("slice - no args", () => {
bench("Buffer(64).slice()", () => small.slice());
bench("Buffer(1024).slice()", () => medium.slice());
bench("Buffer(1M).slice()", () => large.slice());
});
group("slice - one int arg", () => {
bench("Buffer(64).slice(10)", () => small.slice(10));
bench("Buffer(1024).slice(10)", () => medium.slice(10));
bench("Buffer(1M).slice(1024)", () => large.slice(1024));
});
group("slice - two int args", () => {
bench("Buffer(64).slice(10, 50)", () => small.slice(10, 50));
bench("Buffer(1024).slice(10, 100)", () => medium.slice(10, 100));
bench("Buffer(1M).slice(1024, 4096)", () => large.slice(1024, 4096));
});
group("slice - negative args", () => {
bench("Buffer(64).slice(-10)", () => small.slice(-10));
bench("Buffer(1024).slice(-100, -10)", () => medium.slice(-100, -10));
bench("Buffer(1M).slice(-4096, -1024)", () => large.slice(-4096, -1024));
});
group("subarray - two int args", () => {
bench("Buffer(64).subarray(10, 50)", () => small.subarray(10, 50));
bench("Buffer(1024).subarray(10, 100)", () => medium.subarray(10, 100));
bench("Buffer(1M).subarray(1024, 4096)", () => large.subarray(1024, 4096));
});
await run();

View File

@@ -0,0 +1,92 @@
import React from "react";
import { renderToString } from "react-dom/server";
import ReactMarkdown from "react-markdown";
const markdown = `# Project README
## Introduction
This is a medium-sized markdown document that includes **bold text**, *italic text*,
and \`inline code\`. It also has [links](https://example.com) and various formatting.
## Features
- Feature one with **bold**
- Feature two with *emphasis*
- Feature three with \`code\`
- Feature four with [a link](https://example.com)
## Code Example
\`\`\`javascript
function hello() {
console.log("Hello, world!");
return 42;
}
const result = hello();
\`\`\`
## Table
| Name | Value | Description |
|------|-------|-------------|
| foo | 1 | First item |
| bar | 2 | Second item |
| baz | 3 | Third item |
## Blockquote
> This is a blockquote with **bold** and *italic* text.
> It spans multiple lines and contains a [link](https://example.com).
---
### Nested Lists
1. First ordered item
- Nested unordered
- Another nested
2. Second ordered item
1. Nested ordered
2. Another nested
3. Third ordered item
Some final paragraph with ~~strikethrough~~ text and more **formatting**.
`;
// Verify outputs are roughly the same
const bunHtml = renderToString(Bun.markdown.react(markdown));
const reactMarkdownHtml = renderToString(React.createElement(ReactMarkdown, { children: markdown }));
console.log("=== Bun.markdown.react output ===");
console.log(bunHtml.slice(0, 500));
console.log(`... (${bunHtml.length} chars total)\n`);
console.log("=== react-markdown output ===");
console.log(reactMarkdownHtml.slice(0, 500));
console.log(`... (${reactMarkdownHtml.length} chars total)\n`);
const server = Bun.serve({
port: 0,
routes: {
"/bun-markdown": () => {
return new Response(renderToString(Bun.markdown.react(markdown)), {
headers: { "Content-Type": "text/html" },
});
},
"/react-markdown": () => {
return new Response(renderToString(React.createElement(ReactMarkdown, { children: markdown })), {
headers: { "Content-Type": "text/html" },
});
},
},
});
console.log(`Server listening on ${server.url}`);
console.log(` ${server.url}bun-markdown`);
console.log(` ${server.url}react-markdown`);
console.log();
console.log("Run:");
console.log(` oha -c 20 -z 5s ${server.url}bun-markdown`);
console.log(` oha -c 20 -z 5s ${server.url}react-markdown`);

171
bench/snippets/markdown.mjs Normal file
View File

@@ -0,0 +1,171 @@
import { marked } from "marked";
import { remark } from "remark";
import remarkHtml from "remark-html";
import { bench, run, summary } from "../runner.mjs";
const remarkProcessor = remark().use(remarkHtml);
const small = `# Hello World
This is a **bold** and *italic* paragraph with a [link](https://example.com).
- Item 1
- Item 2
- Item 3
`;
const medium = `# Project README
## Introduction
This is a medium-sized markdown document that includes **bold text**, *italic text*,
and \`inline code\`. It also has [links](https://example.com) and various formatting.
## Features
- Feature one with **bold**
- Feature two with *emphasis*
- Feature three with \`code\`
- Feature four with [a link](https://example.com)
## Code Example
\`\`\`javascript
function hello() {
console.log("Hello, world!");
return 42;
}
const result = hello();
\`\`\`
## Table
| Name | Value | Description |
|------|-------|-------------|
| foo | 1 | First item |
| bar | 2 | Second item |
| baz | 3 | Third item |
## Blockquote
> This is a blockquote with **bold** and *italic* text.
> It spans multiple lines and contains a [link](https://example.com).
---
### Nested Lists
1. First ordered item
- Nested unordered
- Another nested
2. Second ordered item
1. Nested ordered
2. Another nested
3. Third ordered item
Some final paragraph with ~~strikethrough~~ text and more **formatting**.
`;
const large = medium.repeat(20);
const renderCallbacks = {
heading: (children, { level }) => `<h${level}>${children}</h${level}>`,
paragraph: children => `<p>${children}</p>`,
strong: children => `<strong>${children}</strong>`,
emphasis: children => `<em>${children}</em>`,
codespan: children => `<code>${children}</code>`,
code: (children, { language }) =>
language
? `<pre><code class="language-${language}">${children}</code></pre>`
: `<pre><code>${children}</code></pre>`,
link: (children, { href, title }) =>
title ? `<a href="${href}" title="${title}">${children}</a>` : `<a href="${href}">${children}</a>`,
image: (children, { src, title }) =>
title ? `<img src="${src}" alt="${children}" title="${title}" />` : `<img src="${src}" alt="${children}" />`,
list: (children, { ordered, start }) => (ordered ? `<ol start="${start}">${children}</ol>` : `<ul>${children}</ul>`),
listItem: children => `<li>${children}</li>`,
blockquote: children => `<blockquote>${children}</blockquote>`,
hr: () => `<hr />`,
strikethrough: children => `<del>${children}</del>`,
table: children => `<table>${children}</table>`,
thead: children => `<thead>${children}</thead>`,
tbody: children => `<tbody>${children}</tbody>`,
tr: children => `<tr>${children}</tr>`,
th: children => `<th>${children}</th>`,
td: children => `<td>${children}</td>`,
};
summary(() => {
if (typeof Bun !== "undefined" && Bun.markdown) {
bench(`small (${small.length} chars) - Bun.markdown.html`, () => {
return Bun.markdown.html(small);
});
bench(`small (${small.length} chars) - Bun.markdown.render`, () => {
return Bun.markdown.render(small, renderCallbacks);
});
bench(`small (${small.length} chars) - Bun.markdown.react`, () => {
return Bun.markdown.react(small);
});
}
bench(`small (${small.length} chars) - marked`, () => {
return marked(small);
});
bench(`small (${small.length} chars) - remark`, () => {
return remarkProcessor.processSync(small).toString();
});
});
summary(() => {
if (typeof Bun !== "undefined" && Bun.markdown) {
bench(`medium (${medium.length} chars) - Bun.markdown.html`, () => {
return Bun.markdown.html(medium);
});
bench(`medium (${medium.length} chars) - Bun.markdown.render`, () => {
return Bun.markdown.render(medium, renderCallbacks);
});
bench(`medium (${medium.length} chars) - Bun.markdown.react`, () => {
return Bun.markdown.react(medium);
});
}
bench(`medium (${medium.length} chars) - marked`, () => {
return marked(medium);
});
bench(`medium (${medium.length} chars) - remark`, () => {
return remarkProcessor.processSync(medium).toString();
});
});
summary(() => {
if (typeof Bun !== "undefined" && Bun.markdown) {
bench(`large (${large.length} chars) - Bun.markdown.html`, () => {
return Bun.markdown.html(large);
});
bench(`large (${large.length} chars) - Bun.markdown.render`, () => {
return Bun.markdown.render(large, renderCallbacks);
});
bench(`large (${large.length} chars) - Bun.markdown.react`, () => {
return Bun.markdown.react(large);
});
}
bench(`large (${large.length} chars) - marked`, () => {
return marked(large);
});
bench(`large (${large.length} chars) - remark`, () => {
return remarkProcessor.processSync(large).toString();
});
});
await run();

View File

@@ -0,0 +1,18 @@
import { posix, win32 } from "path";
import { bench, run } from "../runner.mjs";
const paths = ["/home/user/dir/file.txt", "/home/user/dir/", "file.txt", "/root", ""];
paths.forEach(p => {
bench(`posix.parse(${JSON.stringify(p)})`, () => {
globalThis.abc = posix.parse(p);
});
});
paths.forEach(p => {
bench(`win32.parse(${JSON.stringify(p)})`, () => {
globalThis.abc = win32.parse(p);
});
});
await run();

View File

@@ -0,0 +1,20 @@
// Benchmark for [...set] optimization (WebKit#56539)
// https://github.com/WebKit/WebKit/pull/56539
import { bench, run } from "../runner.mjs";
const intSet10 = new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
const intSet100 = new Set(Array.from({ length: 100 }, (_, i) => i));
const strSet10 = new Set(Array.from({ length: 10 }, (_, i) => `key-${i}`));
const strSet100 = new Set(Array.from({ length: 100 }, (_, i) => `key-${i}`));
const objSet10 = new Set(Array.from({ length: 10 }, (_, i) => ({ id: i })));
const objSet100 = new Set(Array.from({ length: 100 }, (_, i) => ({ id: i })));
bench("[...set] - integers (10)", () => [...intSet10]);
bench("[...set] - integers (100)", () => [...intSet100]);
bench("[...set] - strings (10)", () => [...strSet10]);
bench("[...set] - strings (100)", () => [...strSet100]);
bench("[...set] - objects (10)", () => [...objSet10]);
bench("[...set] - objects (100)", () => [...objSet100]);
await run();

View File

@@ -33,7 +33,30 @@ var testArray = [
import { bench, run } from "../runner.mjs";
bench("structuredClone(array)", () => structuredClone(testArray));
bench("structuredClone(nested array)", () => structuredClone(testArray));
bench("structuredClone(123)", () => structuredClone(123));
bench("structuredClone({a: 123})", () => structuredClone({ a: 123 }));
// Array fast path targets
var numbersSmall = Array.from({ length: 10 }, (_, i) => i);
var numbersMedium = Array.from({ length: 100 }, (_, i) => i);
var numbersLarge = Array.from({ length: 1000 }, (_, i) => i);
var stringsSmall = Array.from({ length: 10 }, (_, i) => `item-${i}`);
var stringsMedium = Array.from({ length: 100 }, (_, i) => `item-${i}`);
var mixed = [1, "hello", true, null, undefined, 3.14, "world", false, 42, "test"];
bench("structuredClone([10 numbers])", () => structuredClone(numbersSmall));
bench("structuredClone([100 numbers])", () => structuredClone(numbersMedium));
bench("structuredClone([1000 numbers])", () => structuredClone(numbersLarge));
bench("structuredClone([10 strings])", () => structuredClone(stringsSmall));
bench("structuredClone([100 strings])", () => structuredClone(stringsMedium));
bench("structuredClone([10 mixed])", () => structuredClone(mixed));
// Array of objects (DenseArray fast path target)
var objectsSmall = Array.from({ length: 10 }, (_, i) => ({ id: i, name: `item-${i}`, active: true }));
var objectsMedium = Array.from({ length: 100 }, (_, i) => ({ id: i, name: `item-${i}`, active: true }));
bench("structuredClone([10 objects])", () => structuredClone(objectsSmall));
bench("structuredClone([100 objects])", () => structuredClone(objectsMedium));
await run();

View File

@@ -13,10 +13,7 @@
},
{
"output": "JavaScriptSources.txt",
"paths": [
"src/js/**/*.{js,ts}",
"src/install/PackageManager/scanner-entry.ts"
]
"paths": ["src/js/**/*.{js,ts}", "src/install/PackageManager/scanner-entry.ts"]
},
{
"output": "JavaScriptCodegenSources.txt",

View File

@@ -7,6 +7,13 @@ register_repository(
4f4f5ef8ebc6e23cbf393428f0ab1b526773f7ac
)
set(BORINGSSL_CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF)
# Disable ASM on Windows ARM64 to avoid mixing non-ARM object files into ARM64 libs
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64|AARCH64")
list(APPEND BORINGSSL_CMAKE_ARGS -DOPENSSL_NO_ASM=1)
endif()
register_cmake_command(
TARGET
boringssl
@@ -15,7 +22,7 @@ register_cmake_command(
ssl
decrepit
ARGS
-DBUILD_SHARED_LIBS=OFF
${BORINGSSL_CMAKE_ARGS}
INCLUDES
include
)

View File

@@ -939,7 +939,7 @@ if(WIN32)
endif()
if(USE_MIMALLOC_AS_DEFAULT_ALLOCATOR)
target_compile_definitions(${bun} PRIVATE USE_MIMALLOC=1)
target_compile_definitions(${bun} PRIVATE USE_BUN_MIMALLOC=1)
endif()
target_compile_definitions(${bun} PRIVATE
@@ -1016,6 +1016,7 @@ if(NOT WIN32)
-Wno-unused-function
-Wno-c++23-lambda-attributes
-Wno-nullability-completeness
-Wno-character-conversion
-Werror
)
else()
@@ -1033,6 +1034,7 @@ if(NOT WIN32)
-Werror=sometimes-uninitialized
-Wno-c++23-lambda-attributes
-Wno-nullability-completeness
-Wno-character-conversion
-Werror
)
@@ -1061,6 +1063,7 @@ else()
-Wno-inconsistent-dllimport
-Wno-incompatible-pointer-types
-Wno-deprecated-declarations
-Wno-character-conversion
)
endif()
@@ -1136,6 +1139,15 @@ if(LINUX)
-Wl,--wrap=pow
-Wl,--wrap=powf
)
# Disable LTO for workaround-missing-symbols.cpp to prevent LLD 21 from emitting
# glibc versioned symbol names (e.g. exp@GLIBC_2.17) from .symver directives into
# the .lto_discard assembler directive, which fails to parse the '@' character.
if(ENABLE_LTO)
set_source_files_properties(${CWD}/src/bun.js/bindings/workaround-missing-symbols.cpp
PROPERTIES COMPILE_OPTIONS "-fno-lto"
)
endif()
endif()
if(NOT ABI STREQUAL "musl")
@@ -1253,6 +1265,7 @@ if(WIN32)
target_link_libraries(${bun} PRIVATE
${WEBKIT_LIB_PATH}/WTF.lib
${WEBKIT_LIB_PATH}/JavaScriptCore.lib
${WEBKIT_LIB_PATH}/bmalloc.lib
${WEBKIT_LIB_PATH}/sicudtd.lib
${WEBKIT_LIB_PATH}/sicuind.lib
${WEBKIT_LIB_PATH}/sicuucd.lib
@@ -1261,6 +1274,7 @@ if(WIN32)
target_link_libraries(${bun} PRIVATE
${WEBKIT_LIB_PATH}/WTF.lib
${WEBKIT_LIB_PATH}/JavaScriptCore.lib
${WEBKIT_LIB_PATH}/bmalloc.lib
${WEBKIT_LIB_PATH}/sicudt.lib
${WEBKIT_LIB_PATH}/sicuin.lib
${WEBKIT_LIB_PATH}/sicuuc.lib
@@ -1271,13 +1285,18 @@ else()
${WEBKIT_LIB_PATH}/libWTF.a
${WEBKIT_LIB_PATH}/libJavaScriptCore.a
)
if(NOT APPLE OR EXISTS ${WEBKIT_LIB_PATH}/libbmalloc.a)
if(WEBKIT_LOCAL OR NOT APPLE OR EXISTS ${WEBKIT_LIB_PATH}/libbmalloc.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libbmalloc.a)
endif()
endif()
include_directories(${WEBKIT_INCLUDE_PATH})
# When building with a local WebKit, ensure JSC is built before compiling Bun's C++ sources.
if(WEBKIT_LOCAL AND TARGET jsc)
add_dependencies(${bun} jsc)
endif()
# Include the generated dependency versions header
include_directories(${CMAKE_BINARY_DIR})
@@ -1322,9 +1341,14 @@ if(LINUX)
target_link_libraries(${bun} PUBLIC libatomic.so)
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)
if(WEBKIT_LOCAL)
find_package(ICU REQUIRED COMPONENTS data i18n uc)
target_link_libraries(${bun} PRIVATE ICU::data ICU::i18n ICU::uc)
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()
endif()
if(WIN32)
@@ -1433,6 +1457,8 @@ if(NOT BUN_CPP_ONLY)
# ==856230==See https://github.com/google/sanitizers/issues/856 for possible workarounds.
# the linked issue refers to very old kernels but this still happens to us on modern ones.
# disabling ASLR to run the binary works around it
# Skip post-build test/features when cross-compiling (can't run the target binary on the host)
if(NOT CMAKE_CROSSCOMPILING)
set(TEST_BUN_COMMAND_BASE ${BUILD_PATH}/${bunExe} --revision)
set(TEST_BUN_COMMAND_ENV_WRAP
${CMAKE_COMMAND} -E env BUN_DEBUG_QUIET_LOGS=1)
@@ -1481,6 +1507,7 @@ if(NOT BUN_CPP_ONLY)
${BUILD_PATH}/features.json
)
endif()
endif() # NOT CMAKE_CROSSCOMPILING
if(CMAKE_HOST_APPLE AND bunStrip)
register_command(
@@ -1527,7 +1554,10 @@ if(NOT BUN_CPP_ONLY)
string(REPLACE bun ${bunTriplet} bunPath ${bun})
endif()
set(bunFiles ${bunExe} features.json)
set(bunFiles ${bunExe})
if(NOT CMAKE_CROSSCOMPILING)
list(APPEND bunFiles features.json)
endif()
if(WIN32)
list(APPEND bunFiles ${bun}.pdb)
elseif(APPLE)

View File

@@ -4,7 +4,7 @@ register_repository(
REPOSITORY
cloudflare/lol-html
COMMIT
d64457d9ff0143deef025d5df7e8586092b9afb7
e9e16dca48dd4a8ffbc77642bc4be60407585f11
)
set(LOLHTML_CWD ${VENDOR_PATH}/lolhtml/c-api)
@@ -26,6 +26,12 @@ if(RELEASE)
list(APPEND LOLHTML_BUILD_ARGS --release)
endif()
# Cross-compilation: tell cargo to target ARM64
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64|AARCH64")
list(APPEND LOLHTML_BUILD_ARGS --target aarch64-pc-windows-msvc)
set(LOLHTML_LIBRARY ${LOLHTML_BUILD_PATH}/aarch64-pc-windows-msvc/${LOLHTML_BUILD_TYPE}/${CMAKE_STATIC_LIBRARY_PREFIX}lolhtml${CMAKE_STATIC_LIBRARY_SUFFIX})
endif()
# Windows requires unwind tables, apparently.
if (NOT WIN32)
# The encoded escape sequences are intentional. They're how you delimit multiple arguments in a single environment variable.
@@ -51,11 +57,18 @@ if(WIN32)
if(MSVC_VERSIONS)
list(GET MSVC_VERSIONS -1 MSVC_LATEST) # Get the latest version
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64")
set(MSVC_LINK_PATH "${MSVC_LATEST}/bin/HostARM64/arm64/link.exe")
# Use Hostx64/arm64 for cross-compilation from x64, fall back to native
if(EXISTS "${MSVC_LATEST}/bin/Hostx64/arm64/link.exe")
set(MSVC_LINK_PATH "${MSVC_LATEST}/bin/Hostx64/arm64/link.exe")
else()
set(MSVC_LINK_PATH "${MSVC_LATEST}/bin/HostARM64/arm64/link.exe")
endif()
set(CARGO_LINKER_VAR "CARGO_TARGET_AARCH64_PC_WINDOWS_MSVC_LINKER")
set(MSVC_LIB_ARCH "arm64")
else()
set(MSVC_LINK_PATH "${MSVC_LATEST}/bin/Hostx64/x64/link.exe")
set(CARGO_LINKER_VAR "CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER")
set(MSVC_LIB_ARCH "x64")
endif()
if(EXISTS "${MSVC_LINK_PATH}")
list(APPEND LOLHTML_ENV "${CARGO_LINKER_VAR}=${MSVC_LINK_PATH}")

View File

@@ -4,7 +4,7 @@ register_repository(
REPOSITORY
oven-sh/mimalloc
COMMIT
989115cefb6915baa13788cb8252d83aac5330ad
1beadf9651a7bfdec6b5367c380ecc3fe1c40d1a
)
set(MIMALLOC_CMAKE_ARGS
@@ -14,7 +14,7 @@ set(MIMALLOC_CMAKE_ARGS
-DMI_BUILD_TESTS=OFF
-DMI_USE_CXX=ON
-DMI_SKIP_COLLECT_ON_EXIT=ON
# ```
# mimalloc_allow_large_os_pages=0 BUN_PORT=3004 mem bun http-hello.js
# Started development server: http://localhost:3004
@@ -51,7 +51,7 @@ if(ENABLE_ASAN)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_DEBUG_UBSAN=ON)
elseif(APPLE OR LINUX)
if(APPLE)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OVERRIDE=OFF)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OVERRIDE=OFF)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OSX_ZONE=OFF)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OSX_INTERPOSE=OFF)
else()
@@ -69,17 +69,27 @@ if(ENABLE_VALGRIND)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_VALGRIND=ON)
endif()
# Enable SIMD optimizations when not building for baseline (older CPUs)
if(NOT ENABLE_BASELINE)
# Enable architecture-specific optimizations when not building for baseline.
# On Linux aarch64, upstream mimalloc force-enables MI_OPT_ARCH which adds
# -march=armv8.1-a (LSE atomics). This crashes on ARMv8.0 CPUs
# (Cortex-A53, Raspberry Pi 4, AWS a1 instances). Use MI_NO_OPT_ARCH
# to prevent that, but keep SIMD enabled. -moutline-atomics for runtime
# dispatch to LSE/LL-SC. macOS arm64 always has LSE (Apple Silicon) so
# MI_OPT_ARCH is safe there.
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64|AARCH64" AND NOT APPLE)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_NO_OPT_ARCH=ON)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OPT_SIMD=ON)
list(APPEND MIMALLOC_CMAKE_ARGS "-DCMAKE_C_FLAGS=-moutline-atomics")
elseif(NOT ENABLE_BASELINE)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OPT_ARCH=ON)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OPT_SIMD=ON)
endif()
if(WIN32)
if(DEBUG)
set(MIMALLOC_LIBRARY mimalloc-debug)
set(MIMALLOC_LIBRARY mimalloc-static-debug)
else()
set(MIMALLOC_LIBRARY mimalloc)
set(MIMALLOC_LIBRARY mimalloc-static)
endif()
elseif(DEBUG)
if (ENABLE_ASAN)

View File

@@ -3,18 +3,35 @@ set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER_WORKS ON)
set(CMAKE_CXX_COMPILER_WORKS ON)
set(CMAKE_CROSSCOMPILING ON)
# Force ARM64 architecture ID - this is what CMake uses to determine /machine: flag
set(MSVC_C_ARCHITECTURE_ID ARM64 CACHE INTERNAL "")
set(MSVC_CXX_ARCHITECTURE_ID ARM64 CACHE INTERNAL "")
# The rest only applies when building on Windows (C++ and link steps).
# The Zig step runs on Linux and only needs CMAKE_SYSTEM_NAME/PROCESSOR above.
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
# CMake 4.0+ policy CMP0197 controls how MSVC machine type flags are handled
set(CMAKE_POLICY_DEFAULT_CMP0197 NEW CACHE INTERNAL "")
# Ensure clang/clang-cl targets Windows ARM64 (otherwise ARM64-specific flags like
# -march=armv8-a are rejected as x86-only).
set(CMAKE_C_COMPILER_TARGET aarch64-pc-windows-msvc CACHE STRING "" FORCE)
set(CMAKE_CXX_COMPILER_TARGET aarch64-pc-windows-msvc CACHE STRING "" FORCE)
# Clear any inherited static linker flags that might have wrong machine types
set(CMAKE_STATIC_LINKER_FLAGS "" CACHE STRING "" FORCE)
# ARM64 has lock-free atomics (highway's FindAtomics check can't run ARM64 test binary on x64)
set(ATOMICS_LOCK_FREE_INSTRUCTIONS TRUE CACHE BOOL "" FORCE)
set(HAVE_CXX_ATOMICS_WITHOUT_LIB TRUE CACHE BOOL "" FORCE)
set(HAVE_CXX_ATOMICS64_WITHOUT_LIB TRUE CACHE BOOL "" FORCE)
# Use wrapper script for llvm-lib that strips /machine:x64 flags
# This works around CMake 4.1.0 bug where both ARM64 and x64 machine flags are added
get_filename_component(_TOOLCHAIN_DIR "${CMAKE_CURRENT_LIST_DIR}" DIRECTORY)
set(CMAKE_AR "${_TOOLCHAIN_DIR}/scripts/llvm-lib-wrapper.bat" CACHE FILEPATH "" FORCE)
# Force ARM64 architecture ID - this is what CMake uses to determine /machine: flag
set(MSVC_C_ARCHITECTURE_ID ARM64 CACHE INTERNAL "")
set(MSVC_CXX_ARCHITECTURE_ID ARM64 CACHE INTERNAL "")
# CMake 4.0+ policy CMP0197 controls how MSVC machine type flags are handled
set(CMAKE_POLICY_DEFAULT_CMP0197 NEW CACHE INTERNAL "")
# Clear any inherited static linker flags that might have wrong machine types
set(CMAKE_STATIC_LINKER_FLAGS "" CACHE STRING "" FORCE)
# Use wrapper script for llvm-lib that strips /machine:x64 flags
# This works around CMake 4.1.0 bug where both ARM64 and x64 machine flags are added
get_filename_component(_TOOLCHAIN_DIR "${CMAKE_CURRENT_LIST_DIR}" DIRECTORY)
set(CMAKE_AR "${_TOOLCHAIN_DIR}/scripts/llvm-lib-wrapper.bat" CACHE FILEPATH "" FORCE)
endif()

View File

@@ -6,7 +6,8 @@ endif()
optionx(BUILDKITE_ORGANIZATION_SLUG STRING "The organization slug to use on Buildkite" DEFAULT "bun")
optionx(BUILDKITE_PIPELINE_SLUG STRING "The pipeline slug to use on Buildkite" DEFAULT "bun")
optionx(BUILDKITE_BUILD_ID STRING "The build ID to use on Buildkite")
optionx(BUILDKITE_BUILD_ID STRING "The build ID (UUID) to use on Buildkite")
optionx(BUILDKITE_BUILD_NUMBER STRING "The build number to use on Buildkite")
optionx(BUILDKITE_GROUP_ID STRING "The group ID to use on Buildkite")
if(ENABLE_BASELINE)
@@ -32,7 +33,13 @@ if(NOT BUILDKITE_BUILD_ID)
return()
endif()
setx(BUILDKITE_BUILD_URL https://buildkite.com/${BUILDKITE_ORGANIZATION_SLUG}/${BUILDKITE_PIPELINE_SLUG}/builds/${BUILDKITE_BUILD_ID})
# Use BUILDKITE_BUILD_NUMBER for the URL if available, as the UUID format causes a 302 redirect
# that CMake's file(DOWNLOAD) doesn't follow, resulting in empty response.
if(BUILDKITE_BUILD_NUMBER)
setx(BUILDKITE_BUILD_URL https://buildkite.com/${BUILDKITE_ORGANIZATION_SLUG}/${BUILDKITE_PIPELINE_SLUG}/builds/${BUILDKITE_BUILD_NUMBER})
else()
setx(BUILDKITE_BUILD_URL https://buildkite.com/${BUILDKITE_ORGANIZATION_SLUG}/${BUILDKITE_PIPELINE_SLUG}/builds/${BUILDKITE_BUILD_ID})
endif()
setx(BUILDKITE_BUILD_PATH ${BUILDKITE_BUILDS_PATH}/builds/${BUILDKITE_BUILD_ID})
file(

View File

@@ -12,13 +12,7 @@ if(NOT ENABLE_LLVM)
return()
endif()
# LLVM 21 is required for Windows ARM64 (first version with ARM64 Windows builds)
# Other platforms use LLVM 19.1.7
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64|AARCH64")
set(DEFAULT_LLVM_VERSION "21.1.8")
else()
set(DEFAULT_LLVM_VERSION "19.1.7")
endif()
set(DEFAULT_LLVM_VERSION "21.1.8")
optionx(LLVM_VERSION STRING "The version of LLVM to use" DEFAULT ${DEFAULT_LLVM_VERSION})
@@ -27,6 +21,8 @@ if(USE_LLVM_VERSION)
set(LLVM_VERSION_MAJOR ${CMAKE_MATCH_1})
set(LLVM_VERSION_MINOR ${CMAKE_MATCH_2})
set(LLVM_VERSION_PATCH ${CMAKE_MATCH_3})
# Accept any LLVM version within the same major.minor range (e.g. Alpine 3.23 ships 21.1.2)
set(LLVM_VERSION_RANGE ">=${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.0 <${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.99")
endif()
set(LLVM_PATHS)
@@ -54,6 +50,11 @@ if(APPLE)
list(APPEND LLVM_PATHS ${HOMEBREW_PREFIX}/opt/llvm/bin)
endif()
if(WIN32)
# Prefer standalone LLVM over VS-bundled (standalone supports cross-compilation)
list(APPEND LLVM_PATHS "C:/Program Files/LLVM/bin")
endif()
if(UNIX)
list(APPEND LLVM_PATHS /usr/lib/llvm/bin)
@@ -78,14 +79,12 @@ macro(find_llvm_command variable command)
)
endif()
math(EXPR LLVM_VERSION_NEXT_MAJOR "${LLVM_VERSION_MAJOR} + 1")
find_command(
VARIABLE ${variable}
VERSION_VARIABLE LLVM_VERSION
COMMAND ${commands}
PATHS ${LLVM_PATHS}
VERSION ">=${LLVM_VERSION_MAJOR}.1.0 <${LLVM_VERSION_NEXT_MAJOR}.0.0"
VERSION "${LLVM_VERSION_RANGE}"
)
list(APPEND CMAKE_ARGS -D${variable}=${${variable}})
endmacro()

View File

@@ -31,13 +31,6 @@ execute_process(
ERROR_QUIET
)
if(MACOS_VERSION VERSION_LESS ${CMAKE_OSX_DEPLOYMENT_TARGET})
message(FATAL_ERROR "Your computer is running macOS ${MACOS_VERSION}, which is older than the target macOS SDK ${CMAKE_OSX_DEPLOYMENT_TARGET}. To fix this, either:\n"
" - Upgrade your computer to macOS ${CMAKE_OSX_DEPLOYMENT_TARGET} or newer\n"
" - Download a newer version of the macOS SDK from Apple: https://developer.apple.com/download/all/?q=xcode\n"
" - Set -DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOS_VERSION}\n")
endif()
execute_process(
COMMAND xcrun --sdk macosx --show-sdk-path
OUTPUT_VARIABLE DEFAULT_CMAKE_OSX_SYSROOT

View File

@@ -1,8 +1,12 @@
# NOTE: Changes to this file trigger QEMU JIT stress tests in CI.
# See scripts/verify-jit-stress-qemu.sh for details.
option(WEBKIT_VERSION "The version of WebKit to use")
option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading")
option(WEBKIT_BUILD_TYPE "The build type for local WebKit (defaults to CMAKE_BUILD_TYPE)")
if(NOT WEBKIT_VERSION)
set(WEBKIT_VERSION daf95b4b4574799ff22c8c4effd0dc6e864968a5)
set(WEBKIT_VERSION 8af7958ff0e2a4787569edf64641a1ae7cfe074a)
endif()
# Use preview build URL for Windows ARM64 until the fix is merged to main
@@ -12,7 +16,10 @@ string(SUBSTRING ${WEBKIT_VERSION} 0 16 WEBKIT_VERSION_PREFIX)
string(SUBSTRING ${WEBKIT_VERSION} 0 8 WEBKIT_VERSION_SHORT)
if(WEBKIT_LOCAL)
set(DEFAULT_WEBKIT_PATH ${VENDOR_PATH}/WebKit/WebKitBuild/${CMAKE_BUILD_TYPE})
if(NOT WEBKIT_BUILD_TYPE)
set(WEBKIT_BUILD_TYPE ${CMAKE_BUILD_TYPE})
endif()
set(DEFAULT_WEBKIT_PATH ${VENDOR_PATH}/WebKit/WebKitBuild/${WEBKIT_BUILD_TYPE})
else()
set(DEFAULT_WEBKIT_PATH ${CACHE_PATH}/webkit-${WEBKIT_VERSION_PREFIX})
endif()
@@ -27,35 +34,153 @@ set(WEBKIT_INCLUDE_PATH ${WEBKIT_PATH}/include)
set(WEBKIT_LIB_PATH ${WEBKIT_PATH}/lib)
if(WEBKIT_LOCAL)
if(EXISTS ${WEBKIT_PATH}/cmakeconfig.h)
# You may need to run:
# make jsc-compile-debug jsc-copy-headers
include_directories(
${WEBKIT_PATH}
${WEBKIT_PATH}/JavaScriptCore/Headers
${WEBKIT_PATH}/JavaScriptCore/Headers/JavaScriptCore
${WEBKIT_PATH}/JavaScriptCore/PrivateHeaders
${WEBKIT_PATH}/bmalloc/Headers
${WEBKIT_PATH}/WTF/Headers
${WEBKIT_PATH}/JavaScriptCore/PrivateHeaders/JavaScriptCore
${WEBKIT_PATH}/JavaScriptCore/DerivedSources/inspector
)
set(WEBKIT_SOURCE_DIR ${VENDOR_PATH}/WebKit)
# On Windows, add ICU include path from vcpkg
if(WIN32)
# Auto-detect vcpkg triplet
set(VCPKG_ARM64_PATH ${VENDOR_PATH}/WebKit/vcpkg_installed/arm64-windows-static)
set(VCPKG_X64_PATH ${VENDOR_PATH}/WebKit/vcpkg_installed/x64-windows-static)
if(EXISTS ${VCPKG_ARM64_PATH})
set(VCPKG_ICU_PATH ${VCPKG_ARM64_PATH})
if(WIN32)
# --- Build ICU from source (Windows only) ---
# On macOS, ICU is found automatically (Homebrew icu4c for headers, system for libs).
# On Linux, ICU is found automatically from system packages (e.g. libicu-dev).
# On Windows, there is no system ICU, so we build it from source.
set(ICU_LOCAL_ROOT ${VENDOR_PATH}/WebKit/WebKitBuild/icu)
if(NOT EXISTS ${ICU_LOCAL_ROOT}/lib/sicudt.lib)
message(STATUS "Building ICU from source...")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|ARM64|aarch64|AARCH64")
set(ICU_PLATFORM "ARM64")
else()
set(VCPKG_ICU_PATH ${VCPKG_X64_PATH})
set(ICU_PLATFORM "x64")
endif()
if(EXISTS ${VCPKG_ICU_PATH}/include)
include_directories(${VCPKG_ICU_PATH}/include)
message(STATUS "Using ICU from vcpkg: ${VCPKG_ICU_PATH}/include")
execute_process(
COMMAND powershell -ExecutionPolicy Bypass -File
${WEBKIT_SOURCE_DIR}/build-icu.ps1
-Platform ${ICU_PLATFORM}
-BuildType ${WEBKIT_BUILD_TYPE}
-OutputDir ${ICU_LOCAL_ROOT}
RESULT_VARIABLE ICU_BUILD_RESULT
)
if(NOT ICU_BUILD_RESULT EQUAL 0)
message(FATAL_ERROR "Failed to build ICU (exit code: ${ICU_BUILD_RESULT}).")
endif()
endif()
# Copy ICU libs to WEBKIT_LIB_PATH with the names BuildBun.cmake expects.
# Prebuilt WebKit uses 's' prefix (static) and 'd' suffix (debug).
file(MAKE_DIRECTORY ${WEBKIT_LIB_PATH})
if(WEBKIT_BUILD_TYPE STREQUAL "Debug")
set(ICU_SUFFIX "d")
else()
set(ICU_SUFFIX "")
endif()
file(COPY_FILE ${ICU_LOCAL_ROOT}/lib/sicudt.lib ${WEBKIT_LIB_PATH}/sicudt${ICU_SUFFIX}.lib ONLY_IF_DIFFERENT)
file(COPY_FILE ${ICU_LOCAL_ROOT}/lib/icuin.lib ${WEBKIT_LIB_PATH}/sicuin${ICU_SUFFIX}.lib ONLY_IF_DIFFERENT)
file(COPY_FILE ${ICU_LOCAL_ROOT}/lib/icuuc.lib ${WEBKIT_LIB_PATH}/sicuuc${ICU_SUFFIX}.lib ONLY_IF_DIFFERENT)
endif()
# --- Configure JSC ---
message(STATUS "Configuring JSC from local WebKit source at ${WEBKIT_SOURCE_DIR}...")
set(JSC_CMAKE_ARGS
-S ${WEBKIT_SOURCE_DIR}
-B ${WEBKIT_PATH}
-G ${CMAKE_GENERATOR}
-DPORT=JSCOnly
-DENABLE_STATIC_JSC=ON
-DUSE_THIN_ARCHIVES=OFF
-DENABLE_FTL_JIT=ON
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DUSE_BUN_JSC_ADDITIONS=ON
-DUSE_BUN_EVENT_LOOP=ON
-DENABLE_BUN_SKIP_FAILING_ASSERTIONS=ON
-DALLOW_LINE_AND_COLUMN_NUMBER_IN_BUILTINS=ON
-DCMAKE_BUILD_TYPE=${WEBKIT_BUILD_TYPE}
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DENABLE_REMOTE_INSPECTOR=ON
)
if(WIN32)
# ICU paths and Windows-specific compiler/linker settings
list(APPEND JSC_CMAKE_ARGS
-DICU_ROOT=${ICU_LOCAL_ROOT}
-DICU_LIBRARY=${ICU_LOCAL_ROOT}/lib
-DICU_INCLUDE_DIR=${ICU_LOCAL_ROOT}/include
-DCMAKE_LINKER=lld-link
)
# Static CRT and U_STATIC_IMPLEMENTATION
if(WEBKIT_BUILD_TYPE STREQUAL "Debug")
set(JSC_MSVC_RUNTIME "MultiThreadedDebug")
else()
set(JSC_MSVC_RUNTIME "MultiThreaded")
endif()
list(APPEND JSC_CMAKE_ARGS
-DCMAKE_MSVC_RUNTIME_LIBRARY=${JSC_MSVC_RUNTIME}
"-DCMAKE_C_FLAGS=/DU_STATIC_IMPLEMENTATION"
"-DCMAKE_CXX_FLAGS=/DU_STATIC_IMPLEMENTATION /clang:-fno-c++-static-destructors"
)
endif()
if(ENABLE_ASAN)
list(APPEND JSC_CMAKE_ARGS -DENABLE_SANITIZERS=address)
endif()
# Pass through ccache if available
if(CMAKE_C_COMPILER_LAUNCHER)
list(APPEND JSC_CMAKE_ARGS -DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER})
endif()
if(CMAKE_CXX_COMPILER_LAUNCHER)
list(APPEND JSC_CMAKE_ARGS -DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER})
endif()
execute_process(
COMMAND ${CMAKE_COMMAND} ${JSC_CMAKE_ARGS}
RESULT_VARIABLE JSC_CONFIGURE_RESULT
)
if(NOT JSC_CONFIGURE_RESULT EQUAL 0)
message(FATAL_ERROR "Failed to configure JSC (exit code: ${JSC_CONFIGURE_RESULT}). "
"Check the output above for errors.")
endif()
if(WIN32)
set(JSC_BYPRODUCTS
${WEBKIT_LIB_PATH}/JavaScriptCore.lib
${WEBKIT_LIB_PATH}/WTF.lib
${WEBKIT_LIB_PATH}/bmalloc.lib
)
else()
set(JSC_BYPRODUCTS
${WEBKIT_LIB_PATH}/libJavaScriptCore.a
${WEBKIT_LIB_PATH}/libWTF.a
${WEBKIT_LIB_PATH}/libbmalloc.a
)
endif()
if(WIN32)
add_custom_target(jsc ALL
COMMAND ${CMAKE_COMMAND} --build ${WEBKIT_PATH} --config ${WEBKIT_BUILD_TYPE} --target jsc
BYPRODUCTS ${JSC_BYPRODUCTS}
COMMENT "Building JSC (${WEBKIT_PATH})"
)
else()
add_custom_target(jsc ALL
COMMAND ${CMAKE_COMMAND} --build ${WEBKIT_PATH} --config ${WEBKIT_BUILD_TYPE} --target jsc
BYPRODUCTS ${JSC_BYPRODUCTS}
COMMENT "Building JSC (${WEBKIT_PATH})"
USES_TERMINAL
)
endif()
include_directories(
${WEBKIT_PATH}
${WEBKIT_PATH}/JavaScriptCore/Headers
${WEBKIT_PATH}/JavaScriptCore/Headers/JavaScriptCore
${WEBKIT_PATH}/JavaScriptCore/PrivateHeaders
${WEBKIT_PATH}/bmalloc/Headers
${WEBKIT_PATH}/WTF/Headers
${WEBKIT_PATH}/JavaScriptCore/PrivateHeaders/JavaScriptCore
)
# On Windows, add ICU headers from the local ICU build
if(WIN32)
include_directories(${ICU_LOCAL_ROOT}/include)
endif()
# After this point, only prebuilt WebKit is supported

View File

@@ -20,12 +20,7 @@
"completionType": "javascript_files"
}
],
"examples": [
"bun run ./index.js",
"bun run ./index.tsx",
"bun run dev",
"bun run lint"
],
"examples": ["bun run ./index.js", "bun run ./index.tsx", "bun run dev", "bun run lint"],
"usage": "Usage: bun run [flags] <file or script>",
"documentationUrl": "https://bun.com/docs/cli/run",
"dynamicCompletions": {
@@ -63,6 +58,14 @@
"required": false,
"multiple": false
},
{
"name": "retry",
"description": "Default retry count for all tests, overridden by per-test { retry: N }",
"hasValue": true,
"valueType": "val",
"required": false,
"multiple": false
},
{
"name": "only",
"description": "Only run tests that are marked with \"test.only()\"",
@@ -152,11 +155,7 @@
"completionType": "test_files"
}
],
"examples": [
"bun test",
"bun test foo bar",
"bun test --test-name-pattern baz"
],
"examples": ["bun test", "bun test foo bar", "bun test --test-name-pattern baz"],
"usage": "Usage: bun test [flags] [<patterns>]",
"documentationUrl": "https://bun.com/docs/cli/test",
"dynamicCompletions": {
@@ -199,9 +198,7 @@
"examples": [],
"usage": "Usage: bunx [flags] <package><@version> [flags and arguments for the package]",
"dynamicCompletions": {},
"aliases": [
"bunx"
]
"aliases": ["bunx"]
},
"repl": {
"name": "repl",
@@ -232,10 +229,7 @@
"completionType": "script"
}
],
"examples": [
"bun exec \"echo hi\"",
"bun exec \"echo \\\"hey friends\\\"!\""
],
"examples": ["bun exec \"echo hi\"", "bun exec \"echo \\\"hey friends\\\"!\""],
"usage": "Usage: bun exec <script>",
"dynamicCompletions": {}
},
@@ -545,14 +539,9 @@
"type": "string"
}
],
"examples": [
"bun install",
"bun install --production"
],
"examples": ["bun install", "bun install --production"],
"usage": "Usage: bun install [flags] <name>@<version>",
"aliases": [
"i"
],
"aliases": ["i"],
"documentationUrl": "https://bun.com/docs/cli/install.",
"dynamicCompletions": {}
},
@@ -864,9 +853,7 @@
"bun add --peer esbuild"
],
"usage": "Usage: bun add [flags] <package><@version>",
"aliases": [
"a"
],
"aliases": ["a"],
"documentationUrl": "https://bun.com/docs/cli/add.",
"dynamicCompletions": {
"packages": true
@@ -1126,13 +1113,9 @@
"completionType": "installed_package"
}
],
"examples": [
"bun remove ts-node"
],
"examples": ["bun remove ts-node"],
"usage": "Usage: bun remove [flags] [<packages>]",
"aliases": [
"rm"
],
"aliases": ["rm"],
"documentationUrl": "https://bun.com/docs/cli/remove.",
"dynamicCompletions": {
"packages": true
@@ -1422,12 +1405,7 @@
"type": "string"
}
],
"examples": [
"bun update",
"bun update --latest",
"bun update -i",
"bun update zod jquery@3"
],
"examples": ["bun update", "bun update --latest", "bun update -i", "bun update zod jquery@3"],
"usage": "Usage: bun update [flags] <name>@<version>",
"documentationUrl": "https://bun.com/docs/cli/update.",
"dynamicCompletions": {}
@@ -1452,10 +1430,7 @@
"type": "string"
}
],
"examples": [
"bun audit",
"bun audit --json"
],
"examples": ["bun audit", "bun audit --json"],
"usage": "Usage: bun audit [flags]",
"documentationUrl": "https://bun.com/docs/install/audit.",
"dynamicCompletions": {}
@@ -1997,10 +1972,7 @@
"completionType": "package"
}
],
"examples": [
"bun link",
"bun link <package>"
],
"examples": ["bun link", "bun link <package>"],
"usage": "Usage: bun link [flags] [<packages>]",
"documentationUrl": "https://bun.com/docs/cli/link.",
"dynamicCompletions": {}
@@ -2252,9 +2224,7 @@
"type": "string"
}
],
"examples": [
"bun unlink"
],
"examples": ["bun unlink"],
"usage": "Usage: bun unlink [flags]",
"documentationUrl": "https://bun.com/docs/cli/unlink.",
"dynamicCompletions": {}
@@ -3248,11 +3218,7 @@
"completionType": "package"
}
],
"examples": [
"bun info react",
"bun info react@18.0.0",
"bun info react version --json"
],
"examples": ["bun info react", "bun info react@18.0.0", "bun info react version --json"],
"usage": "Usage: bun info [flags] <package>[@<version>]",
"documentationUrl": "https://bun.com/docs/cli/info.",
"dynamicCompletions": {}
@@ -3603,12 +3569,7 @@
"type": "string"
}
],
"examples": [
"bun init",
"bun init --yes",
"bun init --react",
"bun init --react=tailwind my-app"
],
"examples": ["bun init", "bun init --yes", "bun init --react", "bun init --react=tailwind my-app"],
"usage": "Usage: bun init [flags] [<folder>]",
"dynamicCompletions": {}
},
@@ -3621,9 +3582,7 @@
"usage": "Usage:",
"documentationUrl": "https://bun.com/docs/cli/bun-create",
"dynamicCompletions": {},
"aliases": [
"c"
]
"aliases": ["c"]
},
"upgrade": {
"name": "upgrade",
@@ -3637,10 +3596,7 @@
"type": "string"
}
],
"examples": [
"bun upgrade",
"bun upgrade --stable"
],
"examples": ["bun upgrade", "bun upgrade --stable"],
"usage": "Usage: bun upgrade [flags]",
"documentationUrl": "https://bun.com/docs/installation#upgrading",
"dynamicCompletions": {}
@@ -3743,9 +3699,7 @@
"description": "Configure auto-install behavior. One of \"auto\" (default, auto-installs when no node_modules), \"fallback\" (missing packages only), \"force\" (always).",
"hasValue": true,
"valueType": "val",
"choices": [
"auto"
],
"choices": ["auto"],
"required": false,
"multiple": false
},
@@ -3827,12 +3781,7 @@
"description": "Set the default order of DNS lookup results. Valid orders: verbatim (default), ipv4first, ipv6first",
"hasValue": true,
"valueType": "val",
"choices": [
"verbatim",
"(default)",
"ipv4first",
"ipv6first"
],
"choices": ["verbatim", "(default)", "ipv4first", "ipv6first"],
"required": false,
"multiple": false
},
@@ -3898,9 +3847,7 @@
"description": "One of \"strict\", \"throw\", \"warn\", \"none\", or \"warn-with-error-code\"",
"hasValue": true,
"valueType": "val",
"choices": [
"strict"
],
"choices": ["strict"],
"required": false,
"multiple": false
},
@@ -4023,4 +3970,4 @@
"files": "bun getcompletes j"
}
}
}
}

View File

@@ -665,6 +665,7 @@ _bun_test_completion() {
'--timeout[Set the per-test timeout in milliseconds, default is 5000.]:timeout' \
'--update-snapshots[Update snapshot files]' \
'--rerun-each[Re-run each test file <NUMBER> times, helps catch certain bugs]:rerun' \
'--retry[Default retry count for all tests]:retry' \
'--todo[Include tests that are marked with "test.todo()"]' \
'--coverage[Generate a coverage profile]' \
'--bail[Exit the test suite after <NUMBER> failures. If you do not specify a number, it defaults to 1.]:bail' \

View File

@@ -7,9 +7,9 @@ Bytecode caching is a build-time optimization that dramatically improves applica
## Usage
### Basic usage
### Basic usage (CommonJS)
Enable bytecode caching with the `--bytecode` flag:
Enable bytecode caching with the `--bytecode` flag. Without `--format`, this defaults to CommonJS:
```bash terminal icon="terminal"
bun build ./index.ts --target=bun --bytecode --outdir=./dist
@@ -17,7 +17,7 @@ bun build ./index.ts --target=bun --bytecode --outdir=./dist
This generates two files:
- `dist/index.js` - Your bundled JavaScript
- `dist/index.js` - Your bundled JavaScript (CommonJS)
- `dist/index.jsc` - The bytecode cache file
At runtime, Bun automatically detects and uses the `.jsc` file:
@@ -28,14 +28,24 @@ bun ./dist/index.js # Automatically uses index.jsc
### With standalone executables
When creating executables with `--compile`, bytecode is embedded into the binary:
When creating executables with `--compile`, bytecode is embedded into the binary. Both ESM and CommonJS formats are supported:
```bash terminal icon="terminal"
# ESM (requires --compile)
bun build ./cli.ts --compile --bytecode --format=esm --outfile=mycli
# CommonJS (works with or without --compile)
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.
### ESM bytecode
ESM bytecode requires `--compile` because Bun embeds module metadata (import/export information) in the compiled binary. This metadata allows the JavaScript engine to skip parsing entirely at runtime.
Without `--compile`, ESM bytecode would still require parsing the source to analyze module dependencies—defeating the purpose of bytecode caching.
### Combining with other optimizations
Bytecode works great with minification and source maps:
@@ -90,35 +100,9 @@ Larger applications benefit more because they have more code to parse.
- ❌ **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.
@@ -236,8 +220,6 @@ It's normal for it it to log a cache miss multiple times since Bun doesn't curre
- 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:

View File

@@ -322,10 +322,7 @@ Using bytecode compilation, `tsc` starts 2x faster:
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.
<Warning>
**Experimental:** Bytecode compilation is an experimental feature. Only `cjs` format is supported (which means no
top-level-await). Let us know if you run into any issues!
</Warning>
<Note>Bytecode compilation supports both `cjs` and `esm` formats when used with `--compile`.</Note>
### What do these flags do?
@@ -365,6 +362,23 @@ The `--bytecode` argument enables bytecode compilation. Every time you run JavaS
console.log(process.execArgv); // ["--smol", "--user-agent=MyBot"]
```
### Runtime arguments via `BUN_OPTIONS`
The `BUN_OPTIONS` environment variable is applied to standalone executables, allowing you to pass runtime flags without recompiling:
```bash terminal icon="terminal"
# Enable CPU profiling on a compiled executable
BUN_OPTIONS="--cpu-prof" ./myapp
# Enable heap profiling with markdown output
BUN_OPTIONS="--heap-prof-md" ./myapp
# Combine multiple flags
BUN_OPTIONS="--smol --cpu-prof-md" ./myapp
```
This is useful for debugging or profiling production executables without rebuilding them.
---
## Automatic config loading

View File

@@ -1333,6 +1333,50 @@ Generate metadata about the build in a structured format. The metafile contains
</Tab>
</Tabs>
#### Markdown metafile
Use `--metafile-md` to generate a markdown metafile, which is LLM-friendly and easy to read in the terminal:
```bash terminal icon="terminal"
bun build ./src/index.ts --outdir ./dist --metafile-md ./dist/meta.md
```
Both `--metafile` and `--metafile-md` can be used together:
```bash terminal icon="terminal"
bun build ./src/index.ts --outdir ./dist --metafile ./dist/meta.json --metafile-md ./dist/meta.md
```
#### `metafile` option formats
In the JavaScript API, `metafile` accepts several forms:
```ts title="build.ts" icon="/icons/typescript.svg"
// Boolean — include metafile in the result object
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
metafile: true,
});
// String — write JSON metafile to a specific path
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
metafile: "./dist/meta.json",
});
// Object — specify separate paths for JSON and markdown output
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
metafile: {
json: "./dist/meta.json",
markdown: "./dist/meta.md",
},
});
```
The metafile structure contains:
```ts
@@ -1464,22 +1508,43 @@ BuildArtifact (entry-point) {
## Bytecode
The `bytecode: boolean` option can be used to generate bytecode for any JavaScript/TypeScript entrypoints. This can greatly improve startup times for large applications. Only supported for `"cjs"` format, only supports `"target": "bun"` and dependent on a matching version of Bun. This adds a corresponding `.jsc` file for each entrypoint.
The `bytecode: boolean` option can be used to generate bytecode for any JavaScript/TypeScript entrypoints. This can greatly improve startup times for large applications. Requires `"target": "bun"` and is dependent on a matching version of Bun.
- **CommonJS**: Works with or without `compile: true`. Generates a `.jsc` file alongside each entrypoint.
- **ESM**: Requires `compile: true`. Bytecode and module metadata are embedded in the standalone executable.
Without an explicit `format`, bytecode defaults to CommonJS.
<Tabs>
<Tab title="JavaScript">
```ts title="build.ts" icon="/icons/typescript.svg"
// CommonJS bytecode (generates .jsc files)
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
bytecode: true,
})
// ESM bytecode (requires compile)
await Bun.build({
entrypoints: ["./index.tsx"],
outfile: "./mycli",
bytecode: true,
format: "esm",
compile: true,
})
```
</Tab>
<Tab title="CLI">
```bash terminal icon="terminal"
# CommonJS bytecode
bun build ./index.tsx --outdir ./out --bytecode
# ESM bytecode (requires --compile)
bun build ./index.tsx --outfile ./mycli --bytecode --format=esm --compile
```
</Tab>
</Tabs>
@@ -1646,7 +1711,10 @@ interface BuildConfig {
* start times, but will make the final output larger and slightly increase
* memory usage.
*
* Bytecode is currently only supported for CommonJS (`format: "cjs"`).
* - CommonJS: works with or without `compile: true`
* - ESM: requires `compile: true`
*
* Without an explicit `format`, defaults to CommonJS.
*
* Must be `target: "bun"`
* @default false

View File

@@ -150,6 +150,8 @@
"/runtime/secrets",
"/runtime/console",
"/runtime/yaml",
"/runtime/markdown",
"/runtime/json5",
"/runtime/jsonl",
"/runtime/html-rewriter",
"/runtime/hashing",
@@ -498,6 +500,7 @@
"/guides/runtime/import-json",
"/guides/runtime/import-toml",
"/guides/runtime/import-yaml",
"/guides/runtime/import-json5",
"/guides/runtime/import-html",
"/guides/util/import-meta-dir",
"/guides/util/import-meta-file",

View File

@@ -0,0 +1,74 @@
---
title: Import a JSON5 file
sidebarTitle: Import JSON5
mode: center
---
Bun natively supports `.json5` imports.
```json5 config.json5 icon="file-code"
{
// Comments are allowed
database: {
host: "localhost",
port: 5432,
name: "myapp",
},
server: {
port: 3000,
timeout: 30,
},
features: {
auth: true,
rateLimit: true,
},
}
```
---
Import the file like any other source file.
```ts config.ts icon="/icons/typescript.svg"
import config from "./config.json5";
config.database.host; // => "localhost"
config.server.port; // => 3000
config.features.auth; // => true
```
---
You can also use named imports to destructure top-level properties:
```ts config.ts icon="/icons/typescript.svg"
import { database, server, features } from "./config.json5";
console.log(database.name); // => "myapp"
console.log(server.timeout); // => 30
console.log(features.rateLimit); // => true
```
---
For parsing JSON5 strings at runtime, use `Bun.JSON5.parse()`:
```ts config.ts icon="/icons/typescript.svg"
const data = JSON5.parse(`{
name: 'John Doe',
age: 30,
hobbies: [
'reading',
'coding',
],
}`);
console.log(data.name); // => "John Doe"
console.log(data.hobbies); // => ["reading", "coding"]
```
---
See [Docs > API > JSON5](/runtime/json5) for complete documentation on JSON5 support in Bun.

View File

@@ -97,6 +97,31 @@ Filters respect your [workspace configuration](/pm/workspaces): If you have a `p
bun run --filter foo myscript
```
### Parallel and sequential mode
Combine `--filter` or `--workspaces` with `--parallel` or `--sequential` to run scripts across workspace packages with Foreman-style prefixed output:
```bash terminal icon="terminal"
# Run "build" in all matching packages concurrently
bun run --parallel --filter '*' build
# Run "build" in all workspace packages sequentially
bun run --sequential --workspaces build
# Run glob-matched scripts across all packages
bun run --parallel --filter '*' "build:*"
# Continue running even if one package's script fails
bun run --parallel --no-exit-on-error --filter '*' test
# Run multiple scripts across all packages
bun run --parallel --filter '*' build lint
```
Each line of output is prefixed with the package and script name (e.g. `pkg-a:build | ...`). Without `--filter`/`--workspaces`, the prefix is just the script name (e.g. `build | ...`). When a package's `package.json` has no `name` field, the relative path from the workspace root is used instead.
Use `--if-present` with `--workspaces` to skip packages that don't have the requested script instead of erroring.
### Dependency Order
Bun will respect package dependency order when running scripts. Say you have a package `foo` that depends on another package `bar` in your workspace, and both packages have a `build` script. When you run `bun --filter '*' build`, you will notice that `foo` will only start running once `bar` is done.

View File

@@ -227,6 +227,26 @@ bun --cpu-prof script.js
This generates a `.cpuprofile` file you can open in Chrome DevTools (Performance tab → Load profile) or VS Code's CPU profiler.
### Markdown output
Use `--cpu-prof-md` to generate a markdown CPU profile, which is grep-friendly and designed for LLM analysis:
```sh terminal icon="terminal"
bun --cpu-prof-md script.js
```
Both `--cpu-prof` and `--cpu-prof-md` can be used together to generate both formats at once:
```sh terminal icon="terminal"
bun --cpu-prof --cpu-prof-md script.js
```
You can also trigger profiling via the `BUN_OPTIONS` environment variable:
```sh terminal icon="terminal"
BUN_OPTIONS="--cpu-prof-md" bun script.js
```
### Options
```sh terminal icon="terminal"
@@ -234,8 +254,43 @@ bun --cpu-prof --cpu-prof-name my-profile.cpuprofile script.js
bun --cpu-prof --cpu-prof-dir ./profiles script.js
```
| Flag | Description |
| ---------------------------- | -------------------- |
| `--cpu-prof` | Enable profiling |
| `--cpu-prof-name <filename>` | Set output filename |
| `--cpu-prof-dir <dir>` | Set output directory |
| Flag | Description |
| ---------------------------- | ----------------------------------------------------------- |
| `--cpu-prof` | Generate a `.cpuprofile` JSON file (Chrome DevTools format) |
| `--cpu-prof-md` | Generate a markdown CPU profile (grep/LLM-friendly) |
| `--cpu-prof-name <filename>` | Set output filename |
| `--cpu-prof-dir <dir>` | Set output directory |
## Heap profiling
Generate heap snapshots on exit to analyze memory usage and find memory leaks.
```sh terminal icon="terminal"
bun --heap-prof script.js
```
This generates a V8 `.heapsnapshot` file that can be loaded in Chrome DevTools (Memory tab → Load).
### Markdown output
Use `--heap-prof-md` to generate a markdown heap profile for CLI analysis:
```sh terminal icon="terminal"
bun --heap-prof-md script.js
```
<Note>If both `--heap-prof` and `--heap-prof-md` are specified, the markdown format is used.</Note>
### Options
```sh terminal icon="terminal"
bun --heap-prof --heap-prof-name my-snapshot.heapsnapshot script.js
bun --heap-prof --heap-prof-dir ./profiles script.js
```
| Flag | Description |
| ----------------------------- | ------------------------------------------ |
| `--heap-prof` | Generate a V8 `.heapsnapshot` file on exit |
| `--heap-prof-md` | Generate a markdown heap profile on exit |
| `--heap-prof-name <filename>` | Set output filename |
| `--heap-prof-dir <dir>` | Set output directory |

View File

@@ -35,7 +35,7 @@ winget install "Visual Studio Community 2022" --override "--add Microsoft.Visual
After Visual Studio, you need the following:
- LLVM (19.1.7 for x64, 21.1.8 for ARM64)
- LLVM 21.1.8
- Go
- Rust
- NASM
@@ -51,7 +51,7 @@ After Visual Studio, you need the following:
irm https://get.scoop.sh | iex
scoop install nodejs-lts go rust nasm ruby perl ccache
# scoop seems to be buggy if you install llvm and the rest at the same time
scoop install llvm@19.1.7
scoop install llvm@21.1.8
```
For Windows ARM64, download LLVM 21.1.8 directly from GitHub releases (first version with ARM64 Windows builds):

View File

@@ -40,7 +40,7 @@ sudo pacman -S base-devel cmake git go libiconv libtool make ninja pkg-config py
```
```bash Fedora
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)'
sudo dnf install cargo clang21 llvm21 lld21 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
@@ -95,17 +95,17 @@ Our build scripts will automatically detect and use `ccache` if available. You c
## 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:
Bun requires LLVM 21.1.8 (`clang` is part of LLVM). This version is enforced by the build system — mismatching versions will cause memory allocation failures at runtime. In most cases, you can install LLVM through your system package manager:
<CodeGroup>
```bash macOS (Homebrew)
brew install llvm@19
brew install llvm@21
```
```bash Ubuntu/Debian
# LLVM has an automatic installation script that is compatible with all versions of Ubuntu
wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 19 all
wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 21 all
```
```bash Arch
@@ -117,17 +117,17 @@ sudo dnf install llvm clang lld-devel
```
```bash openSUSE Tumbleweed
sudo zypper install clang19 lld19 llvm19
sudo zypper install clang21 lld21 llvm21
```
</CodeGroup>
If none of the above solutions apply, you will have to install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-19.1.7).
If none of the above solutions apply, you will have to install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-21.1.8).
Make sure Clang/LLVM 19 is in your path:
Make sure Clang/LLVM 21 is in your path:
```bash
which clang-19
which clang-21
```
If not, run this to manually add it:
@@ -136,13 +136,13 @@ If not, run this to manually add it:
```bash macOS (Homebrew)
# use fish_add_path if you're using fish
# use path+="$(brew --prefix llvm@19)/bin" if you are using zsh
export PATH="$(brew --prefix llvm@19)/bin:$PATH"
# use path+="$(brew --prefix llvm@21)/bin" if you are using zsh
export PATH="$(brew --prefix llvm@21)/bin:$PATH"
```
```bash Arch
# use fish_add_path if you're using fish
export PATH="$PATH:/usr/lib/llvm19/bin"
export PATH="$PATH:/usr/lib/llvm21/bin"
```
</CodeGroup>
@@ -266,18 +266,13 @@ git clone https://github.com/oven-sh/WebKit vendor/WebKit
# Check out the commit hash specified in `set(WEBKIT_VERSION <commit_hash>)` in cmake/tools/SetupWebKit.cmake
git -C vendor/WebKit checkout <commit_hash>
# Make a debug build of JSC. This will output build artifacts in ./vendor/WebKit/WebKitBuild/Debug
# Optionally, you can use `bun run jsc:build` for a release build
bun run jsc:build:debug && rm vendor/WebKit/WebKitBuild/Debug/JavaScriptCore/DerivedSources/inspector/InspectorProtocolObjects.h
# After an initial run of `make jsc-debug`, you can rebuild JSC with:
cmake --build vendor/WebKit/WebKitBuild/Debug --target jsc && rm vendor/WebKit/WebKitBuild/Debug/JavaScriptCore/DerivedSources/inspector/InspectorProtocolObjects.h
# Build bun with the local JSC build
# Build bun with the local JSC build — this automatically configures and builds JSC
bun run build:local
```
Using `bun run build:local` will build Bun in the `./build/debug-local` directory (instead of `./build/debug`), you'll have to change a couple of places to use this new directory:
`bun run build:local` handles everything: configuring JSC, building JSC, and building Bun. On subsequent runs, JSC will incrementally rebuild if any WebKit sources changed. `ninja -Cbuild/debug-local` also works after the first build, and will build Bun+JSC.
The build output goes to `./build/debug-local` (instead of `./build/debug`), so you'll need to update a couple of places:
- The first line in `src/js/builtins.d.ts`
- The `CompilationDatabase` line in `.clangd` config should be `CompilationDatabase: build/debug-local`
@@ -288,7 +283,7 @@ Note that the WebKit folder, including build artifacts, is 8GB+ in size.
If you are using a JSC debug build and using VScode, make sure to run the `C/C++: Select a Configuration` command to configure intellisense to find the debug headers.
Note that if you change make changes to our [WebKit fork](https://github.com/oven-sh/WebKit), you will also have to change `SetupWebKit.cmake` to point to the commit hash.
Note that if you make changes to our [WebKit fork](https://github.com/oven-sh/WebKit), you will also have to change `SetupWebKit.cmake` to point to the commit hash.
## Troubleshooting
@@ -314,7 +309,7 @@ The issue may manifest when initially running `bun setup` as Clang being unable
```txt
The C++ compiler
"/usr/bin/clang++-19"
"/usr/bin/clang++-21"
is not able to compile a simple test program.
```

View File

@@ -55,5 +55,5 @@ Click the link in the right column to jump to the associated documentation.
| Stream Processing | [`Bun.readableStreamTo*()`](/runtime/utils#bun-readablestreamto), `Bun.readableStreamToBytes()`, `Bun.readableStreamToBlob()`, `Bun.readableStreamToFormData()`, `Bun.readableStreamToJSON()`, `Bun.readableStreamToArray()` |
| Memory & Buffer Management | `Bun.ArrayBufferSink`, `Bun.allocUnsafe`, `Bun.concatArrayBuffers` |
| Module Resolution | [`Bun.resolveSync()`](/runtime/utils#bun-resolvesync) |
| Parsing & Formatting | [`Bun.semver`](/runtime/semver), `Bun.TOML.parse`, [`Bun.color`](/runtime/color) |
| Parsing & Formatting | [`Bun.semver`](/runtime/semver), `Bun.TOML.parse`, [`Bun.markdown`](/runtime/markdown), [`Bun.color`](/runtime/color) |
| Low-level / Internals | `Bun.mmap`, `Bun.gc`, `Bun.generateHeapSnapshot`, [`bun:jsc`](https://bun.com/reference/bun/jsc) |

View File

@@ -298,6 +298,17 @@ This is useful for catching flaky tests or non-deterministic behavior. Each test
The `--rerun-each` CLI flag will override this setting when specified.
### `test.retry`
Default retry count for all tests. Failed tests will be retried up to this many times. Per-test `{ retry: N }` overrides this value. Default `0` (no retries).
```toml title="bunfig.toml" icon="settings"
[test]
retry = 3
```
The `--retry` CLI flag will override this setting when specified.
### `test.concurrentTestGlob`
Specify a glob pattern to automatically run matching test files with concurrent test execution enabled. Test files matching this pattern will behave as if the `--concurrent` flag was passed, running all tests within those files concurrently.

View File

@@ -5,7 +5,7 @@ description: "File types and loaders supported by Bun's 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` `.css` `.json` `.jsonc` `.toml` `.yaml` `.yml` `.txt` `.wasm` `.node` `.html` `.sh`
`.js` `.cjs` `.mjs` `.mts` `.cts` `.ts` `.tsx` `.jsx` `.css` `.json` `.jsonc` `.json5` `.toml` `.yaml` `.yml` `.txt` `.wasm` `.node` `.html` `.sh`
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](/bundler/plugins) that extend Bun with custom loaders.
@@ -197,6 +197,53 @@ export default {
</CodeGroup>
### `json5`
**JSON5 loader**. Default for `.json5`.
JSON5 files can be directly imported. Bun will parse them with its fast native JSON5 parser. JSON5 is a superset of JSON that supports comments, trailing commas, unquoted keys, single-quoted strings, and more.
```ts
import config from "./config.json5";
console.log(config);
// via import attribute:
import data from "./data.txt" with { type: "json5" };
```
During bundling, the parsed JSON5 is inlined into the bundle as a JavaScript object.
```ts
var config = {
name: "my-app",
version: "1.0.0",
// ...other fields
};
```
If a `.json5` file is passed as an entrypoint, it will be converted to a `.js` module that `export default`s the parsed object.
<CodeGroup>
```json5 Input
{
// Configuration
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`.

271
docs/runtime/json5.mdx Normal file
View File

@@ -0,0 +1,271 @@
---
title: JSON5
description: Use Bun's built-in support for JSON5 files through both runtime APIs and bundler integration
---
In Bun, JSON5 is a first-class citizen alongside JSON, TOML, and YAML. You can:
- Parse and stringify JSON5 with `Bun.JSON5.parse` and `Bun.JSON5.stringify`
- `import` & `require` JSON5 files as modules at runtime (including hot reloading & watch mode support)
- `import` & `require` JSON5 files in frontend apps via Bun's bundler
---
## Conformance
Bun's JSON5 parser passes 100% of the [official JSON5 test suite](https://github.com/json5/json5-tests). The parser is written in Zig for optimal performance. You can view our [translated test suite](https://github.com/oven-sh/bun/blob/main/test/js/bun/json5/json5-test-suite.test.ts) to see every test case.
---
## Runtime API
### `Bun.JSON5.parse()`
Parse a JSON5 string into a JavaScript value.
```ts
import { JSON5 } from "bun";
const data = JSON5.parse(`{
// JSON5 supports comments
name: 'my-app',
version: '1.0.0',
debug: true,
// trailing commas are allowed
tags: ['web', 'api',],
}`);
console.log(data);
// {
// name: "my-app",
// version: "1.0.0",
// debug: true,
// tags: ["web", "api"]
// }
```
#### Supported JSON5 Features
JSON5 is a superset of JSON based on ECMAScript 5.1 syntax. It supports:
- **Comments**: single-line (`//`) and multi-line (`/* */`)
- **Trailing commas**: in objects and arrays
- **Unquoted keys**: valid ECMAScript 5.1 identifiers can be used as keys
- **Single-quoted strings**: in addition to double-quoted strings
- **Multi-line strings**: using backslash line continuations
- **Hex numbers**: `0xFF`
- **Leading & trailing decimal points**: `.5` and `5.`
- **Infinity and NaN**: positive and negative
- **Explicit plus sign**: `+42`
```ts
const data = JSON5.parse(`{
// Unquoted keys
unquoted: 'keys work',
// Single and double quotes
single: 'single-quoted',
double: "double-quoted",
// Trailing commas
trailing: 'comma',
// Special numbers
hex: 0xDEADbeef,
half: .5,
to: Infinity,
nan: NaN,
// Multi-line strings
multiline: 'line 1 \
line 2',
}`);
```
#### Error Handling
`Bun.JSON5.parse()` throws a `SyntaxError` if the input is invalid JSON5:
```ts
try {
JSON5.parse("{invalid}");
} catch (error) {
console.error("Failed to parse JSON5:", error.message);
}
```
### `Bun.JSON5.stringify()`
Stringify a JavaScript value to a JSON5 string.
```ts
import { JSON5 } from "bun";
const str = JSON5.stringify({ name: "my-app", version: "1.0.0" });
console.log(str);
// {name:'my-app',version:'1.0.0'}
```
#### Pretty Printing
Pass a `space` argument to format the output with indentation:
```ts
const pretty = JSON5.stringify(
{
name: "my-app",
debug: true,
tags: ["web", "api"],
},
null,
2,
);
console.log(pretty);
// {
// name: 'my-app',
// debug: true,
// tags: [
// 'web',
// 'api',
// ],
// }
```
The `space` argument can be a number (number of spaces) or a string (used as the indent character):
```ts
// Tab indentation
JSON5.stringify(data, null, "\t");
```
#### Special Values
Unlike `JSON.stringify`, `JSON5.stringify` preserves special numeric values:
```ts
JSON5.stringify({ inf: Infinity, ninf: -Infinity, nan: NaN });
// {inf:Infinity,ninf:-Infinity,nan:NaN}
```
---
## Module Import
### ES Modules
You can import JSON5 files directly as ES modules:
```json5 config.json5
{
// Database configuration
database: {
host: "localhost",
port: 5432,
name: "myapp",
},
features: {
auth: true,
rateLimit: true,
analytics: false,
},
}
```
#### Default Import
```ts app.ts icon="/icons/typescript.svg"
import config from "./config.json5";
console.log(config.database.host); // "localhost"
console.log(config.features.auth); // true
```
#### Named Imports
You can destructure top-level properties as named imports:
```ts app.ts icon="/icons/typescript.svg"
import { database, features } from "./config.json5";
console.log(database.host); // "localhost"
console.log(features.rateLimit); // true
```
### CommonJS
JSON5 files can also be required in CommonJS:
```ts app.ts icon="/icons/typescript.svg"
const config = require("./config.json5");
console.log(config.database.name); // "myapp"
// Destructuring also works
const { database, features } = require("./config.json5");
```
---
## Hot Reloading with JSON5
When you run your application with `bun --hot`, changes to JSON5 files are automatically detected and reloaded:
```json5 config.json5
{
server: {
port: 3000,
host: "localhost",
},
features: {
debug: true,
verbose: false,
},
}
```
```ts server.ts icon="/icons/typescript.svg"
import { server, features } from "./config.json5";
Bun.serve({
port: server.port,
hostname: server.host,
fetch(req) {
if (features.verbose) {
console.log(`${req.method} ${req.url}`);
}
return new Response("Hello World");
},
});
```
Run with hot reloading:
```bash terminal icon="terminal"
bun --hot server.ts
```
---
## Bundler Integration
When you import JSON5 files and bundle with Bun, the JSON5 is parsed at build time and included as a JavaScript module:
```bash terminal icon="terminal"
bun build app.ts --outdir=dist
```
This means:
- Zero runtime JSON5 parsing overhead in production
- Smaller bundle sizes
- Tree-shaking support for unused properties (named imports)
### Dynamic Imports
JSON5 files can be dynamically imported:
```ts
const config = await import("./config.json5");
```

344
docs/runtime/markdown.mdx Normal file
View File

@@ -0,0 +1,344 @@
---
title: Markdown
description: Parse and render Markdown with Bun's built-in Markdown API, supporting GFM extensions and custom rendering callbacks
---
<Callout type="note">
**Unstable API** — This API is under active development and may change in future versions of Bun.
</Callout>
Bun includes a fast, built-in Markdown parser written in Zig. It supports GitHub Flavored Markdown (GFM) extensions and provides three APIs:
- `Bun.markdown.html()` — render Markdown to an HTML string
- `Bun.markdown.render()` — render Markdown with custom callbacks for each element
- `Bun.markdown.react()` — render Markdown to React JSX elements
---
## `Bun.markdown.html()`
Convert a Markdown string to HTML.
```ts
const html = Bun.markdown.html("# Hello **world**");
// "<h1>Hello <strong>world</strong></h1>\n"
```
GFM extensions like tables, strikethrough, and task lists are enabled by default:
```ts
const html = Bun.markdown.html(`
| Feature | Status |
|-------------|--------|
| Tables | ~~done~~ |
| Strikethrough| ~~done~~ |
| Task lists | done |
`);
```
### Options
Pass an options object as the second argument to configure the parser:
```ts
const html = Bun.markdown.html("some markdown", {
tables: true, // GFM tables (default: true)
strikethrough: true, // GFM strikethrough (default: true)
tasklists: true, // GFM task lists (default: true)
tagFilter: true, // GFM tag filter for disallowed HTML tags
autolinks: true, // Autolink URLs, emails, and www. links
});
```
All available options:
| Option | Default | Description |
| ---------------------- | ------- | ----------------------------------------------------------- |
| `tables` | `false` | GFM tables |
| `strikethrough` | `false` | GFM strikethrough (`~~text~~`) |
| `tasklists` | `false` | GFM task lists (`- [x] item`) |
| `autolinks` | `false` | Enable autolinks — see [Autolinks](#autolinks) |
| `headings` | `false` | Heading IDs and autolinks — see [Heading IDs](#heading-ids) |
| `hardSoftBreaks` | `false` | Treat soft line breaks as hard breaks |
| `wikiLinks` | `false` | Enable `[[wiki links]]` |
| `underline` | `false` | `__text__` renders as `<u>` instead of `<strong>` |
| `latexMath` | `false` | Enable `$inline$` and `$$display$$` math |
| `collapseWhitespace` | `false` | Collapse whitespace in text |
| `permissiveAtxHeaders` | `false` | ATX headers without space after `#` |
| `noIndentedCodeBlocks` | `false` | Disable indented code blocks |
| `noHtmlBlocks` | `false` | Disable HTML blocks |
| `noHtmlSpans` | `false` | Disable inline HTML |
| `tagFilter` | `false` | GFM tag filter for disallowed HTML tags |
#### Autolinks
Pass `true` to enable all autolink types, or an object for granular control:
```ts
// Enable all autolinks (URL, WWW, email)
Bun.markdown.html("Visit www.example.com", { autolinks: true });
// Enable only specific types
Bun.markdown.html("Visit www.example.com", {
autolinks: { url: true, www: true },
});
```
#### Heading IDs
Pass `true` to enable both heading IDs and autolink headings, or an object for granular control:
```ts
// Enable heading IDs and autolink headings
Bun.markdown.html("## Hello World", { headings: true });
// '<h2 id="hello-world"><a href="#hello-world">Hello World</a></h2>\n'
// Enable only heading IDs (no autolink)
Bun.markdown.html("## Hello World", { headings: { ids: true } });
// '<h2 id="hello-world">Hello World</h2>\n'
```
---
## `Bun.markdown.render()`
Parse Markdown and render it using custom JavaScript callbacks. This gives you full control over the output format — you can generate HTML with custom classes, React elements, ANSI terminal output, or any other string format.
```ts
const result = Bun.markdown.render("# Hello **world**", {
heading: (children, { level }) => `<h${level} class="title">${children}</h${level}>`,
strong: children => `<b>${children}</b>`,
paragraph: children => `<p>${children}</p>`,
});
// '<h1 class="title">Hello <b>world</b></h1>'
```
### Callback signature
Each callback receives:
1. **`children`** — the accumulated content of the element as a string
2. **`meta`** (optional) — an object with element-specific metadata
Return a string to replace the element's rendering. Return `null` or `undefined` to omit the element from the output entirely. If no callback is registered for an element, its children pass through unchanged.
### Block callbacks
| Callback | Meta | Description |
| ------------ | ------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `heading` | `{ level: number, id?: string }` | Heading level 16. `id` is set when `headings: { ids: true }` is enabled |
| `paragraph` | — | Paragraph block |
| `blockquote` | — | Blockquote block |
| `code` | `{ language?: string }` | Fenced or indented code block. `language` is the info-string when specified on the fence |
| `list` | `{ ordered: boolean, start?: number }` | Ordered or unordered list. `start` is the start number for ordered lists |
| `listItem` | `{ checked?: boolean }` | List item. `checked` is set for task list items (`- [x]` / `- [ ]`) |
| `hr` | — | Horizontal rule |
| `table` | — | Table block |
| `thead` | — | Table head |
| `tbody` | — | Table body |
| `tr` | — | Table row |
| `th` | `{ align?: "left" \| "center" \| "right" }` | Table header cell. `align` is set when alignment is specified |
| `td` | `{ align?: "left" \| "center" \| "right" }` | Table data cell. `align` is set when alignment is specified |
| `html` | — | Raw HTML content |
### Inline callbacks
| Callback | Meta | Description |
| --------------- | ---------------------------------- | ---------------------------- |
| `strong` | — | Strong emphasis (`**text**`) |
| `emphasis` | — | Emphasis (`*text*`) |
| `link` | `{ href: string, title?: string }` | Link |
| `image` | `{ src: string, title?: string }` | Image |
| `codespan` | — | Inline code (`` `code` ``) |
| `strikethrough` | — | Strikethrough (`~~text~~`) |
| `text` | — | Plain text content |
### Examples
#### Custom HTML with classes
```ts
const html = Bun.markdown.render("# Title\n\nHello **world**", {
heading: (children, { level }) => `<h${level} class="heading heading-${level}">${children}</h${level}>`,
paragraph: children => `<p class="body">${children}</p>`,
strong: children => `<strong class="bold">${children}</strong>`,
});
```
#### Stripping all formatting
```ts
const plaintext = Bun.markdown.render("# Hello **world**", {
heading: children => children,
paragraph: children => children,
strong: children => children,
emphasis: children => children,
link: children => children,
image: () => "",
code: children => children,
codespan: children => children,
});
// "Hello world"
```
#### Omitting elements
Return `null` or `undefined` to remove an element from the output:
```ts
const result = Bun.markdown.render("# Title\n\n![logo](img.png)\n\nHello", {
image: () => null, // Remove all images
heading: children => children,
paragraph: children => children + "\n",
});
// "Title\nHello\n"
```
#### ANSI terminal output
```ts
const ansi = Bun.markdown.render("# Hello\n\nThis is **bold** and *italic*", {
heading: (children, { level }) => `\x1b[1;4m${children}\x1b[0m\n`,
paragraph: children => children + "\n",
strong: children => `\x1b[1m${children}\x1b[22m`,
emphasis: children => `\x1b[3m${children}\x1b[23m`,
});
```
#### Code block syntax highlighting
````ts
const result = Bun.markdown.render("```js\nconsole.log('hi')\n```", {
code: (children, meta) => {
const lang = meta?.language ?? "";
return `<pre><code class="language-${lang}">${children}</code></pre>`;
},
});
````
### Parser options
Parser options are passed as a separate third argument:
```ts
const result = Bun.markdown.render(
"Visit www.example.com",
{
link: (children, { href }) => `[${children}](${href})`,
paragraph: children => children,
},
{ autolinks: true },
);
```
---
## `Bun.markdown.react()`
Render Markdown directly to React elements. Returns a `<Fragment>` that you can use as a component return value.
```tsx
function Markdown({ text }: { text: string }) {
return Bun.markdown.react(text);
}
```
### Server-side rendering
Works with `renderToString()` and React Server Components:
```tsx
import { renderToString } from "react-dom/server";
const html = renderToString(Bun.markdown.react("# Hello **world**"));
// "<h1>Hello <strong>world</strong></h1>"
```
### Component overrides
Replace any HTML element with a custom React component by passing it in the second argument, keyed by tag name:
```tsx
function Code({ language, children }) {
return (
<pre data-language={language}>
<code>{children}</code>
</pre>
);
}
function Link({ href, title, children }) {
return (
<a href={href} title={title} target="_blank" rel="noopener noreferrer">
{children}
</a>
);
}
function Heading({ id, children }) {
return (
<h2 id={id}>
<a href={`#${id}`}>{children}</a>
</h2>
);
}
const el = Bun.markdown.react(
content,
{
pre: Code,
a: Link,
h2: Heading,
},
{ headings: { ids: true } },
);
```
#### Available overrides
Every HTML tag produced by the parser can be overridden:
| Option | Props | Description |
| ------------ | ---------------------------- | --------------------------------------------------------------- |
| `h1``h6` | `{ id?, children }` | Headings. `id` is set when `headings: { ids: true }` is enabled |
| `p` | `{ children }` | Paragraph |
| `blockquote` | `{ children }` | Blockquote |
| `pre` | `{ language?, children }` | Code block. `language` is the info string (e.g. `"js"`) |
| `hr` | `{}` | Horizontal rule (no children) |
| `ul` | `{ children }` | Unordered list |
| `ol` | `{ start, children }` | Ordered list. `start` is the first item number |
| `li` | `{ checked?, children }` | List item. `checked` is set for task list items |
| `table` | `{ children }` | Table |
| `thead` | `{ children }` | Table head |
| `tbody` | `{ children }` | Table body |
| `tr` | `{ children }` | Table row |
| `th` | `{ align?, children }` | Table header cell |
| `td` | `{ align?, children }` | Table data cell |
| `em` | `{ children }` | Emphasis (`*text*`) |
| `strong` | `{ children }` | Strong (`**text**`) |
| `a` | `{ href, title?, children }` | Link |
| `img` | `{ src, alt?, title? }` | Image (no children) |
| `code` | `{ children }` | Inline code |
| `del` | `{ children }` | Strikethrough (`~~text~~`) |
| `br` | `{}` | Hard line break (no children) |
### React 18 and older
By default, elements use `Symbol.for('react.transitional.element')` as the `$$typeof` symbol. For React 18 and older, pass `reactVersion: 18` in the options (third argument):
```tsx
function Markdown({ text }: { text: string }) {
return Bun.markdown.react(text, undefined, { reactVersion: 18 });
}
```
### Parser options
All [parser options](#options) are passed as the third argument:
```tsx
const el = Bun.markdown.react("## Hello World", undefined, {
headings: { ids: true },
autolinks: true,
});
```

View File

@@ -165,7 +165,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
### [`node:inspector`](https://nodejs.org/api/inspector.html)
🔴 Not implemented.
🟡 Partially implemented. `Profiler` API is supported (`Profiler.enable`, `Profiler.disable`, `Profiler.start`, `Profiler.stop`, `Profiler.setSamplingInterval`). Other inspector APIs are not yet implemented.
### [`node:repl`](https://nodejs.org/api/repl.html)

View File

@@ -135,6 +135,18 @@ await s3file.write(JSON.stringify({ name: "John", age: 30 }), {
type: "application/json",
});
// Write with content encoding (e.g. for pre-compressed data)
await s3file.write(compressedData, {
type: "application/json",
contentEncoding: "gzip",
});
// Write with content disposition
await s3file.write(pdfData, {
type: "application/pdf",
contentDisposition: 'attachment; filename="report.pdf"',
});
// Write using a writer (streaming)
const writer = s3file.writer({ type: "application/json" });
writer.write("Hello");
@@ -188,7 +200,13 @@ const download = s3.presign("my-file.txt"); // GET, text/plain, expires in 24 ho
const upload = s3.presign("my-file", {
expiresIn: 3600, // 1 hour
method: "PUT",
type: "application/json", // No extension for inferring, so we can specify the content type to be JSON
type: "application/json", // Sets response-content-type in the presigned URL
});
// Presign with content disposition (e.g. force download with a specific filename)
const downloadUrl = s3.presign("report.pdf", {
expiresIn: 3600,
contentDisposition: 'attachment; filename="quarterly-report.pdf"',
});
// You can call .presign() if on a file reference, but avoid doing so

View File

@@ -460,7 +460,7 @@ console.log(result); // Blob(13) { size: 13, type: "text/plain" }
For cross-platform compatibility, Bun Shell implements a set of builtin commands, in addition to reading commands from the PATH environment variable.
- `cd`: change the working directory
- `ls`: list files in a directory
- `ls`: list files in a directory (supports `-l` for long listing format)
- `rm`: remove files and directories
- `echo`: print text
- `pwd`: print the working directory

View File

@@ -880,6 +880,94 @@ npm/strip-ansi 212,992 chars long-ansi 1.36 ms/iter 1.38 ms
---
## `Bun.wrapAnsi()`
<Note>Drop-in replacement for `wrap-ansi` npm package</Note>
`Bun.wrapAnsi(input: string, columns: number, options?: WrapAnsiOptions): string`
Wrap text to a specified column width while preserving ANSI escape codes, hyperlinks, and handling Unicode/emoji width correctly. This is a native, high-performance alternative to the popular [`wrap-ansi`](https://www.npmjs.com/package/wrap-ansi) npm package.
```ts
// Basic wrapping at 20 columns
Bun.wrapAnsi("The quick brown fox jumps over the lazy dog", 20);
// => "The quick brown fox\njumps over the lazy\ndog"
// Preserves ANSI escape codes
Bun.wrapAnsi("\u001b[31mThe quick brown fox jumps over the lazy dog\u001b[0m", 20);
// => "\u001b[31mThe quick brown fox\njumps over the lazy\ndog\u001b[0m"
```
### Options
```ts
Bun.wrapAnsi("Hello World", 5, {
hard: true, // Break words that exceed column width (default: false)
wordWrap: true, // Wrap at word boundaries (default: true)
trim: true, // Trim leading/trailing whitespace per line (default: true)
ambiguousIsNarrow: true, // Treat ambiguous-width characters as narrow (default: true)
});
```
| Option | Default | Description |
| ------------------- | ------- | --------------------------------------------------------------------------------------------------------------- |
| `hard` | `false` | If `true`, break words in the middle if they exceed the column width. |
| `wordWrap` | `true` | If `true`, wrap at word boundaries. If `false`, only break at explicit newlines. |
| `trim` | `true` | If `true`, trim leading and trailing whitespace from each line. |
| `ambiguousIsNarrow` | `true` | If `true`, treat ambiguous-width Unicode characters as 1 column wide. If `false`, treat them as 2 columns wide. |
TypeScript definition:
```ts expandable
namespace Bun {
export function wrapAnsi(
/**
* The string to wrap
*/
input: string,
/**
* The maximum column width
*/
columns: number,
/**
* Wrapping options
*/
options?: {
/**
* If `true`, break words in the middle if they don't fit on a line.
* If `false`, only break at word boundaries.
*
* @default false
*/
hard?: boolean;
/**
* If `true`, wrap at word boundaries when possible.
* If `false`, don't perform word wrapping (only wrap at explicit newlines).
*
* @default true
*/
wordWrap?: boolean;
/**
* If `true`, trim leading and trailing whitespace from each line.
* If `false`, preserve whitespace.
*
* @default true
*/
trim?: boolean;
/**
* When it's ambiguous and `true`, count ambiguous width characters as 1 character wide.
* If `false`, count them as 2 characters wide.
*
* @default true
*/
ambiguousIsNarrow?: boolean;
},
): string;
}
```
---
## `serialize` & `deserialize` in `bun:jsc`
To save a JavaScript value into an ArrayBuffer & back, use `serialize` and `deserialize` from the `"bun:jsc"` module.

View File

@@ -50,7 +50,8 @@ bun build <entry points>
</ParamField>
<ParamField path="--format" type="string" default="esm">
Module format of the output bundle. One of <code>esm</code>, <code>cjs</code>, or <code>iife</code>
Module format of the output bundle. One of <code>esm</code>, <code>cjs</code>, or <code>iife</code>. Defaults to{" "}
<code>cjs</code> when <code>--bytecode</code> is used.
</ParamField>
### File Naming

View File

@@ -40,6 +40,18 @@ bun run <file or script>
Run a script in all workspace packages (from the <code>workspaces</code> field in <code>package.json</code>)
</ParamField>
<ParamField path="--parallel" type="boolean">
Run multiple scripts or workspace scripts concurrently with prefixed output
</ParamField>
<ParamField path="--sequential" type="boolean">
Run multiple scripts or workspace scripts one after another with prefixed output
</ParamField>
<ParamField path="--no-exit-on-error" type="boolean">
When using <code>--parallel</code> or <code>--sequential</code>, continue running other scripts when one fails
</ParamField>
### Runtime &amp; Process Control
<ParamField path="--bun" type="boolean">

View File

@@ -14,6 +14,11 @@ bun test <patterns>
Re-run each test file <code>NUMBER</code> times, helps catch certain bugs
</ParamField>
<ParamField path="--retry" type="number">
Default retry count for all tests. Failed tests will be retried up to <code>NUMBER</code> times. Overridden by
per-test <code>{`{ retry: N }`}</code>
</ParamField>
<ParamField path="--concurrent" type="boolean">
Treat all tests as <code>test.concurrent()</code> tests
</ParamField>

View File

@@ -222,6 +222,17 @@ randomize = true
seed = 2444615283
```
#### retry
Default retry count for all tests. Failed tests will be retried up to this many times. Per-test `{ retry: N }` overrides this value. Default `0` (no retries).
```toml title="bunfig.toml" icon="settings"
[test]
retry = 3
```
The `--retry` CLI flag will override this setting when specified.
#### rerunEach
Re-run each test file multiple times to identify flaky tests:

View File

@@ -201,6 +201,35 @@ test.failing.each([1, 2, 3])("chained qualifiers %d", input => {
});
```
## Retry failed tests
Use the `--retry` flag to automatically retry failed tests up to a given number of times. If a test fails and then passes on a subsequent attempt, it is reported as passing.
```sh terminal icon="terminal"
bun test --retry 3
```
Per-test `{ retry: N }` overrides the global `--retry` value:
```ts
// Uses the global --retry value
test("uses global retry", () => {
/* ... */
});
// Overrides --retry with its own value
test("custom retry", { retry: 1 }, () => {
/* ... */
});
```
You can also set this in `bunfig.toml`:
```toml title="bunfig.toml" icon="settings"
[test]
retry = 3
```
## Rerun tests
Use the `--rerun-each` flag to run each test multiple times. This is useful for detecting flaky or non-deterministic test failures.

View File

@@ -26,10 +26,10 @@
};
};
# LLVM 19 - matching the bootstrap script (targets 19.1.7, actual version from nixpkgs-unstable)
llvm = pkgs.llvm_19;
clang = pkgs.clang_19;
lld = pkgs.lld_19;
# LLVM 21 - matching the bootstrap script (targets 21.1.8, actual version from nixpkgs-unstable)
llvm = pkgs.llvm_21;
clang = pkgs.clang_21;
lld = pkgs.lld_21;
# Node.js 24 - matching the bootstrap script (targets 24.3.0, actual version from nixpkgs-unstable)
nodejs = pkgs.nodejs_24;
@@ -42,7 +42,7 @@
pkgs.pkg-config
pkgs.ccache
# Compilers and toolchain - version pinned to LLVM 19
# Compilers and toolchain - version pinned to LLVM 21
clang
llvm
lld

24
meta.json Normal file
View File

@@ -0,0 +1,24 @@
{
"inputs": {
"../../tmp/test-entry.js": {
"bytes": 21,
"imports": [
],
"format": "esm"
}
},
"outputs": {
"./test-entry.js": {
"bytes": 49,
"inputs": {
"../../tmp/test-entry.js": {
"bytesInOutput": 22
}
},
"imports": [
],
"exports": [],
"entryPoint": "../../tmp/test-entry.js"
}
}
}

View File

@@ -35,7 +35,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionWrite, (JSC::JSGlobalObject * globalObject,
JSValue arg1 = callframe->argument(0);
JSValue toWriteArg = callframe->argument(1);
auto &vm = globalObject->vm();
auto scope = DECLARE_CATCH_SCOPE(vm);
auto scope = DECLARE_TOP_EXCEPTION_SCOPE(vm);
int32_t fd = STDOUT_FILENO;
if (callframe->argumentCount() > 1) {

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "bun",
"version": "1.3.7",
"version": "1.3.10",
"workspaces": [
"./packages/bun-types",
"./packages/@types/bun"

View File

@@ -0,0 +1,3 @@
# Bun
This is the Windows ARM64 binary for Bun, a fast all-in-one JavaScript runtime. https://bun.com

View File

@@ -73,9 +73,11 @@ async function buildRootModule(dryRun?: boolean) {
});
// Create placeholder scripts that print an error message if postinstall hasn't run.
// On Unix, these are executed as shell scripts despite the .exe extension.
// On Windows, npm creates .cmd wrappers that would fail anyway if the binary isn't valid.
const placeholderScript = `#!/bin/sh
echo "Error: Bun's postinstall script was not run." >&2
// Do NOT add a shebang (#!/bin/sh) here — npm's cmd-shim reads shebangs to generate
// .ps1/.cmd wrappers BEFORE postinstall runs, and bakes the interpreter path in.
// A #!/bin/sh shebang breaks Windows because the wrappers reference /bin/sh which
// doesn't exist, even after postinstall replaces the placeholder with the real binary.
const placeholderScript = `echo "Error: Bun's postinstall script was not run." >&2
echo "" >&2
echo "This occurs when using --ignore-scripts during installation, or when using a" >&2
echo "package manager like pnpm that does not run postinstall scripts by default." >&2

View File

@@ -95,6 +95,12 @@ export const platforms: Platform[] = [
bin: "bun-windows-x64-baseline",
exe: "bin/bun.exe",
},
// {
// os: "win32",
// arch: "arm64",
// bin: "bun-windows-aarch64",
// exe: "bin/bun.exe",
// },
];
export const supportedPlatforms: Platform[] = platforms

View File

@@ -905,6 +905,480 @@ declare module "bun" {
export function stringify(input: unknown, replacer?: undefined | null, space?: string | number): string;
}
/**
* Markdown related APIs.
*
* Provides fast markdown parsing and rendering with three output modes:
* - `html()` — render to an HTML string
* - `render()` — render with custom callbacks for each element
* - `react()` — parse to React-compatible JSX elements
*
* Supports GFM extensions (tables, strikethrough, task lists, autolinks) and
* component overrides to replace default HTML tags with custom components.
*
* @example
* ```tsx
* // Render markdown to HTML
* const html = Bun.markdown.html("# Hello **world**");
* // "<h1>Hello <strong>world</strong></h1>\n"
*
* // Render with custom callbacks
* const ansi = Bun.markdown.render("# Hello **world**", {
* heading: (children, { level }) => `\x1b[1m${children}\x1b[0m\n`,
* strong: (children) => `\x1b[1m${children}\x1b[22m`,
* paragraph: (children) => children + "\n",
* });
*
* // Render as a React component
* function Markdown({ text }: { text: string }) {
* return Bun.markdown.react(text);
* }
*
* // With component overrides
* const element = Bun.markdown.react("# Hello", { h1: MyHeadingComponent });
* ```
*/
namespace markdown {
/**
* Options for configuring the markdown parser.
*
* By default, GFM extensions (tables, strikethrough, task lists) are enabled.
*/
interface Options {
/** Enable GFM tables. Default: `true`. */
tables?: boolean;
/** Enable GFM strikethrough (`~~text~~`). Default: `true`. */
strikethrough?: boolean;
/** Enable GFM task lists (`- [x] item`). Default: `true`. */
tasklists?: boolean;
/** Treat soft line breaks as hard line breaks. Default: `false`. */
hardSoftBreaks?: boolean;
/** Enable wiki-style links (`[[target]]` or `[[target|label]]`). Default: `false`. */
wikiLinks?: boolean;
/** Enable underline syntax (`__text__` renders as `<u>` instead of `<strong>`). Default: `false`. */
underline?: boolean;
/** Enable LaTeX math (`$inline$` and `$$display$$`). Default: `false`. */
latexMath?: boolean;
/** Collapse whitespace in text content. Default: `false`. */
collapseWhitespace?: boolean;
/** Allow ATX headers without a space after `#`. Default: `false`. */
permissiveAtxHeaders?: boolean;
/** Disable indented code blocks. Default: `false`. */
noIndentedCodeBlocks?: boolean;
/** Disable HTML blocks. Default: `false`. */
noHtmlBlocks?: boolean;
/** Disable inline HTML spans. Default: `false`. */
noHtmlSpans?: boolean;
/**
* Enable the GFM tag filter, which replaces `<` with `&lt;` for disallowed
* HTML tags (e.g. `<script>`, `<style>`, `<iframe>`). Default: `false`.
*/
tagFilter?: boolean;
/**
* Enable autolinks. Pass `true` to enable all autolink types (URL, WWW, email),
* or an object to enable individually.
*
* @example
* ```ts
* // Enable all autolinks
* { autolinks: true }
* // Enable only URL and email autolinks
* { autolinks: { url: true, email: true } }
* ```
*/
autolinks?: boolean | { url?: boolean; www?: boolean; email?: boolean };
/**
* Configure heading IDs and autolink headings. Pass `true` to enable both
* heading IDs and autolink headings, or an object to configure individually.
*
* @example
* ```ts
* // Enable both heading IDs and autolink headings
* { headings: true }
* // Enable only heading IDs
* { headings: { ids: true } }
* ```
*/
headings?: boolean | { ids?: boolean; autolink?: boolean };
}
/** A component that accepts props `P`: a function, class, or HTML tag name. */
type Component<P = {}> = string | ((props: P) => any) | (new (props: P) => any);
interface ChildrenProps {
children: import("./jsx.d.ts").JSX.Element[];
}
interface HeadingProps extends ChildrenProps {
/** Heading ID slug. Set when `headings: { ids: true }` is enabled. */
id?: string;
}
interface OrderedListProps extends ChildrenProps {
/** The start number. */
start: number;
}
interface ListItemProps extends ChildrenProps {
/** Task list checked state. Set for `- [x]` / `- [ ]` items. */
checked?: boolean;
}
interface CodeBlockProps extends ChildrenProps {
/** The info-string language (e.g. `"js"`). */
language?: string;
}
interface CellProps extends ChildrenProps {
/** Column alignment. */
align?: "left" | "center" | "right";
}
interface LinkProps extends ChildrenProps {
/** Link URL. */
href: string;
/** Link title attribute. */
title?: string;
}
interface ImageProps {
/** Image URL. */
src: string;
/** Alt text. */
alt?: string;
/** Image title attribute. */
title?: string;
}
/**
* Component overrides for `react()`.
*
* Replace default HTML tags with custom React components. Each override
* receives the same props the default element would get.
*
* @example
* ```tsx
* function Code({ language, children }: { language?: string; children: React.ReactNode }) {
* return <pre data-language={language}><code>{children}</code></pre>;
* }
* Bun.markdown.react(text, { pre: Code });
* ```
*/
interface ComponentOverrides {
h1?: Component<HeadingProps>;
h2?: Component<HeadingProps>;
h3?: Component<HeadingProps>;
h4?: Component<HeadingProps>;
h5?: Component<HeadingProps>;
h6?: Component<HeadingProps>;
p?: Component<ChildrenProps>;
blockquote?: Component<ChildrenProps>;
ul?: Component<ChildrenProps>;
ol?: Component<OrderedListProps>;
li?: Component<ListItemProps>;
pre?: Component<CodeBlockProps>;
hr?: Component<{}>;
html?: Component<ChildrenProps>;
table?: Component<ChildrenProps>;
thead?: Component<ChildrenProps>;
tbody?: Component<ChildrenProps>;
tr?: Component<ChildrenProps>;
th?: Component<CellProps>;
td?: Component<CellProps>;
em?: Component<ChildrenProps>;
strong?: Component<ChildrenProps>;
a?: Component<LinkProps>;
img?: Component<ImageProps>;
code?: Component<ChildrenProps>;
del?: Component<ChildrenProps>;
math?: Component<ChildrenProps>;
u?: Component<ChildrenProps>;
br?: Component<{}>;
}
/**
* Callbacks for `render()`. Each callback receives the accumulated children
* as a string and optional metadata, and returns a string.
*
* Return `null` or `undefined` to omit the element from the output.
* If no callback is registered for an element, its children pass through unchanged.
*/
/** Meta passed to the `heading` callback. */
interface HeadingMeta {
/** Heading level (16). */
level: number;
/** Heading ID slug. Set when `headings: { ids: true }` is enabled. */
id?: string;
}
/** Meta passed to the `code` callback. */
interface CodeBlockMeta {
/** The info-string language (e.g. `"js"`). */
language?: string;
}
/** Meta passed to the `list` callback. */
interface ListMeta {
/** Whether this is an ordered list. */
ordered: boolean;
/** The start number for ordered lists. */
start?: number;
}
/** Meta passed to the `listItem` callback. */
interface ListItemMeta {
/** Task list checked state. Set for `- [x]` / `- [ ]` items. */
checked?: boolean;
}
/** Meta passed to `th` and `td` callbacks. */
interface CellMeta {
/** Column alignment. */
align?: "left" | "center" | "right";
}
/** Meta passed to the `link` callback. */
interface LinkMeta {
/** Link URL. */
href: string;
/** Link title attribute. */
title?: string;
}
/** Meta passed to the `image` callback. */
interface ImageMeta {
/** Image URL. */
src: string;
/** Image title attribute. */
title?: string;
}
interface RenderCallbacks {
/** Heading (level 16). `id` is set when `headings: { ids: true }` is enabled. */
heading?: (children: string, meta: HeadingMeta) => string | null | undefined;
/** Paragraph. */
paragraph?: (children: string) => string | null | undefined;
/** Blockquote. */
blockquote?: (children: string) => string | null | undefined;
/** Code block. `meta.language` is the info-string (e.g. `"js"`). Only passed for fenced code blocks with a language. */
code?: (children: string, meta?: CodeBlockMeta) => string | null | undefined;
/** Ordered or unordered list. `start` is the first item number for ordered lists. */
list?: (children: string, meta: ListMeta) => string | null | undefined;
/** List item. `meta.checked` is set for task list items (`- [x]` / `- [ ]`). Only passed for task list items. */
listItem?: (children: string, meta?: ListItemMeta) => string | null | undefined;
/** Horizontal rule. */
hr?: (children: string) => string | null | undefined;
/** Table. */
table?: (children: string) => string | null | undefined;
/** Table head. */
thead?: (children: string) => string | null | undefined;
/** Table body. */
tbody?: (children: string) => string | null | undefined;
/** Table row. */
tr?: (children: string) => string | null | undefined;
/** Table header cell. `meta.align` is set when column alignment is specified. */
th?: (children: string, meta?: CellMeta) => string | null | undefined;
/** Table data cell. `meta.align` is set when column alignment is specified. */
td?: (children: string, meta?: CellMeta) => string | null | undefined;
/** Raw HTML content. */
html?: (children: string) => string | null | undefined;
/** Strong emphasis (`**text**`). */
strong?: (children: string) => string | null | undefined;
/** Emphasis (`*text*`). */
emphasis?: (children: string) => string | null | undefined;
/** Link. `href` is the URL, `title` is the optional title attribute. */
link?: (children: string, meta: LinkMeta) => string | null | undefined;
/** Image. `src` is the URL, `title` is the optional title attribute. */
image?: (children: string, meta: ImageMeta) => string | null | undefined;
/** Inline code (`` `code` ``). */
codespan?: (children: string) => string | null | undefined;
/** Strikethrough (`~~text~~`). */
strikethrough?: (children: string) => string | null | undefined;
/** Plain text content. */
text?: (text: string) => string | null | undefined;
}
/** Options for `react()` — parser options and element symbol configuration. */
interface ReactOptions extends Options {
/**
* Which `$$typeof` symbol to use on the generated elements.
* - `19` (default): `Symbol.for('react.transitional.element')`
* - `18`: `Symbol.for('react.element')` — use this for React 18 and older
*/
reactVersion?: 18 | 19;
}
/**
* Render markdown to an HTML string.
*
* @param input The markdown string or buffer to render
* @param options Parser options
* @returns An HTML string
*
* @example
* ```ts
* const html = Bun.markdown.html("# Hello **world**");
* // "<h1>Hello <strong>world</strong></h1>\n"
*
* // With options
* const html = Bun.markdown.html("## Hello", { headings: { ids: true } });
* // '<h2 id="hello">Hello</h2>\n'
* ```
*/
export function html(
input: string | NodeJS.TypedArray | DataView<ArrayBuffer> | ArrayBufferLike,
options?: Options,
): string;
/**
* Render markdown with custom JavaScript callbacks for each element.
*
* Each callback receives the accumulated children as a string and optional
* metadata, and returns a string. Return `null` or `undefined` to omit
* an element. If no callback is registered, children pass through unchanged.
*
* Parser options are passed as a separate third argument.
*
* @param input The markdown string to render
* @param callbacks Callbacks for each element type
* @param options Parser options
* @returns The accumulated string output
*
* @example
* ```ts
* // Custom HTML with classes
* const html = Bun.markdown.render("# Title\n\nHello **world**", {
* heading: (children, { level }) => `<h${level} class="title">${children}</h${level}>`,
* paragraph: (children) => `<p>${children}</p>`,
* strong: (children) => `<b>${children}</b>`,
* });
*
* // ANSI terminal output
* const ansi = Bun.markdown.render("# Hello\n\n**bold**", {
* heading: (children) => `\x1b[1;4m${children}\x1b[0m\n`,
* paragraph: (children) => children + "\n",
* strong: (children) => `\x1b[1m${children}\x1b[22m`,
* });
*
* // With parser options as third argument
* const text = Bun.markdown.render("Visit www.example.com", {
* link: (children, { href }) => `[${children}](${href})`,
* paragraph: (children) => children,
* }, { autolinks: true });
* ```
*/
export function render(
input: string | NodeJS.TypedArray | DataView<ArrayBuffer> | ArrayBufferLike,
callbacks?: RenderCallbacks,
options?: Options,
): string;
/**
* Render markdown to React JSX elements.
*
* Returns a React Fragment containing the parsed markdown as children.
* Can be returned directly from a component or passed to `renderToString()`.
*
* Override any HTML element with a custom component by passing it in the
* second argument, keyed by tag name. Custom components receive the same props
* the default elements would (e.g. `href` for links, `language` for code blocks).
*
* Parser options (including `reactVersion`) are passed as a separate third argument.
* Uses `Symbol.for('react.transitional.element')` by default (React 19).
* Pass `reactVersion: 18` for React 18 and older.
*
* @param input The markdown string or buffer to parse
* @param components Component overrides keyed by HTML tag name
* @param options Parser options and element symbol configuration
* @returns A React Fragment element containing the parsed markdown
*
* @example
* ```tsx
* // Use directly as a component return value
* function Markdown({ text }: { text: string }) {
* return Bun.markdown.react(text);
* }
*
* // Server-side rendering
* import { renderToString } from "react-dom/server";
* const html = renderToString(Bun.markdown.react("# Hello **world**"));
*
* // Custom components receive element props
* function Code({ language, children }: { language?: string; children: React.ReactNode }) {
* return <pre data-language={language}><code>{children}</code></pre>;
* }
* function Link({ href, children }: { href: string; children: React.ReactNode }) {
* return <a href={href} target="_blank">{children}</a>;
* }
* const el = Bun.markdown.react(text, { pre: Code, a: Link });
*
* // For React 18 and older
* const el18 = Bun.markdown.react(text, undefined, { reactVersion: 18 });
* ```
*/
export function react(
input: string | NodeJS.TypedArray | DataView<ArrayBuffer> | ArrayBufferLike,
components?: ComponentOverrides,
options?: ReactOptions,
): import("./jsx.d.ts").JSX.Element;
}
/**
* JSON5 related APIs
*/
namespace JSON5 {
/**
* Parse a JSON5 string into a JavaScript value.
*
* JSON5 is a superset of JSON based on ECMAScript 5.1 that supports
* comments, trailing commas, unquoted keys, single-quoted strings,
* hex numbers, Infinity, NaN, and more.
*
* @category Utilities
*
* @param input The JSON5 string to parse
* @returns A JavaScript value
*
* @example
* ```ts
* import { JSON5 } from "bun";
*
* const result = JSON5.parse(`{
* // This is a comment
* name: 'my-app',
* version: '1.0.0', // trailing comma is allowed
* hex: 0xDEADbeef,
* half: .5,
* infinity: Infinity,
* }`);
* ```
*/
export function parse(input: string): unknown;
/**
* Convert a JavaScript value into a JSON5 string. Object keys that are
* valid identifiers are unquoted, strings use double quotes, `Infinity`
* and `NaN` are represented as literals, and indented output includes
* trailing commas.
*
* @category Utilities
*
* @param input The JavaScript value to stringify.
* @param replacer Currently not supported.
* @param space A number for how many spaces each level of indentation gets, or a string used as indentation.
* The number is clamped between 0 and 10, and the first 10 characters of the string are used.
* @returns A JSON5 string, or `undefined` if the input is `undefined`, a function, or a symbol.
*
* @example
* ```ts
* import { JSON5 } from "bun";
*
* console.log(JSON5.stringify({ a: 1, b: "two" }));
* // {a:1,b:"two"}
*
* console.log(JSON5.stringify({ a: 1, b: 2 }, null, 2));
* // {
* // a: 1,
* // b: 2,
* // }
* ```
*/
export function stringify(input: unknown, replacer?: undefined | null, space?: string | number): string | undefined;
}
/**
* Synchronously resolve a `moduleId` as though it were imported from `parent`
*
@@ -1680,7 +2154,7 @@ declare module "bun" {
interface Hash {
wyhash: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: bigint) => bigint;
adler32: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer) => number;
crc32: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer) => number;
crc32: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number) => number;
cityHash32: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer) => number;
cityHash64: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: bigint) => bigint;
xxHash32: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number) => number;
@@ -1959,18 +2433,24 @@ declare module "bun" {
type SIMD = "baseline" | "modern";
type CompileTarget =
| `bun-darwin-${Architecture}`
| `bun-darwin-x64-${SIMD}`
| `bun-darwin-${Architecture}-${SIMD}`
| `bun-linux-${Architecture}`
| `bun-linux-${Architecture}-${Libc}`
| "bun-windows-x64"
| `bun-windows-x64-${SIMD}`
| `bun-linux-x64-${SIMD}-${Libc}`;
| `bun-linux-${Architecture}-${SIMD}`
| `bun-linux-${Architecture}-${SIMD}-${Libc}`
| `bun-windows-${Architecture}`
| `bun-windows-x64-${SIMD}`;
}
/**
* @see [Bun.build API docs](https://bun.com/docs/bundler#api)
*/
interface BuildConfigBase {
interface BuildConfig {
/**
* Enable code splitting
*/
splitting?: boolean;
/**
* List of entrypoints, usually file paths
*/
@@ -2119,7 +2599,10 @@ declare module "bun" {
* start times, but will make the final output larger and slightly increase
* memory usage.
*
* Bytecode is currently only supported for CommonJS (`format: "cjs"`).
* - CommonJS: works with or without `compile: true`
* - ESM: requires `compile: true`
*
* Without an explicit `format`, defaults to CommonJS.
*
* Must be `target: "bun"`
* @default false
@@ -2296,6 +2779,33 @@ declare module "bun" {
metafile?: boolean;
outdir?: string;
/**
* Create a standalone executable
*
* When `true`, creates an executable for the current platform.
* When a target string, creates an executable for that platform.
*
* @example
* ```ts
* // Create executable for current platform
* await Bun.build({
* entrypoints: ['./app.js'],
* compile: {
* target: 'linux-x64',
* },
* outfile: './my-app'
* });
*
* // Cross-compile for Linux x64
* await Bun.build({
* entrypoints: ['./app.js'],
* compile: 'linux-x64',
* outfile: './my-app'
* });
* ```
*/
compile?: boolean | Bun.Build.CompileTarget | CompileBuildOptions;
}
interface CompileBuildOptions {
@@ -2354,57 +2864,6 @@ declare module "bun" {
};
}
// Compile build config - uses outfile for executable output
interface CompileBuildConfig extends BuildConfigBase {
/**
* Create a standalone executable
*
* When `true`, creates an executable for the current platform.
* When a target string, creates an executable for that platform.
*
* @example
* ```ts
* // Create executable for current platform
* await Bun.build({
* entrypoints: ['./app.js'],
* compile: {
* target: 'linux-x64',
* },
* outfile: './my-app'
* });
*
* // Cross-compile for Linux x64
* await Bun.build({
* entrypoints: ['./app.js'],
* compile: 'linux-x64',
* outfile: './my-app'
* });
* ```
*/
compile: boolean | Bun.Build.CompileTarget | CompileBuildOptions;
/**
* Splitting is not currently supported with `.compile`
*/
splitting?: never;
}
interface NormalBuildConfig extends BuildConfigBase {
/**
* Enable code splitting
*
* This does not currently work with {@link CompileBuildConfig.compile `compile`}
*
* @default true
*/
splitting?: boolean;
}
/**
* @see [Bun.build API docs](https://bun.com/docs/bundler#api)
*/
type BuildConfig = CompileBuildConfig | NormalBuildConfig;
/**
* Hash and verify passwords using argon2 or bcrypt
*
@@ -5204,7 +5663,7 @@ declare module "bun" {
*
* This will apply to all sockets from the same {@link Listener}. it is per socket only for {@link Bun.connect}.
*/
reload(handler: SocketHandler): void;
reload(options: Pick<SocketOptions<Data>, "socket">): void;
/**
* Get the server that created this socket
@@ -5547,7 +6006,7 @@ declare module "bun" {
stop(closeActiveConnections?: boolean): void;
ref(): void;
unref(): void;
reload(options: Pick<Partial<SocketOptions>, "socket">): void;
reload(options: Pick<SocketOptions<Data>, "socket">): void;
data: Data;
}
interface TCPSocketListener<Data = unknown> extends SocketListener<Data> {

View File

@@ -23,6 +23,11 @@ declare module "*.jsonc" {
export = contents;
}
declare module "*.json5" {
var contents: any;
export = contents;
}
declare module "*/bun.lock" {
var contents: import("bun").BunLockFile;
export = contents;

11
packages/bun-types/jsx.d.ts vendored Normal file
View File

@@ -0,0 +1,11 @@
export {};
type ReactElement = typeof globalThis extends { React: infer React }
? React extends { createElement(...args: any): infer R }
? R
: never
: unknown;
export namespace JSX {
export type Element = ReactElement;
}

View File

@@ -2179,6 +2179,7 @@ declare module "bun:test" {
mockResolvedValueOnce(value: ResolveType<T>): this;
mockRejectedValue(value: RejectType<T>): this;
mockRejectedValueOnce(value: RejectType<T>): this;
[Symbol.dispose](): void;
}
// export type MockMetadata<T, MetadataType = MockMetadataType> = {

View File

@@ -23196,557 +23196,6 @@ CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
#
# Certificate "CommScope Public Trust ECC Root-01"
#
# Issuer: CN=CommScope Public Trust ECC Root-01,O=CommScope,C=US
# Serial Number:43:70:82:77:cf:4d:5d:34:f1:ca:ae:32:2f:37:f7:f4:7f:75:a0:9e
# Subject: CN=CommScope Public Trust ECC Root-01,O=CommScope,C=US
# Not Valid Before: Wed Apr 28 17:35:43 2021
# Not Valid After : Sat Apr 28 17:35:42 2046
# Fingerprint (SHA-256): 11:43:7C:DA:7B:B4:5E:41:36:5F:45:B3:9A:38:98:6B:0D:E0:0D:EF:34:8E:0C:7B:B0:87:36:33:80:0B:C3:8B
# Fingerprint (SHA1): 07:86:C0:D8:DD:8E:C0:80:98:06:98:D0:58:7A:EF:DE:A6:CC:A2:5D
CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
CKA_TOKEN CK_BBOOL CK_TRUE
CKA_PRIVATE CK_BBOOL CK_FALSE
CKA_MODIFIABLE CK_BBOOL CK_FALSE
CKA_LABEL UTF8 "CommScope Public Trust ECC Root-01"
CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
CKA_SUBJECT MULTILINE_OCTAL
\060\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061
\022\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143
\157\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157
\155\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124
\162\165\163\164\040\105\103\103\040\122\157\157\164\055\060\061
END
CKA_ID UTF8 "0"
CKA_ISSUER MULTILINE_OCTAL
\060\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061
\022\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143
\157\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157
\155\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124
\162\165\163\164\040\105\103\103\040\122\157\157\164\055\060\061
END
CKA_SERIAL_NUMBER MULTILINE_OCTAL
\002\024\103\160\202\167\317\115\135\064\361\312\256\062\057\067
\367\364\177\165\240\236
END
CKA_VALUE MULTILINE_OCTAL
\060\202\002\035\060\202\001\243\240\003\002\001\002\002\024\103
\160\202\167\317\115\135\064\361\312\256\062\057\067\367\364\177
\165\240\236\060\012\006\010\052\206\110\316\075\004\003\003\060
\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061\022
\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143\157
\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157\155
\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124\162
\165\163\164\040\105\103\103\040\122\157\157\164\055\060\061\060
\036\027\015\062\061\060\064\062\070\061\067\063\065\064\063\132
\027\015\064\066\060\064\062\070\061\067\063\065\064\062\132\060
\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061\022
\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143\157
\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157\155
\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124\162
\165\163\164\040\105\103\103\040\122\157\157\164\055\060\061\060
\166\060\020\006\007\052\206\110\316\075\002\001\006\005\053\201
\004\000\042\003\142\000\004\113\066\351\256\127\136\250\160\327
\320\217\164\142\167\303\136\172\252\345\266\242\361\170\375\002
\176\127\335\221\171\234\154\271\122\210\124\274\057\004\276\270
\315\366\020\321\051\354\265\320\240\303\360\211\160\031\273\121
\145\305\103\234\303\233\143\235\040\203\076\006\013\246\102\104
\205\021\247\112\072\055\351\326\150\057\110\116\123\053\007\077
\115\275\271\254\167\071\127\243\102\060\100\060\017\006\003\125
\035\023\001\001\377\004\005\060\003\001\001\377\060\016\006\003
\125\035\017\001\001\377\004\004\003\002\001\006\060\035\006\003
\125\035\016\004\026\004\024\216\007\142\300\120\335\306\031\006
\000\106\164\004\367\363\256\175\165\115\060\060\012\006\010\052
\206\110\316\075\004\003\003\003\150\000\060\145\002\061\000\234
\063\337\101\343\043\250\102\066\046\227\065\134\173\353\333\113
\370\252\213\163\125\025\134\254\170\051\017\272\041\330\304\240
\330\321\003\335\155\321\071\075\304\223\140\322\343\162\262\002
\060\174\305\176\210\323\120\365\036\045\350\372\116\165\346\130
\226\244\065\137\033\145\352\141\232\160\043\265\015\243\233\222
\122\157\151\240\214\215\112\320\356\213\016\313\107\216\320\215
\021
END
CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
CKA_NSS_SERVER_DISTRUST_AFTER CK_BBOOL CK_FALSE
CKA_NSS_EMAIL_DISTRUST_AFTER CK_BBOOL CK_FALSE
# Trust for "CommScope Public Trust ECC Root-01"
# Issuer: CN=CommScope Public Trust ECC Root-01,O=CommScope,C=US
# Serial Number:43:70:82:77:cf:4d:5d:34:f1:ca:ae:32:2f:37:f7:f4:7f:75:a0:9e
# Subject: CN=CommScope Public Trust ECC Root-01,O=CommScope,C=US
# Not Valid Before: Wed Apr 28 17:35:43 2021
# Not Valid After : Sat Apr 28 17:35:42 2046
# Fingerprint (SHA-256): 11:43:7C:DA:7B:B4:5E:41:36:5F:45:B3:9A:38:98:6B:0D:E0:0D:EF:34:8E:0C:7B:B0:87:36:33:80:0B:C3:8B
# Fingerprint (SHA1): 07:86:C0:D8:DD:8E:C0:80:98:06:98:D0:58:7A:EF:DE:A6:CC:A2:5D
CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
CKA_TOKEN CK_BBOOL CK_TRUE
CKA_PRIVATE CK_BBOOL CK_FALSE
CKA_MODIFIABLE CK_BBOOL CK_FALSE
CKA_LABEL UTF8 "CommScope Public Trust ECC Root-01"
CKA_CERT_SHA1_HASH MULTILINE_OCTAL
\007\206\300\330\335\216\300\200\230\006\230\320\130\172\357\336
\246\314\242\135
END
CKA_CERT_MD5_HASH MULTILINE_OCTAL
\072\100\247\374\003\214\234\070\171\057\072\242\154\266\012\026
END
CKA_ISSUER MULTILINE_OCTAL
\060\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061
\022\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143
\157\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157
\155\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124
\162\165\163\164\040\105\103\103\040\122\157\157\164\055\060\061
END
CKA_SERIAL_NUMBER MULTILINE_OCTAL
\002\024\103\160\202\167\317\115\135\064\361\312\256\062\057\067
\367\364\177\165\240\236
END
CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
#
# Certificate "CommScope Public Trust ECC Root-02"
#
# Issuer: CN=CommScope Public Trust ECC Root-02,O=CommScope,C=US
# Serial Number:28:fd:99:60:41:47:a6:01:3a:ca:14:7b:1f:ef:f9:68:08:83:5d:7d
# Subject: CN=CommScope Public Trust ECC Root-02,O=CommScope,C=US
# Not Valid Before: Wed Apr 28 17:44:54 2021
# Not Valid After : Sat Apr 28 17:44:53 2046
# Fingerprint (SHA-256): 2F:FB:7F:81:3B:BB:B3:C8:9A:B4:E8:16:2D:0F:16:D7:15:09:A8:30:CC:9D:73:C2:62:E5:14:08:75:D1:AD:4A
# Fingerprint (SHA1): 3C:3F:EF:57:0F:FE:65:93:86:9E:A0:FE:B0:F6:ED:8E:D1:13:C7:E5
CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
CKA_TOKEN CK_BBOOL CK_TRUE
CKA_PRIVATE CK_BBOOL CK_FALSE
CKA_MODIFIABLE CK_BBOOL CK_FALSE
CKA_LABEL UTF8 "CommScope Public Trust ECC Root-02"
CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
CKA_SUBJECT MULTILINE_OCTAL
\060\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061
\022\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143
\157\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157
\155\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124
\162\165\163\164\040\105\103\103\040\122\157\157\164\055\060\062
END
CKA_ID UTF8 "0"
CKA_ISSUER MULTILINE_OCTAL
\060\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061
\022\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143
\157\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157
\155\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124
\162\165\163\164\040\105\103\103\040\122\157\157\164\055\060\062
END
CKA_SERIAL_NUMBER MULTILINE_OCTAL
\002\024\050\375\231\140\101\107\246\001\072\312\024\173\037\357
\371\150\010\203\135\175
END
CKA_VALUE MULTILINE_OCTAL
\060\202\002\034\060\202\001\243\240\003\002\001\002\002\024\050
\375\231\140\101\107\246\001\072\312\024\173\037\357\371\150\010
\203\135\175\060\012\006\010\052\206\110\316\075\004\003\003\060
\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061\022
\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143\157
\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157\155
\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124\162
\165\163\164\040\105\103\103\040\122\157\157\164\055\060\062\060
\036\027\015\062\061\060\064\062\070\061\067\064\064\065\064\132
\027\015\064\066\060\064\062\070\061\067\064\064\065\063\132\060
\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061\022
\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143\157
\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157\155
\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124\162
\165\163\164\040\105\103\103\040\122\157\157\164\055\060\062\060
\166\060\020\006\007\052\206\110\316\075\002\001\006\005\053\201
\004\000\042\003\142\000\004\170\060\201\350\143\036\345\353\161
\121\017\367\007\007\312\071\231\174\116\325\017\314\060\060\013
\217\146\223\076\317\275\305\206\275\371\261\267\264\076\264\007
\310\363\226\061\363\355\244\117\370\243\116\215\051\025\130\270
\325\157\177\356\154\042\265\260\257\110\105\012\275\250\111\224
\277\204\103\260\333\204\112\003\043\031\147\152\157\301\156\274
\006\071\067\321\210\042\367\243\102\060\100\060\017\006\003\125
\035\023\001\001\377\004\005\060\003\001\001\377\060\016\006\003
\125\035\017\001\001\377\004\004\003\002\001\006\060\035\006\003
\125\035\016\004\026\004\024\346\030\165\377\357\140\336\204\244
\365\106\307\336\112\125\343\062\066\171\365\060\012\006\010\052
\206\110\316\075\004\003\003\003\147\000\060\144\002\060\046\163
\111\172\266\253\346\111\364\175\122\077\324\101\004\256\200\103
\203\145\165\271\205\200\070\073\326\157\344\223\206\253\217\347
\211\310\177\233\176\153\012\022\125\141\252\021\340\171\002\060
\167\350\061\161\254\074\161\003\326\204\046\036\024\270\363\073
\073\336\355\131\374\153\114\060\177\131\316\105\351\163\140\025
\232\114\360\346\136\045\042\025\155\302\207\131\320\262\216\152
END
CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
CKA_NSS_SERVER_DISTRUST_AFTER CK_BBOOL CK_FALSE
CKA_NSS_EMAIL_DISTRUST_AFTER CK_BBOOL CK_FALSE
# Trust for "CommScope Public Trust ECC Root-02"
# Issuer: CN=CommScope Public Trust ECC Root-02,O=CommScope,C=US
# Serial Number:28:fd:99:60:41:47:a6:01:3a:ca:14:7b:1f:ef:f9:68:08:83:5d:7d
# Subject: CN=CommScope Public Trust ECC Root-02,O=CommScope,C=US
# Not Valid Before: Wed Apr 28 17:44:54 2021
# Not Valid After : Sat Apr 28 17:44:53 2046
# Fingerprint (SHA-256): 2F:FB:7F:81:3B:BB:B3:C8:9A:B4:E8:16:2D:0F:16:D7:15:09:A8:30:CC:9D:73:C2:62:E5:14:08:75:D1:AD:4A
# Fingerprint (SHA1): 3C:3F:EF:57:0F:FE:65:93:86:9E:A0:FE:B0:F6:ED:8E:D1:13:C7:E5
CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
CKA_TOKEN CK_BBOOL CK_TRUE
CKA_PRIVATE CK_BBOOL CK_FALSE
CKA_MODIFIABLE CK_BBOOL CK_FALSE
CKA_LABEL UTF8 "CommScope Public Trust ECC Root-02"
CKA_CERT_SHA1_HASH MULTILINE_OCTAL
\074\077\357\127\017\376\145\223\206\236\240\376\260\366\355\216
\321\023\307\345
END
CKA_CERT_MD5_HASH MULTILINE_OCTAL
\131\260\104\325\145\115\270\134\125\031\222\002\266\321\224\262
END
CKA_ISSUER MULTILINE_OCTAL
\060\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061
\022\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143
\157\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157
\155\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124
\162\165\163\164\040\105\103\103\040\122\157\157\164\055\060\062
END
CKA_SERIAL_NUMBER MULTILINE_OCTAL
\002\024\050\375\231\140\101\107\246\001\072\312\024\173\037\357
\371\150\010\203\135\175
END
CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
#
# Certificate "CommScope Public Trust RSA Root-01"
#
# Issuer: CN=CommScope Public Trust RSA Root-01,O=CommScope,C=US
# Serial Number:3e:03:49:81:75:16:74:31:8e:4c:ab:d5:c5:90:29:96:c5:39:10:dd
# Subject: CN=CommScope Public Trust RSA Root-01,O=CommScope,C=US
# Not Valid Before: Wed Apr 28 16:45:54 2021
# Not Valid After : Sat Apr 28 16:45:53 2046
# Fingerprint (SHA-256): 02:BD:F9:6E:2A:45:DD:9B:F1:8F:C7:E1:DB:DF:21:A0:37:9B:A3:C9:C2:61:03:44:CF:D8:D6:06:FE:C1:ED:81
# Fingerprint (SHA1): 6D:0A:5F:F7:B4:23:06:B4:85:B3:B7:97:64:FC:AC:75:F5:33:F2:93
CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
CKA_TOKEN CK_BBOOL CK_TRUE
CKA_PRIVATE CK_BBOOL CK_FALSE
CKA_MODIFIABLE CK_BBOOL CK_FALSE
CKA_LABEL UTF8 "CommScope Public Trust RSA Root-01"
CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
CKA_SUBJECT MULTILINE_OCTAL
\060\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061
\022\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143
\157\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157
\155\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124
\162\165\163\164\040\122\123\101\040\122\157\157\164\055\060\061
END
CKA_ID UTF8 "0"
CKA_ISSUER MULTILINE_OCTAL
\060\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061
\022\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143
\157\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157
\155\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124
\162\165\163\164\040\122\123\101\040\122\157\157\164\055\060\061
END
CKA_SERIAL_NUMBER MULTILINE_OCTAL
\002\024\076\003\111\201\165\026\164\061\216\114\253\325\305\220
\051\226\305\071\020\335
END
CKA_VALUE MULTILINE_OCTAL
\060\202\005\154\060\202\003\124\240\003\002\001\002\002\024\076
\003\111\201\165\026\164\061\216\114\253\325\305\220\051\226\305
\071\020\335\060\015\006\011\052\206\110\206\367\015\001\001\013
\005\000\060\116\061\013\060\011\006\003\125\004\006\023\002\125
\123\061\022\060\020\006\003\125\004\012\014\011\103\157\155\155
\123\143\157\160\145\061\053\060\051\006\003\125\004\003\014\042
\103\157\155\155\123\143\157\160\145\040\120\165\142\154\151\143
\040\124\162\165\163\164\040\122\123\101\040\122\157\157\164\055
\060\061\060\036\027\015\062\061\060\064\062\070\061\066\064\065
\065\064\132\027\015\064\066\060\064\062\070\061\066\064\065\065
\063\132\060\116\061\013\060\011\006\003\125\004\006\023\002\125
\123\061\022\060\020\006\003\125\004\012\014\011\103\157\155\155
\123\143\157\160\145\061\053\060\051\006\003\125\004\003\014\042
\103\157\155\155\123\143\157\160\145\040\120\165\142\154\151\143
\040\124\162\165\163\164\040\122\123\101\040\122\157\157\164\055
\060\061\060\202\002\042\060\015\006\011\052\206\110\206\367\015
\001\001\001\005\000\003\202\002\017\000\060\202\002\012\002\202
\002\001\000\260\110\145\243\015\035\102\343\221\155\235\204\244
\141\226\022\302\355\303\332\043\064\031\166\366\352\375\125\132
\366\125\001\123\017\362\314\214\227\117\271\120\313\263\001\104
\126\226\375\233\050\354\173\164\013\347\102\153\125\316\311\141
\262\350\255\100\074\272\271\101\012\005\117\033\046\205\217\103
\265\100\265\205\321\324\161\334\203\101\363\366\105\307\200\242
\204\120\227\106\316\240\014\304\140\126\004\035\007\133\106\245
\016\262\113\244\016\245\174\356\370\324\142\003\271\223\152\212
\024\270\160\370\056\202\106\070\043\016\164\307\153\101\267\320
\051\243\235\200\260\176\167\223\143\102\373\064\203\073\163\243
\132\041\066\353\107\372\030\027\331\272\146\302\223\244\217\374
\135\244\255\374\120\152\225\254\274\044\063\321\275\210\177\206
\365\365\262\163\052\217\174\257\010\362\032\230\077\251\201\145
\077\301\214\211\305\226\060\232\012\317\364\324\310\064\355\235
\057\274\215\070\206\123\356\227\237\251\262\143\224\027\215\017
\334\146\052\174\122\121\165\313\231\216\350\075\134\277\236\073
\050\215\203\002\017\251\237\162\342\054\053\263\334\146\227\000
\100\320\244\124\216\233\135\173\105\066\046\326\162\103\353\317
\300\352\015\334\316\022\346\175\070\237\005\047\250\227\076\351
\121\306\154\005\050\301\002\017\351\030\155\354\275\234\006\324
\247\111\364\124\005\153\154\060\361\353\003\325\352\075\152\166
\302\313\032\050\111\115\177\144\340\372\053\332\163\203\201\377
\221\003\275\224\273\344\270\216\234\062\143\315\237\273\150\201
\261\204\133\257\066\277\167\356\035\177\367\111\233\122\354\322
\167\132\175\221\235\115\302\071\055\344\272\202\370\157\362\116
\036\017\116\346\077\131\245\043\334\075\207\250\050\130\050\321
\361\033\066\333\117\304\377\341\214\133\162\214\307\046\003\047
\243\071\012\001\252\300\262\061\140\203\042\241\117\022\011\001
\021\257\064\324\317\327\256\142\323\005\007\264\061\165\340\015
\155\127\117\151\207\371\127\251\272\025\366\310\122\155\241\313
\234\037\345\374\170\250\065\232\237\101\024\316\245\264\316\224
\010\034\011\255\126\345\332\266\111\232\112\352\143\030\123\234
\054\056\303\002\003\001\000\001\243\102\060\100\060\017\006\003
\125\035\023\001\001\377\004\005\060\003\001\001\377\060\016\006
\003\125\035\017\001\001\377\004\004\003\002\001\006\060\035\006
\003\125\035\016\004\026\004\024\067\135\246\232\164\062\302\302
\371\307\246\025\020\131\270\344\375\345\270\155\060\015\006\011
\052\206\110\206\367\015\001\001\013\005\000\003\202\002\001\000
\257\247\317\336\377\340\275\102\215\115\345\042\226\337\150\352
\175\115\052\175\320\255\075\026\134\103\347\175\300\206\350\172
\065\143\361\314\201\310\306\013\350\056\122\065\244\246\111\220
\143\121\254\064\254\005\073\127\000\351\323\142\323\331\051\325
\124\276\034\020\221\234\262\155\376\131\375\171\367\352\126\320
\236\150\124\102\217\046\122\342\114\337\057\227\246\057\322\007
\230\250\363\140\135\113\232\130\127\210\357\202\345\372\257\154
\201\113\222\217\100\232\223\106\131\313\137\170\026\261\147\076
\102\013\337\050\331\260\255\230\040\276\103\174\321\136\032\011
\027\044\215\173\135\225\351\253\301\140\253\133\030\144\200\373
\255\340\006\175\035\312\131\270\363\170\051\147\306\126\035\257
\266\265\164\052\166\241\077\373\165\060\237\224\136\073\245\140
\363\313\134\014\342\016\311\140\370\311\037\026\212\046\335\347
\047\177\353\045\246\212\275\270\055\066\020\232\261\130\115\232
\150\117\140\124\345\366\106\023\216\210\254\274\041\102\022\255
\306\112\211\175\233\301\330\055\351\226\003\364\242\164\014\274
\000\035\277\326\067\045\147\264\162\213\257\205\275\352\052\003
\217\314\373\074\104\044\202\342\001\245\013\131\266\064\215\062
\013\022\015\353\047\302\375\101\327\100\074\162\106\051\300\214
\352\272\017\361\006\223\056\367\234\250\364\140\076\243\361\070
\136\216\023\301\263\072\227\207\077\222\312\170\251\034\257\320
\260\033\046\036\276\160\354\172\365\063\230\352\134\377\053\013
\004\116\103\335\143\176\016\247\116\170\003\225\076\324\055\060
\225\021\020\050\056\277\240\002\076\377\136\131\323\005\016\225
\137\123\105\357\153\207\325\110\315\026\246\226\203\341\337\263
\006\363\301\024\333\247\354\034\213\135\220\220\015\162\121\347
\141\371\024\312\257\203\217\277\257\261\012\131\135\334\134\327
\344\226\255\133\140\035\332\256\227\262\071\331\006\365\166\000
\023\370\150\114\041\260\065\304\334\125\262\311\301\101\132\034
\211\300\214\157\164\240\153\063\115\265\001\050\375\255\255\211
\027\073\246\232\204\274\353\214\352\304\161\044\250\272\051\371
\010\262\047\126\065\062\137\352\071\373\061\232\325\031\314\360
END
CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
CKA_NSS_SERVER_DISTRUST_AFTER CK_BBOOL CK_FALSE
CKA_NSS_EMAIL_DISTRUST_AFTER CK_BBOOL CK_FALSE
# Trust for "CommScope Public Trust RSA Root-01"
# Issuer: CN=CommScope Public Trust RSA Root-01,O=CommScope,C=US
# Serial Number:3e:03:49:81:75:16:74:31:8e:4c:ab:d5:c5:90:29:96:c5:39:10:dd
# Subject: CN=CommScope Public Trust RSA Root-01,O=CommScope,C=US
# Not Valid Before: Wed Apr 28 16:45:54 2021
# Not Valid After : Sat Apr 28 16:45:53 2046
# Fingerprint (SHA-256): 02:BD:F9:6E:2A:45:DD:9B:F1:8F:C7:E1:DB:DF:21:A0:37:9B:A3:C9:C2:61:03:44:CF:D8:D6:06:FE:C1:ED:81
# Fingerprint (SHA1): 6D:0A:5F:F7:B4:23:06:B4:85:B3:B7:97:64:FC:AC:75:F5:33:F2:93
CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
CKA_TOKEN CK_BBOOL CK_TRUE
CKA_PRIVATE CK_BBOOL CK_FALSE
CKA_MODIFIABLE CK_BBOOL CK_FALSE
CKA_LABEL UTF8 "CommScope Public Trust RSA Root-01"
CKA_CERT_SHA1_HASH MULTILINE_OCTAL
\155\012\137\367\264\043\006\264\205\263\267\227\144\374\254\165
\365\063\362\223
END
CKA_CERT_MD5_HASH MULTILINE_OCTAL
\016\264\025\274\207\143\135\135\002\163\324\046\070\150\163\330
END
CKA_ISSUER MULTILINE_OCTAL
\060\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061
\022\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143
\157\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157
\155\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124
\162\165\163\164\040\122\123\101\040\122\157\157\164\055\060\061
END
CKA_SERIAL_NUMBER MULTILINE_OCTAL
\002\024\076\003\111\201\165\026\164\061\216\114\253\325\305\220
\051\226\305\071\020\335
END
CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
#
# Certificate "CommScope Public Trust RSA Root-02"
#
# Issuer: CN=CommScope Public Trust RSA Root-02,O=CommScope,C=US
# Serial Number:54:16:bf:3b:7e:39:95:71:8d:d1:aa:00:a5:86:0d:2b:8f:7a:05:4e
# Subject: CN=CommScope Public Trust RSA Root-02,O=CommScope,C=US
# Not Valid Before: Wed Apr 28 17:16:43 2021
# Not Valid After : Sat Apr 28 17:16:42 2046
# Fingerprint (SHA-256): FF:E9:43:D7:93:42:4B:4F:7C:44:0C:1C:3D:64:8D:53:63:F3:4B:82:DC:87:AA:7A:9F:11:8F:C5:DE:E1:01:F1
# Fingerprint (SHA1): EA:B0:E2:52:1B:89:93:4C:11:68:F2:D8:9A:AC:22:4C:A3:8A:57:AE
CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
CKA_TOKEN CK_BBOOL CK_TRUE
CKA_PRIVATE CK_BBOOL CK_FALSE
CKA_MODIFIABLE CK_BBOOL CK_FALSE
CKA_LABEL UTF8 "CommScope Public Trust RSA Root-02"
CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
CKA_SUBJECT MULTILINE_OCTAL
\060\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061
\022\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143
\157\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157
\155\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124
\162\165\163\164\040\122\123\101\040\122\157\157\164\055\060\062
END
CKA_ID UTF8 "0"
CKA_ISSUER MULTILINE_OCTAL
\060\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061
\022\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143
\157\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157
\155\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124
\162\165\163\164\040\122\123\101\040\122\157\157\164\055\060\062
END
CKA_SERIAL_NUMBER MULTILINE_OCTAL
\002\024\124\026\277\073\176\071\225\161\215\321\252\000\245\206
\015\053\217\172\005\116
END
CKA_VALUE MULTILINE_OCTAL
\060\202\005\154\060\202\003\124\240\003\002\001\002\002\024\124
\026\277\073\176\071\225\161\215\321\252\000\245\206\015\053\217
\172\005\116\060\015\006\011\052\206\110\206\367\015\001\001\013
\005\000\060\116\061\013\060\011\006\003\125\004\006\023\002\125
\123\061\022\060\020\006\003\125\004\012\014\011\103\157\155\155
\123\143\157\160\145\061\053\060\051\006\003\125\004\003\014\042
\103\157\155\155\123\143\157\160\145\040\120\165\142\154\151\143
\040\124\162\165\163\164\040\122\123\101\040\122\157\157\164\055
\060\062\060\036\027\015\062\061\060\064\062\070\061\067\061\066
\064\063\132\027\015\064\066\060\064\062\070\061\067\061\066\064
\062\132\060\116\061\013\060\011\006\003\125\004\006\023\002\125
\123\061\022\060\020\006\003\125\004\012\014\011\103\157\155\155
\123\143\157\160\145\061\053\060\051\006\003\125\004\003\014\042
\103\157\155\155\123\143\157\160\145\040\120\165\142\154\151\143
\040\124\162\165\163\164\040\122\123\101\040\122\157\157\164\055
\060\062\060\202\002\042\060\015\006\011\052\206\110\206\367\015
\001\001\001\005\000\003\202\002\017\000\060\202\002\012\002\202
\002\001\000\341\372\016\373\150\000\022\310\115\325\254\042\304
\065\001\073\305\124\345\131\166\143\245\177\353\301\304\152\230
\275\062\215\027\200\353\135\272\321\142\075\045\043\031\065\024
\351\177\211\247\033\142\074\326\120\347\064\225\003\062\261\264
\223\042\075\247\342\261\355\346\173\116\056\207\233\015\063\165
\012\336\252\065\347\176\345\066\230\242\256\045\236\225\263\062
\226\244\053\130\036\357\077\376\142\064\110\121\321\264\215\102
\255\140\332\111\152\225\160\335\322\000\342\314\127\143\002\173
\226\335\111\227\133\222\116\225\323\371\313\051\037\030\112\370
\001\052\322\143\011\156\044\351\211\322\345\307\042\114\334\163
\206\107\000\252\015\210\216\256\205\175\112\351\273\063\117\016
\122\160\235\225\343\174\155\226\133\055\075\137\241\203\106\135
\266\343\045\270\174\247\031\200\034\352\145\103\334\221\171\066
\054\164\174\362\147\006\311\211\311\333\277\332\150\277\043\355
\334\153\255\050\203\171\057\354\070\245\015\067\001\147\047\232
\351\063\331\063\137\067\241\305\360\253\075\372\170\260\347\054
\237\366\076\237\140\340\357\110\351\220\105\036\005\121\170\032
\054\022\054\134\050\254\015\242\043\236\064\217\005\346\242\063
\316\021\167\023\324\016\244\036\102\037\206\315\160\376\331\056
\025\075\035\273\270\362\123\127\333\314\306\164\051\234\030\263
\066\165\070\056\017\124\241\370\222\037\211\226\117\273\324\356
\235\351\073\066\102\265\012\073\052\324\144\171\066\020\341\371
\221\003\053\173\040\124\315\015\031\032\310\101\062\064\321\260
\231\341\220\036\001\100\066\265\267\372\251\345\167\165\244\042
\201\135\260\213\344\047\022\017\124\210\306\333\205\164\346\267
\300\327\246\051\372\333\336\363\223\227\047\004\125\057\012\157
\067\305\075\023\257\012\000\251\054\213\034\201\050\327\357\206
\061\251\256\362\156\270\312\152\054\124\107\330\052\210\056\257
\301\007\020\170\254\021\242\057\102\360\067\305\362\270\126\335
\016\142\055\316\055\126\176\125\362\247\104\366\053\062\364\043
\250\107\350\324\052\001\170\317\152\303\067\250\236\145\322\054
\345\372\272\063\301\006\104\366\346\317\245\015\247\146\010\064
\212\054\363\002\003\001\000\001\243\102\060\100\060\017\006\003
\125\035\023\001\001\377\004\005\060\003\001\001\377\060\016\006
\003\125\035\017\001\001\377\004\004\003\002\001\006\060\035\006
\003\125\035\016\004\026\004\024\107\320\347\261\042\377\235\054
\365\331\127\140\263\261\261\160\225\357\141\172\060\015\006\011
\052\206\110\206\367\015\001\001\013\005\000\003\202\002\001\000
\206\151\261\115\057\351\237\117\042\223\150\216\344\041\231\243
\316\105\123\033\163\104\123\000\201\141\315\061\343\010\272\201
\050\050\172\222\271\266\250\310\103\236\307\023\046\115\302\330
\345\125\234\222\135\120\330\302\053\333\376\346\250\227\317\122
\072\044\303\145\144\134\107\061\243\145\065\023\303\223\271\367
\371\121\227\273\244\360\142\207\305\326\006\323\227\203\040\251
\176\273\266\041\302\245\015\204\000\341\362\047\020\203\272\335
\003\201\325\335\150\303\146\020\310\321\166\264\263\157\051\236
\000\371\302\051\365\261\223\031\122\151\032\054\114\240\213\340
\025\232\061\057\323\210\225\131\156\345\304\263\120\310\024\010
\112\233\213\023\203\261\244\162\262\073\166\063\101\334\334\252
\246\007\157\035\044\022\237\310\166\275\057\331\216\364\054\356
\267\322\070\020\044\066\121\057\343\134\135\201\041\247\332\273
\116\377\346\007\250\376\271\015\047\154\273\160\132\125\172\023
\351\361\052\111\151\307\137\207\127\114\103\171\155\072\145\351
\060\134\101\356\353\167\245\163\022\210\350\277\175\256\345\304
\250\037\015\216\034\155\120\002\117\046\030\103\336\217\125\205
\261\013\067\005\140\311\125\071\022\004\241\052\317\161\026\237
\066\121\111\277\160\073\236\147\234\373\173\171\311\071\034\170
\254\167\221\124\232\270\165\012\201\122\227\343\146\141\153\355
\076\070\036\226\141\125\341\221\124\214\355\214\044\037\201\311
\020\232\163\231\053\026\116\162\000\077\124\033\370\215\272\213
\347\024\326\266\105\117\140\354\226\256\303\057\002\116\135\235
\226\111\162\000\262\253\165\134\017\150\133\035\145\302\137\063
\017\036\017\360\073\206\365\260\116\273\234\367\352\045\005\334
\255\242\233\113\027\001\276\102\337\065\041\035\255\253\256\364
\277\256\037\033\323\342\073\374\263\162\163\034\233\050\220\211
\023\075\035\301\000\107\011\226\232\070\033\335\261\317\015\302
\264\104\363\226\225\316\062\072\217\064\234\340\027\307\136\316
\256\015\333\207\070\345\077\133\375\233\031\341\061\101\172\160
\252\043\153\001\341\105\114\315\224\316\073\236\055\347\210\002
\042\364\156\350\310\354\326\074\363\271\262\327\167\172\254\173
END
CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
CKA_NSS_SERVER_DISTRUST_AFTER CK_BBOOL CK_FALSE
CKA_NSS_EMAIL_DISTRUST_AFTER CK_BBOOL CK_FALSE
# Trust for "CommScope Public Trust RSA Root-02"
# Issuer: CN=CommScope Public Trust RSA Root-02,O=CommScope,C=US
# Serial Number:54:16:bf:3b:7e:39:95:71:8d:d1:aa:00:a5:86:0d:2b:8f:7a:05:4e
# Subject: CN=CommScope Public Trust RSA Root-02,O=CommScope,C=US
# Not Valid Before: Wed Apr 28 17:16:43 2021
# Not Valid After : Sat Apr 28 17:16:42 2046
# Fingerprint (SHA-256): FF:E9:43:D7:93:42:4B:4F:7C:44:0C:1C:3D:64:8D:53:63:F3:4B:82:DC:87:AA:7A:9F:11:8F:C5:DE:E1:01:F1
# Fingerprint (SHA1): EA:B0:E2:52:1B:89:93:4C:11:68:F2:D8:9A:AC:22:4C:A3:8A:57:AE
CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
CKA_TOKEN CK_BBOOL CK_TRUE
CKA_PRIVATE CK_BBOOL CK_FALSE
CKA_MODIFIABLE CK_BBOOL CK_FALSE
CKA_LABEL UTF8 "CommScope Public Trust RSA Root-02"
CKA_CERT_SHA1_HASH MULTILINE_OCTAL
\352\260\342\122\033\211\223\114\021\150\362\330\232\254\042\114
\243\212\127\256
END
CKA_CERT_MD5_HASH MULTILINE_OCTAL
\341\051\371\142\173\166\342\226\155\363\324\327\017\256\037\252
END
CKA_ISSUER MULTILINE_OCTAL
\060\116\061\013\060\011\006\003\125\004\006\023\002\125\123\061
\022\060\020\006\003\125\004\012\014\011\103\157\155\155\123\143
\157\160\145\061\053\060\051\006\003\125\004\003\014\042\103\157
\155\155\123\143\157\160\145\040\120\165\142\154\151\143\040\124
\162\165\163\164\040\122\123\101\040\122\157\157\164\055\060\062
END
CKA_SERIAL_NUMBER MULTILINE_OCTAL
\002\024\124\026\277\073\176\071\225\161\215\321\252\000\245\206
\015\053\217\172\005\116
END
CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
#
# Certificate "D-Trust SBR Root CA 1 2022"
#

View File

@@ -3182,96 +3182,6 @@ static struct us_cert_string_t root_certs[] = {
"MvHVI5TWWA==\n"
"-----END CERTIFICATE-----",.len=869},
/* CommScope Public Trust ECC Root-01 */
{.str="-----BEGIN CERTIFICATE-----\n"
"MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMwTjELMAkG\n"
"A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1Ymxp\n"
"YyBUcnVzdCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNaFw00NjA0MjgxNzM1NDJaME4x\n"
"CzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQ\n"
"dWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16o\n"
"cNfQj3Rid8NeeqrltqLxeP0CflfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOc\n"
"w5tjnSCDPgYLpkJEhRGnSjot6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMB\n"
"Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggq\n"
"hkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg2NED3W3R\n"
"OT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liWpDVfG2XqYZpwI7UNo5uSUm9poIyNStDuiw7L\n"
"R47QjRE=\n"
"-----END CERTIFICATE-----",.len=792},
/* CommScope Public Trust ECC Root-02 */
{.str="-----BEGIN CERTIFICATE-----\n"
"MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMwTjELMAkG\n"
"A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1Ymxp\n"
"YyBUcnVzdCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRaFw00NjA0MjgxNzQ0NTNaME4x\n"
"CzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQ\n"
"dWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l\n"
"63FRD/cHB8o5mXxO1Q/MMDALj2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/u\n"
"bCK1sK9IRQq9qEmUv4RDsNuESgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMB\n"
"Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggq\n"
"hkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/nich/m35r\n"
"ChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs73u1Z/GtMMH9ZzkXpc2AVmkzw5l4lIhVtwodZ\n"
"0LKOag==\n"
"-----END CERTIFICATE-----",.len=792},
/* CommScope Public Trust RSA Root-01 */
{.str="-----BEGIN CERTIFICATE-----\n"
"MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQELBQAwTjEL\n"
"MAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1\n"
"YmxpYyBUcnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1NTRaFw00NjA0MjgxNjQ1NTNa\n"
"ME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29w\n"
"ZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3QtMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n"
"AoICAQCwSGWjDR1C45FtnYSkYZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2b\n"
"KOx7dAvnQmtVzslhsuitQDy6uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBW\n"
"BB0HW0alDrJLpA6lfO741GIDuZNqihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3Oj\n"
"WiE260f6GBfZumbCk6SP/F2krfxQapWsvCQz0b2If4b19bJzKo98rwjyGpg/qYFlP8GMicWW\n"
"MJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/cZip8UlF1y5mO6D1cv547KI2DAg+pn3LiLCuz\n"
"3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTifBSeolz7pUcZsBSjBAg/pGG3svZwG1KdJ\n"
"9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/kQO9lLvkuI6cMmPNn7togbGEW682v3fu\n"
"HX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JOHg9O5j9ZpSPcPYeoKFgo0fEbNttPxP/hjFtyjMcm\n"
"AyejOQoBqsCyMWCDIqFPEgkBEa801M/XrmLTBQe0MXXgDW1XT2mH+VepuhX2yFJtocucH+X8\n"
"eKg1mp9BFM6ltM6UCBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\n"
"AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm45P3luG0wDQYJ\n"
"KoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6NWPxzIHI\n"
"xgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQnmhUQo8mUuJM3y+X\n"
"pi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+QgvfKNmwrZggvkN80V4aCRck\n"
"jXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2vtrV0KnahP/t1MJ+UXjulYPPLXAziDslg\n"
"+MkfFoom3ecnf+slpoq9uC02EJqxWE2aaE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0\n"
"DLwAHb/WNyVntHKLr4W96ioDj8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/x\n"
"BpMu95yo9GA+o/E4Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054\n"
"A5U+1C0wlREQKC6/oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHn\n"
"YfkUyq+Dj7+vsQpZXdxc1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVocicCMb3Sg\n"
"azNNtQEo/a2tiRc7ppqEvOuM6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw\n"
"-----END CERTIFICATE-----",.len=1935},
/* CommScope Public Trust RSA Root-02 */
{.str="-----BEGIN CERTIFICATE-----\n"
"MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQELBQAwTjEL\n"
"MAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1\n"
"YmxpYyBUcnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2NDNaFw00NjA0MjgxNzE2NDJa\n"
"ME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29w\n"
"ZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3QtMDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n"
"AoICAQDh+g77aAASyE3VrCLENQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mn\n"
"G2I81lDnNJUDMrG0kyI9p+Kx7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0\n"
"SFHRtI1CrWDaSWqVcN3SAOLMV2MCe5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxz\n"
"hkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2WWy09X6GDRl224yW4fKcZgBzqZUPckXk2LHR88mcG\n"
"yYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rpM9kzXzehxfCrPfp4sOcsn/Y+n2Dg70jpkEUe\n"
"BVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIfhs1w/tkuFT0du7jyU1fbzMZ0KZwYszZ1\n"
"OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5kQMreyBUzQ0ZGshBMjTRsJnhkB4BQDa1\n"
"t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3wNemKfrb3vOTlycEVS8KbzfFPROvCgCpLIscgSjX\n"
"74Yxqa7ybrjKaixUR9gqiC6vwQcQeKwRoi9C8DfF8rhW3Q5iLc4tVn5V8qdE9isy9COoR+jU\n"
"KgF4z2rDN6ieZdIs5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\n"
"AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7GxcJXvYXowDQYJ\n"
"KoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqBKCh6krm2\n"
"qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3+VGXu6TwYofF1gbT\n"
"l4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbymeAPnCKfWxkxlSaRosTKCL4BWa\n"
"MS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3NyqpgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv\n"
"41xdgSGn2rtO/+YHqP65DSdsu3BaVXoT6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u\n"
"5cSoHw2OHG1QAk8mGEPej1WFsQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FU\n"
"mrh1CoFSl+NmYWvtPjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jau\n"
"wy8CTl2dlklyALKrdVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670\n"
"v64fG9PiO/yzcnMcmyiQiRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjl\n"
"P1v9mxnhMUF6cKojawHhRUzNlM47ni3niAIi9G7oyOzWPPO5std3eqx7\n"
"-----END CERTIFICATE-----",.len=1935},
/* Telekom Security TLS ECC Root 2020 */
{.str="-----BEGIN CERTIFICATE-----\n"
"MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQG\n"

View File

@@ -188,6 +188,103 @@ struct us_loop_t *us_create_loop(void *hint, void (*wakeup_cb)(struct us_loop_t
return loop;
}
/* Shared dispatch loop for both us_loop_run and us_loop_run_bun_tick */
static void us_internal_dispatch_ready_polls(struct us_loop_t *loop) {
#ifdef LIBUS_USE_EPOLL
for (loop->current_ready_poll = 0; loop->current_ready_poll < loop->num_ready_polls; loop->current_ready_poll++) {
struct us_poll_t *poll = GET_READY_POLL(loop, loop->current_ready_poll);
if (LIKELY(poll)) {
if (CLEAR_POINTER_TAG(poll) != poll) {
Bun__internal_dispatch_ready_poll(loop, poll);
continue;
}
int events = loop->ready_polls[loop->current_ready_poll].events;
const int error = events & EPOLLERR;
const int eof = events & EPOLLHUP;
events &= us_poll_events(poll);
if (events || error || eof) {
us_internal_dispatch_ready_poll(poll, error, eof, events);
}
}
}
#else
/* Kqueue delivers each filter (READ, WRITE, TIMER, etc.) as a separate kevent,
* so the same fd/poll can appear twice in ready_polls. We coalesce them into a
* single set of flags per poll before dispatching, matching epoll's behavior
* where each fd appears once with a combined bitmask. */
struct kevent_flags {
uint8_t readable : 1;
uint8_t writable : 1;
uint8_t error : 1;
uint8_t eof : 1;
uint8_t skip : 1;
uint8_t _pad : 3;
};
_Static_assert(sizeof(struct kevent_flags) == 1, "kevent_flags must be 1 byte");
struct kevent_flags coalesced[LIBUS_MAX_READY_POLLS]; /* no zeroing needed — every index is written in the first pass */
/* First pass: decode kevents and coalesce same-poll entries */
for (int i = 0; i < loop->num_ready_polls; i++) {
struct us_poll_t *poll = GET_READY_POLL(loop, i);
if (!poll || CLEAR_POINTER_TAG(poll) != poll) {
coalesced[i] = (struct kevent_flags){ .skip = 1 };
continue;
}
const int16_t filter = loop->ready_polls[i].filter;
const uint16_t flags = loop->ready_polls[i].flags;
struct kevent_flags bits = {
.readable = (filter == EVFILT_READ || filter == EVFILT_TIMER || filter == EVFILT_MACHPORT),
.writable = (filter == EVFILT_WRITE),
.error = !!(flags & EV_ERROR),
.eof = !!(flags & EV_EOF),
};
/* Look backward for a prior entry with the same poll to coalesce into.
* Kqueue returns at most 2 kevents per fd (READ + WRITE). */
int merged = 0;
for (int j = i - 1; j >= 0; j--) {
if (!coalesced[j].skip && GET_READY_POLL(loop, j) == poll) {
coalesced[j].readable |= bits.readable;
coalesced[j].writable |= bits.writable;
coalesced[j].error |= bits.error;
coalesced[j].eof |= bits.eof;
coalesced[i] = (struct kevent_flags){ .skip = 1 };
merged = 1;
break;
}
}
if (!merged) {
coalesced[i] = bits;
}
}
/* Second pass: dispatch everything in order — tagged pointers and coalesced events */
for (loop->current_ready_poll = 0; loop->current_ready_poll < loop->num_ready_polls; loop->current_ready_poll++) {
struct us_poll_t *poll = GET_READY_POLL(loop, loop->current_ready_poll);
if (!poll) continue;
/* Tagged pointers (FilePoll) go through Bun's own dispatch */
if (CLEAR_POINTER_TAG(poll) != poll) {
Bun__internal_dispatch_ready_poll(loop, poll);
continue;
}
struct kevent_flags bits = coalesced[loop->current_ready_poll];
if (bits.skip) continue;
int events = (bits.readable ? LIBUS_SOCKET_READABLE : 0)
| (bits.writable ? LIBUS_SOCKET_WRITABLE : 0);
events &= us_poll_events(poll);
if (events || bits.error || bits.eof) {
us_internal_dispatch_ready_poll(poll, bits.error, bits.eof, events);
}
}
#endif
}
void us_loop_run(struct us_loop_t *loop) {
us_loop_integrate(loop);
@@ -205,41 +302,7 @@ void us_loop_run(struct us_loop_t *loop) {
} while (IS_EINTR(loop->num_ready_polls));
#endif
/* Iterate ready polls, dispatching them by type */
for (loop->current_ready_poll = 0; loop->current_ready_poll < loop->num_ready_polls; loop->current_ready_poll++) {
struct us_poll_t *poll = GET_READY_POLL(loop, loop->current_ready_poll);
/* Any ready poll marked with nullptr will be ignored */
if (LIKELY(poll)) {
if (CLEAR_POINTER_TAG(poll) != poll) {
Bun__internal_dispatch_ready_poll(loop, poll);
continue;
}
#ifdef LIBUS_USE_EPOLL
int events = loop->ready_polls[loop->current_ready_poll].events;
const int error = events & EPOLLERR;
const int eof = events & EPOLLHUP;
#else
const struct kevent64_s* current_kevent = &loop->ready_polls[loop->current_ready_poll];
const int16_t filter = current_kevent->filter;
const uint16_t flags = current_kevent->flags;
const uint32_t fflags = current_kevent->fflags;
// > Multiple events which trigger the filter do not result in multiple kevents being placed on the kqueue
// > Instead, the filter will aggregate the events into a single kevent struct
// Note: EV_ERROR only sets the error in data as part of changelist. Not in this call!
int events = 0
| ((filter == EVFILT_READ) ? LIBUS_SOCKET_READABLE : 0)
| ((filter == EVFILT_WRITE) ? LIBUS_SOCKET_WRITABLE : 0);
const int error = (flags & (EV_ERROR)) ? ((int)fflags || 1) : 0;
const int eof = (flags & (EV_EOF));
#endif
/* Always filter all polls by what they actually poll for (callback polls always poll for readable) */
events &= us_poll_events(poll);
if (events || error || eof) {
us_internal_dispatch_ready_poll(poll, error, eof, events);
}
}
}
us_internal_dispatch_ready_polls(loop);
/* Emit post callback */
us_internal_loop_post(loop);
@@ -263,57 +326,33 @@ void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout
/* Emit pre callback */
us_internal_loop_pre(loop);
if (loop->data.jsc_vm)
const unsigned int had_wakeups = __atomic_exchange_n(&loop->pending_wakeups, 0, __ATOMIC_ACQUIRE);
const int will_idle_inside_event_loop = had_wakeups == 0 && (!timeout || (timeout->tv_nsec != 0 || timeout->tv_sec != 0));
if (will_idle_inside_event_loop && loop->data.jsc_vm)
Bun__JSC_onBeforeWait(loop->data.jsc_vm);
/* Fetch ready polls */
#ifdef LIBUS_USE_EPOLL
/* A zero timespec already has a fast path in ep_poll (fs/eventpoll.c):
* it sets timed_out=1 (line 1952) and returns before any scheduler
* interaction (line 1975). No equivalent of KEVENT_FLAG_IMMEDIATE needed. */
loop->num_ready_polls = bun_epoll_pwait2(loop->fd, loop->ready_polls, 1024, timeout);
#else
do {
loop->num_ready_polls = kevent64(loop->fd, NULL, 0, loop->ready_polls, 1024, 0, timeout);
loop->num_ready_polls = kevent64(loop->fd, NULL, 0, loop->ready_polls, 1024,
/* When we won't idle (pending wakeups or zero timeout), use KEVENT_FLAG_IMMEDIATE.
* In XNU's kqueue_scan (bsd/kern/kern_event.c):
* - KEVENT_FLAG_IMMEDIATE: returns immediately after kqueue_process() (line 8031)
* - Zero timespec without the flag: falls through to assert_wait_deadline (line 8039)
* and thread_block (line 8048), doing a full context switch cycle (~14us) even
* though the deadline is already in the past. */
will_idle_inside_event_loop ? 0 : KEVENT_FLAG_IMMEDIATE,
timeout);
} while (IS_EINTR(loop->num_ready_polls));
#endif
/* Iterate ready polls, dispatching them by type */
for (loop->current_ready_poll = 0; loop->current_ready_poll < loop->num_ready_polls; loop->current_ready_poll++) {
struct us_poll_t *poll = GET_READY_POLL(loop, loop->current_ready_poll);
/* Any ready poll marked with nullptr will be ignored */
if (LIKELY(poll)) {
if (CLEAR_POINTER_TAG(poll) != poll) {
Bun__internal_dispatch_ready_poll(loop, poll);
continue;
}
#ifdef LIBUS_USE_EPOLL
int events = loop->ready_polls[loop->current_ready_poll].events;
const int error = events & EPOLLERR;
const int eof = events & EPOLLHUP;
#else
const struct kevent64_s* current_kevent = &loop->ready_polls[loop->current_ready_poll];
const int16_t filter = current_kevent->filter;
const uint16_t flags = current_kevent->flags;
const uint32_t fflags = current_kevent->fflags;
// > Multiple events which trigger the filter do not result in multiple kevents being placed on the kqueue
// > Instead, the filter will aggregate the events into a single kevent struct
int events = 0
| ((filter & EVFILT_READ) ? LIBUS_SOCKET_READABLE : 0)
| ((filter & EVFILT_WRITE) ? LIBUS_SOCKET_WRITABLE : 0);
// Note: EV_ERROR only sets the error in data as part of changelist. Not in this call!
const int error = (flags & (EV_ERROR)) ? ((int)fflags || 1) : 0;
const int eof = (flags & (EV_EOF));
#endif
/* Always filter all polls by what they actually poll for (callback polls always poll for readable) */
events &= us_poll_events(poll);
if (events || error || eof) {
us_internal_dispatch_ready_poll(poll, error, eof, events);
}
}
}
us_internal_dispatch_ready_polls(loop);
/* Emit post callback */
us_internal_loop_post(loop);
@@ -613,7 +652,7 @@ struct us_internal_async *us_internal_create_async(struct us_loop_t *loop, int f
struct us_internal_callback_t *cb = (struct us_internal_callback_t *) p;
cb->loop = loop;
cb->cb_expects_the_loop = 1;
cb->leave_poll_ready = 0;
cb->leave_poll_ready = 1; /* Edge-triggered: skip reading eventfd on wakeup */
return (struct us_internal_async *) cb;
}
@@ -635,12 +674,28 @@ void us_internal_async_set(struct us_internal_async *a, void (*cb)(struct us_int
internal_cb->cb = (void (*)(struct us_internal_callback_t *)) cb;
us_poll_start((struct us_poll_t *) a, internal_cb->loop, LIBUS_SOCKET_READABLE);
#ifdef LIBUS_USE_EPOLL
/* Upgrade to edge-triggered to avoid reading the eventfd on each wakeup */
struct epoll_event event;
event.events = EPOLLIN | EPOLLET;
event.data.ptr = (struct us_poll_t *) a;
epoll_ctl(internal_cb->loop->fd, EPOLL_CTL_MOD,
us_poll_fd((struct us_poll_t *) a), &event);
#endif
}
void us_internal_async_wakeup(struct us_internal_async *a) {
uint64_t one = 1;
int written = write(us_poll_fd((struct us_poll_t *) a), &one, 8);
(void)written;
int fd = us_poll_fd((struct us_poll_t *) a);
uint64_t val;
for (val = 1; ; val = 1) {
if (write(fd, &val, 8) >= 0) return;
if (errno == EINTR) continue;
if (errno == EAGAIN) {
/* Counter overflow — drain and retry */
if (read(fd, &val, 8) > 0 || errno == EAGAIN || errno == EINTR) continue;
}
break;
}
}
#else

View File

@@ -54,6 +54,10 @@ struct us_loop_t {
/* Number of polls owned by bun */
unsigned int bun_polls;
/* Incremented atomically by wakeup(), swapped to 0 before epoll/kqueue.
* If non-zero, the event loop will return immediately so we can skip the GC safepoint. */
unsigned int pending_wakeups;
/* The list of ready polls */
#ifdef LIBUS_USE_EPOLL
alignas(LIBUS_EXT_ALIGNMENT) struct epoll_event ready_polls[1024];

View File

@@ -93,6 +93,9 @@ void us_internal_loop_data_free(struct us_loop_t *loop) {
}
void us_wakeup_loop(struct us_loop_t *loop) {
#ifndef LIBUS_USE_LIBUV
__atomic_fetch_add(&loop->pending_wakeups, 1, __ATOMIC_RELEASE);
#endif
us_internal_async_wakeup(loop->data.wakeup_async);
}
@@ -393,8 +396,12 @@ void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int eof, in
if (events & LIBUS_SOCKET_WRITABLE && !error) {
s->flags.last_write_failed = 0;
#ifdef LIBUS_USE_KQUEUE
/* Kqueue is one-shot so is not writable anymore */
p->state.poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0);
/* Kqueue EVFILT_WRITE is one-shot so the filter is removed after delivery.
* Clear POLLING_OUT to reflect this.
* Keep POLLING_IN from the poll's own state, NOT from `events`: kqueue delivers
* each filter as a separate kevent, so a pure EVFILT_WRITE event won't have
* LIBUS_SOCKET_READABLE set even though the socket is still registered for reads. */
p->state.poll_type = us_internal_poll_type(p) | (p->state.poll_type & POLL_TYPE_POLLING_IN);
#endif
s = s->context->on_writable(s);
@@ -412,7 +419,7 @@ void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int eof, in
us_poll_change(&s->p, loop, us_poll_events(&s->p) & LIBUS_SOCKET_READABLE);
} else {
#ifdef LIBUS_USE_KQUEUE
/* Kqueue one-shot writable needs to be re-enabled */
/* Kqueue one-shot writable needs to be re-registered */
us_poll_change(&s->p, loop, us_poll_events(&s->p) | LIBUS_SOCKET_WRITABLE);
#endif
}

View File

@@ -204,26 +204,38 @@ namespace uWS {
}
// do we have data to emit all?
if (data.length() >= chunkSize(state)) {
unsigned int remaining = chunkSize(state);
if (data.length() >= remaining) {
// emit all but 2 bytes then reset state to 0 and goto beginning
// not fin
std::string_view emitSoon;
bool shouldEmit = false;
if (chunkSize(state) > 2) {
emitSoon = std::string_view(data.data(), chunkSize(state) - 2);
shouldEmit = true;
// Validate the chunk terminator (\r\n) accounting for partial reads
switch (remaining) {
default:
// remaining > 2: emit data and validate full terminator
emitSoon = std::string_view(data.data(), remaining - 2);
shouldEmit = true;
[[fallthrough]];
case 2:
// remaining >= 2: validate both \r and \n
if (data[remaining - 2] != '\r' || data[remaining - 1] != '\n') {
state = STATE_IS_ERROR;
return std::nullopt;
}
break;
case 1:
// remaining == 1: only \n left to validate
if (data[0] != '\n') {
state = STATE_IS_ERROR;
return std::nullopt;
}
break;
case 0:
// remaining == 0: terminator already consumed
break;
}
// Validate that the chunk terminator is \r\n to prevent request smuggling
// The last 2 bytes of the chunk must be exactly \r\n
// Note: chunkSize always includes +2 for the terminator (added in consumeHexNumber),
// and chunks with size 0 (chunkSize == 2) are handled earlier at line 190.
// Therefore chunkSize >= 3 here, so no underflow is possible.
size_t terminatorOffset = chunkSize(state) - 2;
if (data[terminatorOffset] != '\r' || data[terminatorOffset + 1] != '\n') {
state = STATE_IS_ERROR;
return std::nullopt;
}
data.remove_prefix(chunkSize(state));
data.remove_prefix(remaining);
state = STATE_IS_CHUNKED;
if (shouldEmit) {
return emitSoon;
@@ -232,19 +244,45 @@ namespace uWS {
} else {
/* We will consume all our input data */
std::string_view emitSoon;
if (chunkSize(state) > 2) {
uint64_t maximalAppEmit = chunkSize(state) - 2;
if (data.length() > maximalAppEmit) {
unsigned int size = chunkSize(state);
size_t len = data.length();
if (size > 2) {
uint64_t maximalAppEmit = size - 2;
if (len > maximalAppEmit) {
emitSoon = data.substr(0, maximalAppEmit);
// Validate terminator bytes being consumed
size_t terminatorBytesConsumed = len - maximalAppEmit;
if (terminatorBytesConsumed >= 1 && data[maximalAppEmit] != '\r') {
state = STATE_IS_ERROR;
return std::nullopt;
}
if (terminatorBytesConsumed >= 2 && data[maximalAppEmit + 1] != '\n') {
state = STATE_IS_ERROR;
return std::nullopt;
}
} else {
//cb(data);
emitSoon = data;
}
} else if (size == 2) {
// Only terminator bytes remain, validate what we have
if (len >= 1 && data[0] != '\r') {
state = STATE_IS_ERROR;
return std::nullopt;
}
if (len >= 2 && data[1] != '\n') {
state = STATE_IS_ERROR;
return std::nullopt;
}
} else if (size == 1) {
// Only \n remains
if (data[0] != '\n') {
state = STATE_IS_ERROR;
return std::nullopt;
}
}
decChunkSize(state, (unsigned int) data.length());
decChunkSize(state, (unsigned int) len);
state |= STATE_IS_CHUNKED;
// new: decrease data by its size (bug)
data.remove_prefix(data.length()); // ny bug fix för getNextChunk
data.remove_prefix(len);
if (emitSoon.length()) {
return emitSoon;
} else {

View File

@@ -566,8 +566,10 @@ namespace uWS
bool isHTTPMethod = (__builtin_expect(data[1] == '/', 1));
bool isConnect = !isHTTPMethod && (isHTTPorHTTPSPrefixForProxies(data + 1, end) == 1 || ((data - start) == 7 && memcmp(start, "CONNECT", 7) == 0));
if (isHTTPMethod || isConnect) [[likely]] {
bool isConnect = !isHTTPMethod && ((data - start) == 7 && memcmp(start, "CONNECT", 7) == 0);
/* Also accept proxy-style absolute URLs (http://... or https://...) as valid request targets */
bool isProxyStyleURL = !isHTTPMethod && !isConnect && data[0] == 32 && isHTTPorHTTPSPrefixForProxies(data + 1, end) == 1;
if (isHTTPMethod || isConnect || isProxyStyleURL) [[likely]] {
header.key = {start, (size_t) (data - start)};
data++;
if(!isValidMethod(header.key, useStrictMethodValidation)) {

View File

@@ -1,4 +1,4 @@
# Version: 11
# Version: 12
# A script that installs the dependencies needed to build and test Bun.
# This should work on Windows 10 or newer with PowerShell.
@@ -387,7 +387,7 @@ function Install-PdbAddr2line {
function Install-Llvm {
Install-Package llvm `
-Command clang-cl `
-Version "19.1.7"
-Version "21.1.8"
Add-To-Path "$env:ProgramFiles\LLVM\bin"
}

View File

@@ -1,5 +1,5 @@
#!/bin/sh
# Version: 26
# Version: 28
# A script that installs the dependencies needed to build and test Bun.
# This should work on macOS and Linux with a POSIX shell.
@@ -1061,6 +1061,11 @@ install_build_essentials() {
go \
xz
install_packages apache2-utils
# QEMU user-mode for baseline CPU verification in CI
case "$arch" in
x64) install_packages qemu-x86_64 ;;
aarch64) install_packages qemu-aarch64 ;;
esac
;;
esac
@@ -1091,7 +1096,7 @@ install_build_essentials() {
}
llvm_version_exact() {
print "19.1.7"
print "21.1.8"
}
llvm_version() {
@@ -1101,23 +1106,20 @@ llvm_version() {
install_llvm() {
case "$pm" in
apt)
# Debian 13 (Trixie) has LLVM 19 natively, and apt.llvm.org doesn't have a trixie repo
if [ "$distro" = "debian" ]; then
install_packages \
"llvm-$(llvm_version)" \
"clang-$(llvm_version)" \
"lld-$(llvm_version)" \
"llvm-$(llvm_version)-dev" \
"llvm-$(llvm_version)-tools" \
"libclang-rt-$(llvm_version)-dev"
else
bash="$(require bash)"
llvm_script="$(download_file "https://apt.llvm.org/llvm.sh")"
execute_sudo "$bash" "$llvm_script" "$(llvm_version)" all
# Install llvm-symbolizer explicitly to ensure it's available for ASAN
install_packages "llvm-$(llvm_version)-tools"
# apt.llvm.org's GPG key uses SHA1, which Debian 13+ (sqv) rejects since 2026-02-01.
# Override the sequoia crypto policy to extend the SHA1 deadline.
# See: https://github.com/llvm/llvm-project/issues/153385
if [ -x /usr/bin/sqv ] && [ -f /usr/share/apt/default-sequoia.config ]; then
execute_sudo mkdir -p /etc/crypto-policies/back-ends
execute_sudo /usr/bin/sh -c "sed 's/sha1.second_preimage_resistance = 2026-02-01/sha1.second_preimage_resistance = 2028-02-01/' /usr/share/apt/default-sequoia.config > /etc/crypto-policies/back-ends/apt-sequoia.config"
fi
bash="$(require bash)"
llvm_script="$(download_file "https://apt.llvm.org/llvm.sh")"
execute_sudo "$bash" "$llvm_script" "$(llvm_version)" all
# Install llvm-symbolizer explicitly to ensure it's available for ASAN
install_packages "llvm-$(llvm_version)-tools"
;;
brew)
install_packages "llvm@$(llvm_version)"
@@ -1172,7 +1174,7 @@ install_gcc() {
;;
esac
llvm_v="19"
llvm_v="21"
append_to_profile "export CC=clang-${llvm_v}"
append_to_profile "export CXX=clang++-${llvm_v}"

View File

@@ -77,10 +77,10 @@ const HAS_CCACHE = CCACHE !== null;
// On Windows, use clang-cl for MSVC compatibility
const CC_BASE = IS_WINDOWS
? findExecutable(["clang-cl.exe", "clang-cl"]) || "clang-cl"
: findExecutable(["clang-19", "clang"]) || "clang";
: findExecutable(["clang-21", "clang"]) || "clang";
const CXX_BASE = IS_WINDOWS
? findExecutable(["clang-cl.exe", "clang-cl"]) || "clang-cl"
: findExecutable(["clang++-19", "clang++"]) || "clang++";
: findExecutable(["clang++-21", "clang++"]) || "clang++";
const CC = HAS_CCACHE ? CCACHE : CC_BASE;
const CXX = HAS_CCACHE ? CCACHE : CXX_BASE;
@@ -129,6 +129,7 @@ const getCommonFlags = (config: BuildConfig) => {
"-DBUN_FAST_TLS=ON",
"-DPTHREAD_JIT_PERMISSIONS_API=1",
"-DUSE_PTHREAD_JIT_PERMISSIONS_API=ON",
"-DENABLE_REMOTE_INSPECTOR=ON",
);
} else if (IS_LINUX) {
flags.push(
@@ -172,7 +173,6 @@ const getBuildFlags = (config: BuildConfig) => {
"-DCMAKE_BUILD_TYPE=Debug",
"-DENABLE_BUN_SKIP_FAILING_ASSERTIONS=ON",
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
"-DENABLE_REMOTE_INSPECTOR=ON",
"-DUSE_VISIBILITY_ATTRIBUTE=1",
);

View File

@@ -57,7 +57,11 @@ async function build(args) {
if (process.platform === "win32" && !process.env["VSINSTALLDIR"]) {
const shellPath = join(import.meta.dirname, "vs-shell.ps1");
const scriptPath = import.meta.filename;
return spawn("pwsh", ["-NoProfile", "-NoLogo", "-File", shellPath, process.argv0, scriptPath, ...args]);
// When cross-compiling to ARM64, tell vs-shell.ps1 to set up the x64_arm64 VS environment
const toolchainIdx = args.indexOf("--toolchain");
const requestedVsArch = toolchainIdx !== -1 && args[toolchainIdx + 1] === "windows-aarch64" ? "arm64" : undefined;
const env = requestedVsArch ? { ...process.env, BUN_VS_ARCH: requestedVsArch } : undefined;
return spawn("pwsh", ["-NoProfile", "-NoLogo", "-File", shellPath, process.argv0, scriptPath, ...args], { env });
}
if (isCI) {
@@ -92,21 +96,9 @@ async function build(args) {
generateOptions["--toolchain"] = toolchainPath;
}
// Windows ARM64: automatically set required options
// Windows ARM64: log detection (compiler is selected by CMake/toolchain)
if (isWindowsARM64) {
// Use clang-cl instead of MSVC cl.exe for proper ARM64 flag support
if (!generateOptions["-DCMAKE_C_COMPILER"]) {
generateOptions["-DCMAKE_C_COMPILER"] = "clang-cl";
}
if (!generateOptions["-DCMAKE_CXX_COMPILER"]) {
generateOptions["-DCMAKE_CXX_COMPILER"] = "clang-cl";
}
// Skip codegen by default since x64 bun crashes under WoW64 emulation
// Can be overridden with -DSKIP_CODEGEN=OFF once ARM64 bun is available
if (!generateOptions["-DSKIP_CODEGEN"]) {
generateOptions["-DSKIP_CODEGEN"] = "ON";
}
console.log("Windows ARM64 detected: using clang-cl and SKIP_CODEGEN=ON");
console.log("Windows ARM64 detected");
}
const generateArgs = Object.entries(generateOptions).flatMap(([flag, value]) =>

View File

@@ -12,7 +12,7 @@ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
MODE="${1:-format}"
# Use LLVM_VERSION_MAJOR from environment or default to 19
LLVM_VERSION="${LLVM_VERSION_MAJOR:-19}"
LLVM_VERSION="${LLVM_VERSION_MAJOR:-21}"
# Ensure we have the specific clang-format version
CLANG_FORMAT="clang-format-${LLVM_VERSION}"

100
scripts/verify-baseline-cpu.sh Executable file
View File

@@ -0,0 +1,100 @@
#!/usr/bin/env bash
set -euo pipefail
# Verify that a Bun binary doesn't use CPU instructions beyond its baseline target.
# Uses QEMU user-mode emulation with restricted CPU features.
# Any illegal instruction (SIGILL) causes exit code 132 and fails the build.
#
# QEMU must be pre-installed in the CI image (see .buildkite/Dockerfile and
# scripts/bootstrap.sh).
ARCH=""
BINARY=""
while [[ $# -gt 0 ]]; do
case $1 in
--arch) ARCH="$2"; shift 2 ;;
--binary) BINARY="$2"; shift 2 ;;
*) echo "Unknown arg: $1"; exit 1 ;;
esac
done
if [ -z "$ARCH" ] || [ -z "$BINARY" ]; then
echo "Usage: $0 --arch <x64|aarch64> --binary <path>"
exit 1
fi
if [ ! -f "$BINARY" ]; then
echo "ERROR: Binary not found: $BINARY"
exit 1
fi
# Select QEMU binary and CPU model
HOST_ARCH=$(uname -m)
if [ "$ARCH" = "x64" ]; then
QEMU_BIN="qemu-x86_64"
if [ -f "/usr/bin/qemu-x86_64-static" ]; then
QEMU_BIN="qemu-x86_64-static"
fi
QEMU_CPU="Nehalem"
CPU_DESC="Nehalem (SSE4.2, no AVX/AVX2/AVX512)"
elif [ "$ARCH" = "aarch64" ]; then
QEMU_BIN="qemu-aarch64"
if [ -f "/usr/bin/qemu-aarch64-static" ]; then
QEMU_BIN="qemu-aarch64-static"
fi
# cortex-a53 is ARMv8.0-A (no LSE atomics, no SVE). It's the most widely
# supported ARMv8.0 model across QEMU versions.
QEMU_CPU="cortex-a53"
CPU_DESC="Cortex-A53 (ARMv8.0-A+CRC, no LSE/SVE)"
else
echo "ERROR: Unknown arch: $ARCH"
exit 1
fi
if ! command -v "$QEMU_BIN" &>/dev/null; then
echo "ERROR: $QEMU_BIN not found. It must be pre-installed in the CI image."
exit 1
fi
BINARY_NAME=$(basename "$BINARY")
echo "--- Verifying $BINARY_NAME on $CPU_DESC"
echo " Binary: $BINARY"
echo " QEMU: $QEMU_BIN -cpu $QEMU_CPU"
echo " Host: $HOST_ARCH"
echo ""
run_test() {
local label="$1"
shift
echo "+++ $BINARY_NAME: $label"
if "$QEMU_BIN" -cpu "$QEMU_CPU" "$@"; then
echo " PASS"
return 0
else
local exit_code=$?
echo ""
if [ $exit_code -eq 132 ]; then
echo " FAIL: Illegal instruction (SIGILL)"
echo ""
echo " The $BINARY_NAME binary uses CPU instructions not available on $QEMU_CPU."
if [ "$ARCH" = "x64" ]; then
echo " The baseline x64 build targets Nehalem (SSE4.2)."
echo " AVX, AVX2, and AVX512 instructions are not allowed."
else
echo " The aarch64 build targets Cortex-A53 (ARMv8.0-A+CRC)."
echo " LSE atomics, SVE, and dotprod instructions are not allowed."
fi
else
echo " FAIL: exit code $exit_code"
fi
exit $exit_code
fi
}
run_test "bun --version" "$BINARY" --version
run_test "bun -e eval" "$BINARY" -e "console.log(JSON.stringify({ok:1+1}))"
echo ""
echo " All checks passed for $BINARY_NAME on $QEMU_CPU."

148
scripts/verify-jit-stress-qemu.sh Executable file
View File

@@ -0,0 +1,148 @@
#!/usr/bin/env bash
set -euo pipefail
# Run JSC JIT stress tests under QEMU to verify that JIT-compiled code
# doesn't use CPU instructions beyond the baseline target.
#
# This script exercises all JIT tiers (DFG, FTL, Wasm BBQ/OMG) and catches
# cases where JIT-generated code emits AVX instructions on x64 or LSE
# atomics on aarch64.
#
# See: test/js/bun/jsc-stress/ for the test fixtures.
ARCH=""
BINARY=""
while [[ $# -gt 0 ]]; do
case $1 in
--arch) ARCH="$2"; shift 2 ;;
--binary) BINARY="$2"; shift 2 ;;
*) echo "Unknown arg: $1"; exit 1 ;;
esac
done
if [ -z "$ARCH" ] || [ -z "$BINARY" ]; then
echo "Usage: $0 --arch <x64|aarch64> --binary <path>"
exit 1
fi
if [ ! -f "$BINARY" ]; then
echo "ERROR: Binary not found: $BINARY"
exit 1
fi
# Convert to absolute path for use after pushd
BINARY="$(cd "$(dirname "$BINARY")" && pwd)/$(basename "$BINARY")"
# Select QEMU binary and CPU model
if [ "$ARCH" = "x64" ]; then
QEMU_BIN="qemu-x86_64"
if [ -f "/usr/bin/qemu-x86_64-static" ]; then
QEMU_BIN="qemu-x86_64-static"
fi
QEMU_CPU="Nehalem"
CPU_DESC="Nehalem (SSE4.2, no AVX/AVX2/AVX512)"
elif [ "$ARCH" = "aarch64" ]; then
QEMU_BIN="qemu-aarch64"
if [ -f "/usr/bin/qemu-aarch64-static" ]; then
QEMU_BIN="qemu-aarch64-static"
fi
QEMU_CPU="cortex-a53"
CPU_DESC="Cortex-A53 (ARMv8.0-A+CRC, no LSE/SVE)"
else
echo "ERROR: Unknown arch: $ARCH"
exit 1
fi
if ! command -v "$QEMU_BIN" &>/dev/null; then
echo "ERROR: $QEMU_BIN not found. It must be pre-installed in the CI image."
exit 1
fi
BINARY_NAME=$(basename "$BINARY")
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
FIXTURES_DIR="$REPO_ROOT/test/js/bun/jsc-stress/fixtures"
WASM_FIXTURES_DIR="$FIXTURES_DIR/wasm"
PRELOAD_PATH="$REPO_ROOT/test/js/bun/jsc-stress/preload.js"
echo "--- Running JSC JIT stress tests on $CPU_DESC"
echo " Binary: $BINARY"
echo " QEMU: $QEMU_BIN -cpu $QEMU_CPU"
echo ""
SIGILL_FAILURES=0
OTHER_FAILURES=0
PASSED=0
run_fixture() {
local fixture="$1"
local fixture_name
fixture_name=$(basename "$fixture")
echo "+++ $fixture_name"
if "$QEMU_BIN" -cpu "$QEMU_CPU" "$BINARY" --preload "$PRELOAD_PATH" "$fixture" 2>&1; then
echo " PASS"
((PASSED++))
return 0
else
local exit_code=$?
if [ $exit_code -eq 132 ]; then
echo " FAIL: Illegal instruction (SIGILL)"
echo ""
echo " JIT-compiled code in $fixture_name uses CPU instructions not available on $QEMU_CPU."
if [ "$ARCH" = "x64" ]; then
echo " The baseline x64 build targets Nehalem (SSE4.2)."
echo " JIT must not emit AVX, AVX2, or AVX512 instructions."
else
echo " The aarch64 build targets Cortex-A53 (ARMv8.0-A+CRC)."
echo " JIT must not emit LSE atomics, SVE, or dotprod instructions."
fi
((SIGILL_FAILURES++))
else
# Non-SIGILL failures are warnings (test issues, not CPU instruction issues)
echo " WARN: exit code $exit_code (not a CPU instruction issue)"
((OTHER_FAILURES++))
fi
return $exit_code
fi
}
# Run JS fixtures (DFG/FTL)
echo "--- JS fixtures (DFG/FTL)"
for fixture in "$FIXTURES_DIR"/*.js; do
if [ -f "$fixture" ]; then
run_fixture "$fixture" || true
fi
done
# Run Wasm fixtures (BBQ/OMG)
echo "--- Wasm fixtures (BBQ/OMG)"
for fixture in "$WASM_FIXTURES_DIR"/*.js; do
if [ -f "$fixture" ]; then
# Wasm tests need to run from the wasm fixtures directory
# because they reference .wasm files relative to the script
pushd "$WASM_FIXTURES_DIR" > /dev/null
run_fixture "$fixture" || true
popd > /dev/null
fi
done
echo ""
echo "--- Summary"
echo " Passed: $PASSED"
echo " SIGILL failures: $SIGILL_FAILURES"
echo " Other failures: $OTHER_FAILURES (warnings, not CPU instruction issues)"
echo ""
if [ $SIGILL_FAILURES -gt 0 ]; then
echo " FAILED: JIT-generated code uses unsupported CPU instructions."
exit 1
fi
if [ $OTHER_FAILURES -gt 0 ]; then
echo " Some tests failed for reasons unrelated to CPU instructions."
echo " These are warnings and do not indicate JIT instruction issues."
fi
echo " All JIT stress tests passed on $QEMU_CPU (no SIGILL)."

View File

@@ -5,7 +5,22 @@ $ErrorActionPreference = "Stop"
# Detect system architecture
$script:IsARM64 = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq [System.Runtime.InteropServices.Architecture]::Arm64
$script:VsArch = if ($script:IsARM64) { "arm64" } else { "amd64" }
# Allow overriding the target arch (useful for cross-compiling on x64 -> ARM64)
$script:VsArch = $null
if ($env:BUN_VS_ARCH) {
switch ($env:BUN_VS_ARCH.ToLowerInvariant()) {
"arm64" { $script:VsArch = "arm64" }
"aarch64" { $script:VsArch = "arm64" }
"amd64" { $script:VsArch = "amd64" }
"x64" { $script:VsArch = "amd64" }
default { throw "Invalid BUN_VS_ARCH: $env:BUN_VS_ARCH (expected arm64|amd64)" }
}
}
if (-not $script:VsArch) {
$script:VsArch = if ($script:IsARM64) { "arm64" } else { "amd64" }
}
if($env:VSINSTALLDIR -eq $null) {
Write-Host "Loading Visual Studio environment, this may take a second..."
@@ -17,17 +32,29 @@ if($env:VSINSTALLDIR -eq $null) {
$vsDir = (& $vswhere -prerelease -latest -property installationPath)
if ($vsDir -eq $null) {
$vsDir = Get-ChildItem -Path "C:\Program Files\Microsoft Visual Studio\2022" -Directory
# Check common VS installation paths
$searchPaths = @(
"C:\Program Files\Microsoft Visual Studio\2022",
"C:\Program Files (x86)\Microsoft Visual Studio\2022"
)
foreach ($searchPath in $searchPaths) {
if (Test-Path $searchPath) {
$vsDir = (Get-ChildItem -Path $searchPath -Directory | Select-Object -First 1).FullName
if ($vsDir -ne $null) { break }
}
}
if ($vsDir -eq $null) {
throw "Visual Studio directory not found."
}
$vsDir = $vsDir.FullName
}
Push-Location $vsDir
try {
$vsShell = (Join-Path -Path $vsDir -ChildPath "Common7\Tools\Launch-VsDevShell.ps1")
. $vsShell -Arch $script:VsArch -HostArch $script:VsArch
# Visual Studio's Launch-VsDevShell.ps1 only supports x86/amd64 for HostArch
# For ARM64 builds, use amd64 as HostArch since it can cross-compile to ARM64
$hostArch = if ($script:VsArch -eq "arm64") { "amd64" } else { $script:VsArch }
. $vsShell -Arch $script:VsArch -HostArch $hostArch
} finally {
Pop-Location
}
@@ -61,7 +88,7 @@ if ($args.Count -gt 0) {
$displayArgs += $arg
}
}
Write-Host "$ $command $displayArgs"
& $command $commandArgs
exit $LASTEXITCODE

View File

@@ -8,9 +8,9 @@ pkgs.mkShell rec {
# Core build tools (matching bootstrap.sh)
cmake
ninja
clang_19
llvm_19
lld_19
clang_21
llvm_21
lld_21
nodejs_24
bun
rustc
@@ -77,10 +77,10 @@ pkgs.mkShell rec {
];
shellHook = ''
export CC="${pkgs.lib.getExe pkgs.clang_19}"
export CXX="${pkgs.lib.getExe' pkgs.clang_19 "clang++"}"
export AR="${pkgs.llvm_19}/bin/llvm-ar"
export RANLIB="${pkgs.llvm_19}/bin/llvm-ranlib"
export CC="${pkgs.lib.getExe pkgs.clang_21}"
export CXX="${pkgs.lib.getExe' pkgs.clang_21 "clang++"}"
export AR="${pkgs.llvm_21}/bin/llvm-ar"
export RANLIB="${pkgs.llvm_21}/bin/llvm-ranlib"
export CMAKE_C_COMPILER="$CC"
export CMAKE_CXX_COMPILER="$CXX"
export CMAKE_AR="$AR"
@@ -88,7 +88,7 @@ pkgs.mkShell rec {
export CMAKE_SYSTEM_PROCESSOR=$(uname -m)
export TMPDIR=''${TMPDIR:-/tmp}
'' + pkgs.lib.optionalString pkgs.stdenv.isLinux ''
export LD="${pkgs.lib.getExe' pkgs.lld_19 "ld.lld"}"
export LD="${pkgs.lib.getExe' pkgs.lld_21 "ld.lld"}"
export NIX_CFLAGS_LINK="''${NIX_CFLAGS_LINK:+$NIX_CFLAGS_LINK }-fuse-ld=lld"
export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath packages}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
'' + ''

View File

@@ -10,3 +10,295 @@ Conventions:
- Prefer `@import` at the **bottom** of the file, but the auto formatter will move them so you don't need to worry about it.
- **Never** use `@import()` inline inside of functions. **Always** put them at the bottom of the file or containing struct. Imports in Zig are free of side-effects, so there's no such thing as a "dynamic" import.
- You must be patient with the build.
## Prefer Bun APIs over `std`
**Always use `bun.*` APIs instead of `std.*`.** The `bun` namespace (`@import("bun")`) provides cross-platform wrappers that preserve OS error info and never use `unreachable`. Using `std.fs`, `std.posix`, or `std.os` directly is wrong in this codebase.
| Instead of | Use |
| ------------------------------------------------------------ | ------------------------------------ |
| `std.fs.File` | `bun.sys.File` |
| `std.fs.cwd()` | `bun.FD.cwd()` |
| `std.posix.open/read/write/stat/mkdir/unlink/rename/symlink` | `bun.sys.*` equivalents |
| `std.fs.path.join/dirname/basename` | `bun.path.join/dirname/basename` |
| `std.mem.eql/indexOf/startsWith` (for strings) | `bun.strings.eql/indexOf/startsWith` |
| `std.posix.O` / `std.posix.mode_t` / `std.posix.fd_t` | `bun.O` / `bun.Mode` / `bun.FD` |
| `std.process.Child` | `bun.spawnSync` |
| `catch bun.outOfMemory()` | `bun.handleOom(...)` |
## `bun.sys` — System Calls (`src/sys.zig`)
All return `Maybe(T)` — a tagged union of `.result: T` or `.err: bun.sys.Error`:
```zig
const fd = switch (bun.sys.open(path, bun.O.RDONLY, 0)) {
.result => |fd| fd,
.err => |err| return .{ .err = err },
};
// Or: const fd = try bun.sys.open(path, bun.O.RDONLY, 0).unwrap();
```
Key functions (all take `bun.FileDescriptor`, not `std.posix.fd_t`):
- `open`, `openat`, `openA` (non-sentinel) → `Maybe(bun.FileDescriptor)`
- `read`, `readAll`, `pread``Maybe(usize)`
- `write`, `pwrite`, `writev``Maybe(usize)`
- `stat`, `fstat`, `lstat``Maybe(bun.Stat)`
- `mkdir`, `unlink`, `rename`, `symlink`, `chmod`, `fchmod`, `fchown``Maybe(void)`
- `readlink`, `getFdPath`, `getcwd``Maybe` of path slice
- `getFileSize`, `dup`, `sendfile`, `mmap`
Use `bun.O.RDONLY`, `bun.O.WRONLY | bun.O.CREAT | bun.O.TRUNC`, etc. for open flags.
### `bun.sys.File` (`src/sys/File.zig`)
Higher-level file handle wrapping `bun.FileDescriptor`:
```zig
// One-shot read: open + read + close
const bytes = switch (bun.sys.File.readFrom(bun.FD.cwd(), path, allocator)) {
.result => |b| b,
.err => |err| return .{ .err = err },
};
// One-shot write: open + write + close
switch (bun.sys.File.writeFile(bun.FD.cwd(), path, data)) {
.result => {},
.err => |err| return .{ .err = err },
}
```
Key methods:
- `File.open/openat/makeOpen``Maybe(File)` (`makeOpen` creates parent dirs)
- `file.read/readAll/write/writeAll` — single or looped I/O
- `file.readToEnd(allocator)` — read entire file into allocated buffer
- `File.readFrom(dir_fd, path, allocator)` — open + read + close
- `File.writeFile(dir_fd, path, data)` — open + write + close
- `file.stat()`, `file.close()`, `file.writer()`, `file.reader()`
### `bun.FD` (`src/fd.zig`)
Cross-platform file descriptor. Use `bun.FD.cwd()` for cwd, `bun.invalid_fd` for sentinel, `fd.close()` to close.
### `bun.sys.Error` (`src/sys/Error.zig`)
Preserves errno, syscall tag, and file path. Convert to JS: `err.toSystemError().toErrorInstance(globalObject)`.
## `bun.strings` — String Utilities (`src/string/immutable.zig`)
SIMD-accelerated string operations. Use instead of `std.mem` for strings.
```zig
// Searching
strings.indexOf(haystack, needle) // ?usize
strings.contains(haystack, needle) // bool
strings.containsChar(haystack, char) // bool
strings.indexOfChar(haystack, char) // ?u32
strings.indexOfAny(str, comptime chars) // ?OptionalUsize (SIMD-accelerated)
// Comparison
strings.eql(a, b) // bool
strings.eqlComptime(str, comptime literal) // bool — optimized
strings.eqlCaseInsensitiveASCII(a, b, comptime true) // 3rd arg = check_len
// Prefix/Suffix
strings.startsWith(str, prefix) // bool
strings.endsWith(str, suffix) // bool
strings.hasPrefixComptime(str, comptime prefix) // bool — optimized
strings.hasSuffixComptime(str, comptime suffix) // bool — optimized
// Trimming
strings.trim(str, comptime chars) // strip from both ends
strings.trimSpaces(str) // strip whitespace
// Encoding conversions
strings.toUTF8Alloc(allocator, utf16) // ![]u8
strings.toUTF16Alloc(allocator, utf8) // !?[]u16
strings.toUTF8FromLatin1(allocator, latin1) // !?Managed(u8)
strings.firstNonASCII(slice) // ?u32
```
Bun handles UTF-8, Latin-1, and UTF-16/WTF-16 because JSC uses Latin-1 and UTF-16 internally. Latin-1 is NOT UTF-8 — bytes 128-255 are single chars in Latin-1 but invalid UTF-8.
### `bun.String` (`src/string.zig`)
Bridges Zig and JavaScriptCore. Prefer over `ZigString` in new code.
```zig
const s = bun.String.cloneUTF8(utf8_slice); // copies into WTFStringImpl
const s = bun.String.borrowUTF8(utf8_slice); // no copy, caller keeps alive
const utf8 = s.toUTF8(allocator); // ZigString.Slice
defer utf8.deinit();
const js_value = s.toJS(globalObject);
// Create a JS string value directly from UTF-8 bytes:
const js_str = try bun.String.createUTF8ForJS(globalObject, utf8_slice);
```
## `bun.path` — Path Manipulation (`src/resolver/resolve_path.zig`)
Use instead of `std.fs.path`. Platform param: `.auto` (current platform), `.posix`, `.windows`, `.loose` (both separators).
```zig
// Join paths — uses threadlocal buffer, result must be copied if it needs to persist
bun.path.join(&.{ dir, filename }, .auto)
bun.path.joinZ(&.{ dir, filename }, .auto) // null-terminated
// Join into a caller-provided buffer
bun.path.joinStringBuf(&buf, &.{ a, b }, .auto)
bun.path.joinStringBufZ(&buf, &.{ a, b }, .auto) // null-terminated
// Resolve against an absolute base (like Node.js path.resolve)
bun.path.joinAbsString(cwd, &.{ relative_path }, .auto)
bun.path.joinAbsStringBufZ(cwd, &buf, &.{ relative_path }, .auto)
// Path components
bun.path.dirname(path, .auto)
bun.path.basename(path)
// Relative path between two absolute paths
bun.path.relative(from, to)
bun.path.relativeAlloc(allocator, from, to)
// Normalize (resolve `.` and `..`)
bun.path.normalizeBuf(path, &buf, .auto)
// Null-terminate a path into a buffer
bun.path.z(path, &buf) // returns [:0]const u8
```
Use `bun.PathBuffer` for path buffers: `var buf: bun.PathBuffer = undefined;`
For pooled path buffers (avoids 64KB stack allocations on Windows):
```zig
const buf = bun.path_buffer_pool.get();
defer bun.path_buffer_pool.put(buf);
```
## URL Parsing
Prefer `bun.jsc.URL` (WHATWG-compliant, backed by WebKit C++) over `bun.URL.parse` (internal, doesn't properly handle errors or invalid URLs).
```zig
// Parse a URL string (returns null if invalid)
const url = bun.jsc.URL.fromUTF8(href_string) orelse return error.InvalidURL;
defer url.deinit();
url.protocol() // bun.String
url.pathname() // bun.String
url.search() // bun.String
url.hash() // bun.String (includes leading '#')
url.port() // u32 (maxInt(u32) if not set, otherwise u16 range)
// NOTE: host/hostname are SWAPPED vs JS:
url.host() // hostname WITHOUT port (opposite of JS!)
url.hostname() // hostname WITH port (opposite of JS!)
// Normalize a URL string (percent-encode, punycode, etc.)
const normalized = bun.jsc.URL.hrefFromString(bun.String.borrowUTF8(input));
if (normalized.tag == .Dead) return error.InvalidURL;
defer normalized.deref();
// Join base + relative URLs
const joined = bun.jsc.URL.join(base_str, relative_str);
defer joined.deref();
// Convert between file paths and file:// URLs
const file_url = bun.jsc.URL.fileURLFromString(path_str); // path → file://
const file_path = bun.jsc.URL.pathFromFileURL(url_str); // file:// → path
```
## MIME Types (`src/http/MimeType.zig`)
```zig
const MimeType = bun.http.MimeType;
// Look up by file extension (without leading dot)
const mime = MimeType.byExtension("html"); // MimeType{ .value = "text/html", .category = .html }
const mime = MimeType.byExtensionNoDefault("xyz"); // ?MimeType (null if unknown)
// Category checks
mime.category // .javascript, .css, .html, .json, .image, .text, .wasm, .font, .video, .audio, ...
mime.category.isCode()
```
Common constants: `MimeType.javascript`, `MimeType.json`, `MimeType.html`, `MimeType.css`, `MimeType.text`, `MimeType.wasm`, `MimeType.ico`, `MimeType.other`.
## Memory & Allocators
**Use `bun.default_allocator` for almost everything.** It's backed by mimalloc.
`bun.handleOom(expr)` converts `error.OutOfMemory` into a crash without swallowing other errors:
```zig
const buf = bun.handleOom(allocator.alloc(u8, size)); // correct
// NOT: allocator.alloc(u8, size) catch bun.outOfMemory() — could swallow non-OOM errors
```
## Environment Variables (`src/env_var.zig`)
Type-safe, cached environment variable accessors via `bun.env_var`:
```zig
bun.env_var.HOME.get() // ?[]const u8
bun.env_var.CI.get() // ?bool
bun.env_var.BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS.get() // u64 (has default: 30)
```
## Logging (`src/output.zig`)
```zig
const log = bun.Output.scoped(.MY_FEATURE, .visible); // .hidden = opt-in via BUN_DEBUG_MY_FEATURE=1
log("processing {d} items", .{count});
// Color output (convenience wrappers auto-detect TTY):
bun.Output.pretty("<green>success<r>: {s}\n", .{msg});
bun.Output.prettyErrorln("<red>error<r>: {s}", .{msg});
```
## Spawning Subprocesses (`src/bun.js/api/bun/process.zig`)
Use `bun.spawnSync` instead of `std.process.Child`:
```zig
switch (bun.spawnSync(&.{
.argv = argv,
.envp = null, // inherit parent env
.cwd = cwd,
.stdout = .buffer, // capture
.stderr = .inherit, // pass through
.stdin = .ignore,
.windows = if (bun.Environment.isWindows) .{
.loop = bun.jsc.EventLoopHandle.init(bun.jsc.MiniEventLoop.initGlobal(env, null)),
},
}) catch return) {
.err => |err| { /* bun.sys.Error */ },
.result => |result| {
defer result.deinit();
const stdout = result.stdout.items;
if (result.status.isOK()) { ... }
},
}
```
Options: `argv: []const []const u8`, `envp: ?[*:null]?[*:0]const u8` (null = inherit), `argv0: ?[*:0]const u8`. Stdio: `.inherit`, `.ignore`, `.buffer`.
## Common Patterns
```zig
// Read a file
const contents = switch (bun.sys.File.readFrom(bun.FD.cwd(), path, allocator)) {
.result => |bytes| bytes,
.err => |err| { globalObject.throwValue(err.toSystemError().toErrorInstance(globalObject)); return .zero; },
};
// Create directories recursively
bun.makePath(dir.stdDir(), sub_path) catch |err| { ... };
// Hashing
bun.hash(bytes) // u64 — wyhash
bun.hash32(bytes) // u32
```

View File

@@ -15,6 +15,7 @@ hash: u64 = 0,
is_executable: bool = false,
source_map_index: u32 = std.math.maxInt(u32),
bytecode_index: u32 = std.math.maxInt(u32),
module_info_index: u32 = std.math.maxInt(u32),
output_kind: jsc.API.BuildArtifact.OutputKind,
/// Relative
dest_path: []const u8 = "",
@@ -210,6 +211,7 @@ pub const Options = struct {
hash: ?u64 = null,
source_map_index: ?u32 = null,
bytecode_index: ?u32 = null,
module_info_index: ?u32 = null,
output_path: string,
source_index: Index.Optional = .none,
size: ?usize = null,
@@ -251,6 +253,7 @@ pub fn init(options: Options) OutputFile {
.hash = options.hash orelse 0,
.output_kind = options.output_kind,
.bytecode_index = options.bytecode_index orelse std.math.maxInt(u32),
.module_info_index = options.module_info_index orelse std.math.maxInt(u32),
.source_map_index = options.source_map_index orelse std.math.maxInt(u32),
.is_executable = options.is_executable,
.value = switch (options.data) {

View File

@@ -92,6 +92,10 @@ pub const StandaloneModuleGraph = struct {
contents: Schema.StringPointer = .{},
sourcemap: Schema.StringPointer = .{},
bytecode: Schema.StringPointer = .{},
module_info: Schema.StringPointer = .{},
/// The file path used when generating bytecode (e.g., "B:/~BUN/root/app.js").
/// Must match exactly at runtime for bytecode cache hits.
bytecode_origin_path: Schema.StringPointer = .{},
encoding: Encoding = .latin1,
loader: bun.options.Loader = .file,
module_format: ModuleFormat = .none,
@@ -159,6 +163,10 @@ pub const StandaloneModuleGraph = struct {
encoding: Encoding = .binary,
wtf_string: bun.String = bun.String.empty,
bytecode: []u8 = "",
module_info: []u8 = "",
/// The file path used when generating bytecode (e.g., "B:/~BUN/root/app.js").
/// Must match exactly at runtime for bytecode cache hits.
bytecode_origin_path: []const u8 = "",
module_format: ModuleFormat = .none,
side: FileSide = .server,
@@ -333,6 +341,8 @@ pub const StandaloneModuleGraph = struct {
else
.none,
.bytecode = if (module.bytecode.length > 0) @constCast(sliceTo(raw_bytes, module.bytecode)) else &.{},
.module_info = if (module.module_info.length > 0) @constCast(sliceTo(raw_bytes, module.module_info)) else &.{},
.bytecode_origin_path = if (module.bytecode_origin_path.length > 0) sliceToZ(raw_bytes, module.bytecode_origin_path) else "",
.module_format = module.module_format,
.side = module.side,
},
@@ -382,6 +392,8 @@ pub const StandaloneModuleGraph = struct {
} else if (output_file.output_kind == .bytecode) {
// Allocate up to 256 byte alignment for bytecode
string_builder.cap += (output_file.value.buffer.bytes.len + 255) / 256 * 256 + 256;
} else if (output_file.output_kind == .module_info) {
string_builder.cap += output_file.value.buffer.bytes.len;
} else {
if (entry_point_id == null) {
if (output_file.side == null or output_file.side.? == .server) {
@@ -477,6 +489,19 @@ pub const StandaloneModuleGraph = struct {
}
};
// Embed module_info for ESM bytecode
const module_info: StringPointer = brk: {
if (output_file.module_info_index != std.math.maxInt(u32)) {
const mi_bytes = output_files[output_file.module_info_index].value.buffer.bytes;
const offset = string_builder.len;
const writable = string_builder.writable();
@memcpy(writable[0..mi_bytes.len], mi_bytes[0..mi_bytes.len]);
string_builder.len += mi_bytes.len;
break :brk StringPointer{ .offset = @truncate(offset), .length = @truncate(mi_bytes.len) };
}
break :brk .{};
};
if (comptime bun.Environment.is_canary or bun.Environment.isDebug) {
if (bun.env_var.BUN_FEATURE_FLAG_DUMP_CODE.get()) |dump_code_dir| {
const buf = bun.path_buffer_pool.get();
@@ -498,6 +523,13 @@ pub const StandaloneModuleGraph = struct {
}
}
// When there's bytecode, store the bytecode output file's path as bytecode_origin_path.
// This path was used to generate the bytecode cache and must match at runtime.
const bytecode_origin_path: StringPointer = if (output_file.bytecode_index != std.math.maxInt(u32))
string_builder.appendCountZ(output_files[output_file.bytecode_index].dest_path)
else
.{};
var module = CompiledModuleGraphFile{
.name = string_builder.fmtAppendCountZ("{s}{s}", .{
prefix,
@@ -515,6 +547,8 @@ pub const StandaloneModuleGraph = struct {
else => .none,
} else .none,
.bytecode = bytecode,
.module_info = module_info,
.bytecode_origin_path = bytecode_origin_path,
.side = switch (output_file.side orelse .server) {
.server => .server,
.client => .client,
@@ -901,7 +935,7 @@ pub const StandaloneModuleGraph = struct {
var remain = bytes;
while (remain.len > 0) {
switch (Syscall.write(cloned_executable_fd, bytes)) {
switch (Syscall.write(cloned_executable_fd, remain)) {
.result => |written| remain = remain[written..],
.err => |err| {
Output.prettyErrorln("<r><red>error<r><d>:<r> failed to write to temporary file\n{f}", .{err});

View File

@@ -2,10 +2,7 @@
const Self = @This();
const safety_checks = bun.Environment.isDebug or bun.Environment.enable_asan;
#heap: *mimalloc.Heap,
thread_id: if (safety_checks) std.Thread.Id else void,
#heap: if (safety_checks) Owned(*DebugHeap) else *mimalloc.Heap,
/// Uses the default thread-local heap. This type is zero-sized.
///
@@ -23,18 +20,18 @@ pub const Default = struct {
///
/// This type is a `GenericAllocator`; see `src/allocators.zig`.
pub const Borrowed = struct {
#heap: *mimalloc.Heap,
#heap: BorrowedHeap,
pub fn allocator(self: Borrowed) std.mem.Allocator {
return .{ .ptr = self.#heap, .vtable = c_allocator_vtable };
return .{ .ptr = self.#heap, .vtable = &c_allocator_vtable };
}
pub fn getDefault() Borrowed {
return .{ .#heap = mimalloc.mi_heap_main() };
return .{ .#heap = getThreadHeap() };
}
pub fn gc(self: Borrowed) void {
mimalloc.mi_heap_collect(self.#heap, false);
mimalloc.mi_heap_collect(self.getMimallocHeap(), false);
}
pub fn helpCatchMemoryIssues(self: Borrowed) void {
@@ -44,17 +41,30 @@ pub const Borrowed = struct {
}
}
pub fn ownsPtr(self: Borrowed, ptr: *const anyopaque) bool {
return mimalloc.mi_heap_check_owned(self.getMimallocHeap(), ptr);
}
fn fromOpaque(ptr: *anyopaque) Borrowed {
return .{ .#heap = @ptrCast(@alignCast(ptr)) };
}
fn getMimallocHeap(self: Borrowed) *mimalloc.Heap {
return if (comptime safety_checks) self.#heap.inner else self.#heap;
}
fn assertThreadLock(self: Borrowed) void {
if (comptime safety_checks) self.#heap.thread_lock.assertLocked();
}
fn alignedAlloc(self: Borrowed, len: usize, alignment: Alignment) ?[*]u8 {
log("Malloc: {d}\n", .{len});
const heap = self.getMimallocHeap();
const ptr: ?*anyopaque = if (mimalloc.mustUseAlignedAlloc(alignment))
mimalloc.mi_heap_malloc_aligned(self.#heap, len, alignment.toByteUnits())
mimalloc.mi_heap_malloc_aligned(heap, len, alignment.toByteUnits())
else
mimalloc.mi_heap_malloc(self.#heap, len);
mimalloc.mi_heap_malloc(heap, len);
if (comptime bun.Environment.isDebug) {
const usable = mimalloc.mi_malloc_usable_size(ptr);
@@ -79,17 +89,42 @@ pub const Borrowed = struct {
}
};
const BorrowedHeap = if (safety_checks) *DebugHeap else *mimalloc.Heap;
const DebugHeap = struct {
inner: *mimalloc.Heap,
thread_lock: bun.safety.ThreadLock,
pub const deinit = void;
};
threadlocal var thread_heap: if (safety_checks) ?DebugHeap else void = if (safety_checks) null;
fn getThreadHeap() BorrowedHeap {
if (comptime !safety_checks) return mimalloc.mi_heap_get_default();
if (thread_heap == null) {
thread_heap = .{
.inner = mimalloc.mi_heap_get_default(),
.thread_lock = .initLocked(),
};
}
return &thread_heap.?;
}
const log = bun.Output.scoped(.mimalloc, .hidden);
pub fn allocator(self: Self) std.mem.Allocator {
self.assertThreadOwnership();
return self.borrow().allocator();
}
pub fn borrow(self: Self) Borrowed {
return .{ .#heap = self.#heap };
return .{ .#heap = if (comptime safety_checks) self.#heap.get() else self.#heap };
}
/// Internally, mimalloc calls mi_heap_get_default()
/// to get the default heap.
/// It uses pthread_getspecific to do that.
/// We can save those extra calls if we just do it once in here
pub fn getThreadLocalDefault() std.mem.Allocator {
if (bun.Environment.enable_asan) return bun.default_allocator;
return Borrowed.getDefault().allocator();
@@ -122,15 +157,22 @@ pub fn dumpStats(_: Self) void {
}
pub fn deinit(self: *Self) void {
mimalloc.mi_heap_destroy(self.#heap);
const mimalloc_heap = self.borrow().getMimallocHeap();
if (comptime safety_checks) {
self.#heap.deinit();
}
mimalloc.mi_heap_destroy(mimalloc_heap);
self.* = undefined;
}
pub fn init() Self {
return .{
.#heap = mimalloc.mi_heap_new() orelse bun.outOfMemory(),
.thread_id = if (safety_checks) std.Thread.getCurrentId() else {},
};
const mimalloc_heap = mimalloc.mi_heap_new() orelse bun.outOfMemory();
if (comptime !safety_checks) return .{ .#heap = mimalloc_heap };
const heap: Owned(*DebugHeap) = .new(.{
.inner = mimalloc_heap,
.thread_lock = .initLocked(),
});
return .{ .#heap = heap };
}
pub fn gc(self: Self) void {
@@ -141,16 +183,8 @@ pub fn helpCatchMemoryIssues(self: Self) void {
self.borrow().helpCatchMemoryIssues();
}
fn assertThreadOwnership(self: Self) void {
if (comptime safety_checks) {
const current_thread = std.Thread.getCurrentId();
if (current_thread != self.thread_id) {
std.debug.panic(
"MimallocArena used from wrong thread: arena belongs to thread {d}, but current thread is {d}",
.{ self.thread_id, current_thread },
);
}
}
pub fn ownsPtr(self: Self, ptr: *const anyopaque) bool {
return self.borrow().ownsPtr(ptr);
}
fn alignedAllocSize(ptr: [*]u8) usize {
@@ -159,10 +193,13 @@ fn alignedAllocSize(ptr: [*]u8) usize {
fn vtable_alloc(ptr: *anyopaque, len: usize, alignment: Alignment, _: usize) ?[*]u8 {
const self: Borrowed = .fromOpaque(ptr);
self.assertThreadLock();
return self.alignedAlloc(len, alignment);
}
fn vtable_resize(_: *anyopaque, buf: []u8, _: Alignment, new_len: usize, _: usize) bool {
fn vtable_resize(ptr: *anyopaque, buf: []u8, _: Alignment, new_len: usize, _: usize) bool {
const self: Borrowed = .fromOpaque(ptr);
self.assertThreadLock();
return mimalloc.mi_expand(buf.ptr, new_len) != null;
}
@@ -186,17 +223,39 @@ fn vtable_free(
}
}
/// Attempt to expand or shrink memory, allowing relocation.
///
/// `memory.len` must equal the length requested from the most recent
/// successful call to `alloc`, `resize`, or `remap`. `alignment` must
/// equal the same value that was passed as the `alignment` parameter to
/// the original `alloc` call.
///
/// A non-`null` return value indicates the resize was successful. The
/// allocation may have same address, or may have been relocated. In either
/// case, the allocation now has size of `new_len`. A `null` return value
/// indicates that the resize would be equivalent to allocating new memory,
/// copying the bytes from the old memory, and then freeing the old memory.
/// In such case, it is more efficient for the caller to perform the copy.
///
/// `new_len` must be greater than zero.
///
/// `ret_addr` is optionally provided as the first return address of the
/// allocation call stack. If the value is `0` it means no return address
/// has been provided.
fn vtable_remap(ptr: *anyopaque, buf: []u8, alignment: Alignment, new_len: usize, _: usize) ?[*]u8 {
const self: Borrowed = .fromOpaque(ptr);
const value = mimalloc.mi_heap_realloc_aligned(self.#heap, buf.ptr, new_len, alignment.toByteUnits());
self.assertThreadLock();
const heap = self.getMimallocHeap();
const aligned_size = alignment.toByteUnits();
const value = mimalloc.mi_heap_realloc_aligned(heap, buf.ptr, new_len, aligned_size);
return @ptrCast(value);
}
pub fn isInstance(alloc: std.mem.Allocator) bool {
return alloc.vtable == c_allocator_vtable;
return alloc.vtable == &c_allocator_vtable;
}
const c_allocator_vtable = &std.mem.Allocator.VTable{
const c_allocator_vtable = std.mem.Allocator.VTable{
.alloc = vtable_alloc,
.resize = vtable_resize,
.remap = vtable_remap,
@@ -209,3 +268,5 @@ const Alignment = std.mem.Alignment;
const bun = @import("bun");
const assert = bun.assert;
const mimalloc = bun.mimalloc;
const Owned = bun.ptr.Owned;
const safety_checks = bun.Environment.ci_assert;

View File

@@ -60,29 +60,17 @@ pub const Heap = opaque {
return mi_heap_realloc(self, p, newsize);
}
pub fn isOwned(self: *Heap, p: ?*const anyopaque) bool {
return mi_heap_contains(self, p);
pub fn isOwned(self: *Heap, p: ?*anyopaque) bool {
return mi_heap_check_owned(self, p);
}
};
pub extern fn mi_heap_new() ?*Heap;
pub extern fn mi_heap_delete(heap: *Heap) void;
pub extern fn mi_heap_destroy(heap: *Heap) void;
pub extern fn mi_heap_set_default(heap: *Heap) *Heap;
pub extern fn mi_heap_get_default() *Heap;
pub extern fn mi_heap_get_backing() *Heap;
pub extern fn mi_heap_collect(heap: *Heap, force: bool) void;
pub extern fn mi_heap_main() *Heap;
// Thread-local heap (theap) API - new in mimalloc v3
pub const THeap = opaque {};
pub extern fn mi_theap_get_default() *THeap;
pub extern fn mi_theap_set_default(theap: *THeap) *THeap;
pub extern fn mi_theap_collect(theap: *THeap, force: bool) void;
pub extern fn mi_theap_malloc(theap: *THeap, size: usize) ?*anyopaque;
pub extern fn mi_theap_zalloc(theap: *THeap, size: usize) ?*anyopaque;
pub extern fn mi_theap_calloc(theap: *THeap, count: usize, size: usize) ?*anyopaque;
pub extern fn mi_theap_malloc_small(theap: *THeap, size: usize) ?*anyopaque;
pub extern fn mi_theap_malloc_aligned(theap: *THeap, size: usize, alignment: usize) ?*anyopaque;
pub extern fn mi_theap_realloc(theap: *THeap, p: ?*anyopaque, newsize: usize) ?*anyopaque;
pub extern fn mi_theap_destroy(theap: *THeap) void;
pub extern fn mi_heap_theap(heap: *Heap) *THeap;
pub extern fn mi_heap_malloc(heap: *Heap, size: usize) ?*anyopaque;
pub extern fn mi_heap_zalloc(heap: *Heap, size: usize) ?*anyopaque;
pub extern fn mi_heap_calloc(heap: *Heap, count: usize, size: usize) ?*anyopaque;
@@ -114,7 +102,8 @@ pub extern fn mi_heap_rezalloc_aligned(heap: *Heap, p: ?*anyopaque, newsize: usi
pub extern fn mi_heap_rezalloc_aligned_at(heap: *Heap, p: ?*anyopaque, newsize: usize, alignment: usize, offset: usize) ?*anyopaque;
pub extern fn mi_heap_recalloc_aligned(heap: *Heap, p: ?*anyopaque, newcount: usize, size: usize, alignment: usize) ?*anyopaque;
pub extern fn mi_heap_recalloc_aligned_at(heap: *Heap, p: ?*anyopaque, newcount: usize, size: usize, alignment: usize, offset: usize) ?*anyopaque;
pub extern fn mi_heap_contains(heap: *const Heap, p: ?*const anyopaque) bool;
pub extern fn mi_heap_contains_block(heap: *Heap, p: *const anyopaque) bool;
pub extern fn mi_heap_check_owned(heap: *Heap, p: *const anyopaque) bool;
pub extern fn mi_check_owned(p: ?*const anyopaque) bool;
pub const struct_mi_heap_area_s = extern struct {
blocks: ?*anyopaque,

View File

@@ -0,0 +1,513 @@
pub const RecordKind = enum(u8) {
/// var_name
declared_variable,
/// let_name
lexical_variable,
/// module_name, import_name, local_name
import_info_single,
/// module_name, import_name, local_name
import_info_single_type_script,
/// module_name, import_name = '*', local_name
import_info_namespace,
/// export_name, import_name, module_name
export_info_indirect,
/// export_name, local_name, padding (for local => indirect conversion)
export_info_local,
/// export_name, module_name
export_info_namespace,
/// module_name
export_info_star,
_,
pub fn len(record: RecordKind) !usize {
return switch (record) {
.declared_variable, .lexical_variable => 1,
.import_info_single => 3,
.import_info_single_type_script => 3,
.import_info_namespace => 3,
.export_info_indirect => 3,
.export_info_local => 3,
.export_info_namespace => 2,
.export_info_star => 1,
else => return error.InvalidRecordKind,
};
}
};
pub const Flags = packed struct(u8) {
contains_import_meta: bool = false,
is_typescript: bool = false,
_padding: u6 = 0,
};
pub const ModuleInfoDeserialized = struct {
strings_buf: []const u8,
strings_lens: []align(1) const u32,
requested_modules_keys: []align(1) const StringID,
requested_modules_values: []align(1) const ModuleInfo.FetchParameters,
buffer: []align(1) const StringID,
record_kinds: []align(1) const RecordKind,
flags: Flags,
owner: union(enum) {
module_info,
allocated_slice: struct {
slice: []const u8,
allocator: std.mem.Allocator,
},
},
pub fn deinit(self: *ModuleInfoDeserialized) void {
switch (self.owner) {
.module_info => {
const mi: *ModuleInfo = @fieldParentPtr("_deserialized", self);
mi.destroy();
},
.allocated_slice => |as| {
as.allocator.free(as.slice);
as.allocator.destroy(self);
},
}
}
inline fn eat(rem: *[]const u8, len: usize) ![]const u8 {
if (rem.*.len < len) return error.BadModuleInfo;
const res = rem.*[0..len];
rem.* = rem.*[len..];
return res;
}
inline fn eatC(rem: *[]const u8, comptime len: usize) !*const [len]u8 {
if (rem.*.len < len) return error.BadModuleInfo;
const res = rem.*[0..len];
rem.* = rem.*[len..];
return res;
}
pub fn create(source: []const u8, gpa: std.mem.Allocator) !*ModuleInfoDeserialized {
const duped = try gpa.dupe(u8, source);
errdefer gpa.free(duped);
var rem: []const u8 = duped;
const res = try gpa.create(ModuleInfoDeserialized);
errdefer gpa.destroy(res);
const record_kinds_len = std.mem.readInt(u32, try eatC(&rem, 4), .little);
const record_kinds = std.mem.bytesAsSlice(RecordKind, try eat(&rem, record_kinds_len * @sizeOf(RecordKind)));
_ = try eat(&rem, (4 - (record_kinds_len % 4)) % 4); // alignment padding
const buffer_len = std.mem.readInt(u32, try eatC(&rem, 4), .little);
const buffer = std.mem.bytesAsSlice(StringID, try eat(&rem, buffer_len * @sizeOf(StringID)));
const requested_modules_len = std.mem.readInt(u32, try eatC(&rem, 4), .little);
const requested_modules_keys = std.mem.bytesAsSlice(StringID, try eat(&rem, requested_modules_len * @sizeOf(StringID)));
const requested_modules_values = std.mem.bytesAsSlice(ModuleInfo.FetchParameters, try eat(&rem, requested_modules_len * @sizeOf(ModuleInfo.FetchParameters)));
const flags: Flags = @bitCast((try eatC(&rem, 1))[0]);
_ = try eat(&rem, 3); // alignment padding
const strings_len = std.mem.readInt(u32, try eatC(&rem, 4), .little);
const strings_lens = std.mem.bytesAsSlice(u32, try eat(&rem, strings_len * @sizeOf(u32)));
const strings_buf = rem;
res.* = .{
.strings_buf = strings_buf,
.strings_lens = strings_lens,
.requested_modules_keys = requested_modules_keys,
.requested_modules_values = requested_modules_values,
.buffer = buffer,
.record_kinds = record_kinds,
.flags = flags,
.owner = .{ .allocated_slice = .{
.slice = duped,
.allocator = gpa,
} },
};
return res;
}
/// Wrapper around `create` for use when loading from a cache (transpiler cache or standalone module graph).
/// Returns `null` instead of panicking on corrupt/truncated data.
pub fn createFromCachedRecord(source: []const u8, gpa: std.mem.Allocator) ?*ModuleInfoDeserialized {
return create(source, gpa) catch |e| switch (e) {
error.OutOfMemory => bun.outOfMemory(),
error.BadModuleInfo => null,
};
}
pub fn serialize(self: *const ModuleInfoDeserialized, writer: anytype) !void {
try writer.writeInt(u32, @truncate(self.record_kinds.len), .little);
try writer.writeAll(std.mem.sliceAsBytes(self.record_kinds));
try writer.writeByteNTimes(0, (4 - (self.record_kinds.len % 4)) % 4); // alignment padding
try writer.writeInt(u32, @truncate(self.buffer.len), .little);
try writer.writeAll(std.mem.sliceAsBytes(self.buffer));
try writer.writeInt(u32, @truncate(self.requested_modules_keys.len), .little);
try writer.writeAll(std.mem.sliceAsBytes(self.requested_modules_keys));
try writer.writeAll(std.mem.sliceAsBytes(self.requested_modules_values));
try writer.writeByte(@bitCast(self.flags));
try writer.writeByteNTimes(0, 3); // alignment padding
try writer.writeInt(u32, @truncate(self.strings_lens.len), .little);
try writer.writeAll(std.mem.sliceAsBytes(self.strings_lens));
try writer.writeAll(self.strings_buf);
}
};
const StringMapKey = enum(u32) {
_,
};
pub const StringContext = struct {
strings_buf: []const u8,
strings_lens: []const u32,
pub fn hash(_: @This(), s: []const u8) u32 {
return @as(u32, @truncate(std.hash.Wyhash.hash(0, s)));
}
pub fn eql(self: @This(), fetch_key: []const u8, item_key: StringMapKey, item_i: usize) bool {
return bun.strings.eqlLong(fetch_key, self.strings_buf[@intFromEnum(item_key)..][0..self.strings_lens[item_i]], true);
}
};
pub const ModuleInfo = struct {
/// all strings in wtf-8. index in hashmap = StringID
gpa: std.mem.Allocator,
strings_map: std.ArrayHashMapUnmanaged(StringMapKey, void, void, true),
strings_buf: std.ArrayListUnmanaged(u8),
strings_lens: std.ArrayListUnmanaged(u32),
requested_modules: std.AutoArrayHashMap(StringID, FetchParameters),
buffer: std.ArrayListUnmanaged(StringID),
record_kinds: std.ArrayListUnmanaged(RecordKind),
flags: Flags,
exported_names: std.AutoArrayHashMapUnmanaged(StringID, void),
finalized: bool = false,
/// only initialized after .finalize() is called
_deserialized: ModuleInfoDeserialized,
pub fn asDeserialized(self: *ModuleInfo) *ModuleInfoDeserialized {
bun.assert(self.finalized);
return &self._deserialized;
}
pub const FetchParameters = enum(u32) {
none = std.math.maxInt(u32),
javascript = std.math.maxInt(u32) - 1,
webassembly = std.math.maxInt(u32) - 2,
json = std.math.maxInt(u32) - 3,
_, // host_defined: cast to StringID
pub fn hostDefined(value: StringID) FetchParameters {
return @enumFromInt(@intFromEnum(value));
}
};
pub const VarKind = enum { declared, lexical };
pub fn addVar(self: *ModuleInfo, name: StringID, kind: VarKind) !void {
switch (kind) {
.declared => try self.addDeclaredVariable(name),
.lexical => try self.addLexicalVariable(name),
}
}
fn _addRecord(self: *ModuleInfo, kind: RecordKind, data: []const StringID) !void {
bun.assert(!self.finalized);
bun.assert(data.len == kind.len() catch unreachable);
try self.record_kinds.append(self.gpa, kind);
try self.buffer.appendSlice(self.gpa, data);
}
pub fn addDeclaredVariable(self: *ModuleInfo, id: StringID) !void {
try self._addRecord(.declared_variable, &.{id});
}
pub fn addLexicalVariable(self: *ModuleInfo, id: StringID) !void {
try self._addRecord(.lexical_variable, &.{id});
}
pub fn addImportInfoSingle(self: *ModuleInfo, module_name: StringID, import_name: StringID, local_name: StringID, only_used_as_type: bool) !void {
try self._addRecord(if (only_used_as_type) .import_info_single_type_script else .import_info_single, &.{ module_name, import_name, local_name });
}
pub fn addImportInfoNamespace(self: *ModuleInfo, module_name: StringID, local_name: StringID) !void {
try self._addRecord(.import_info_namespace, &.{ module_name, try self.str("*"), local_name });
}
pub fn addExportInfoIndirect(self: *ModuleInfo, export_name: StringID, import_name: StringID, module_name: StringID) !void {
if (try self._hasOrAddExportedName(export_name)) return; // a syntax error will be emitted later in this case
try self._addRecord(.export_info_indirect, &.{ export_name, import_name, module_name });
}
pub fn addExportInfoLocal(self: *ModuleInfo, export_name: StringID, local_name: StringID) !void {
if (try self._hasOrAddExportedName(export_name)) return; // a syntax error will be emitted later in this case
try self._addRecord(.export_info_local, &.{ export_name, local_name, @enumFromInt(std.math.maxInt(u32)) });
}
pub fn addExportInfoNamespace(self: *ModuleInfo, export_name: StringID, module_name: StringID) !void {
if (try self._hasOrAddExportedName(export_name)) return; // a syntax error will be emitted later in this case
try self._addRecord(.export_info_namespace, &.{ export_name, module_name });
}
pub fn addExportInfoStar(self: *ModuleInfo, module_name: StringID) !void {
try self._addRecord(.export_info_star, &.{module_name});
}
pub fn _hasOrAddExportedName(self: *ModuleInfo, name: StringID) !bool {
if (try self.exported_names.fetchPut(self.gpa, name, {}) != null) return true;
return false;
}
pub fn create(gpa: std.mem.Allocator, is_typescript: bool) !*ModuleInfo {
const res = try gpa.create(ModuleInfo);
res.* = ModuleInfo.init(gpa, is_typescript);
return res;
}
fn init(allocator: std.mem.Allocator, is_typescript: bool) ModuleInfo {
return .{
.gpa = allocator,
.strings_map = .{},
.strings_buf = .{},
.strings_lens = .{},
.exported_names = .{},
.requested_modules = std.AutoArrayHashMap(StringID, FetchParameters).init(allocator),
.buffer = .empty,
.record_kinds = .empty,
.flags = .{ .contains_import_meta = false, .is_typescript = is_typescript },
._deserialized = undefined,
};
}
fn deinit(self: *ModuleInfo) void {
self.strings_map.deinit(self.gpa);
self.strings_buf.deinit(self.gpa);
self.strings_lens.deinit(self.gpa);
self.exported_names.deinit(self.gpa);
self.requested_modules.deinit();
self.buffer.deinit(self.gpa);
self.record_kinds.deinit(self.gpa);
}
pub fn destroy(self: *ModuleInfo) void {
const alloc = self.gpa;
self.deinit();
alloc.destroy(self);
}
pub fn str(self: *ModuleInfo, value: []const u8) !StringID {
try self.strings_buf.ensureUnusedCapacity(self.gpa, value.len);
try self.strings_lens.ensureUnusedCapacity(self.gpa, 1);
const gpres = try self.strings_map.getOrPutAdapted(self.gpa, value, StringContext{
.strings_buf = self.strings_buf.items,
.strings_lens = self.strings_lens.items,
});
if (gpres.found_existing) return @enumFromInt(@as(u32, @intCast(gpres.index)));
gpres.key_ptr.* = @enumFromInt(@as(u32, @truncate(self.strings_buf.items.len)));
gpres.value_ptr.* = {};
self.strings_buf.appendSliceAssumeCapacity(value);
self.strings_lens.appendAssumeCapacity(@as(u32, @truncate(value.len)));
return @enumFromInt(@as(u32, @intCast(gpres.index)));
}
pub fn requestModule(self: *ModuleInfo, import_record_path: StringID, fetch_parameters: FetchParameters) !void {
// jsc only records the attributes of the first import with the given import_record_path. so only put if not exists.
const gpres = try self.requested_modules.getOrPut(import_record_path);
if (!gpres.found_existing) gpres.value_ptr.* = fetch_parameters;
}
/// Replace all occurrences of old_id with new_id in records and requested_modules.
/// Used to fix up cross-chunk import specifiers after final paths are computed.
pub fn replaceStringID(self: *ModuleInfo, old_id: StringID, new_id: StringID) void {
bun.assert(!self.finalized);
// Replace in record buffer
for (self.buffer.items) |*item| {
if (item.* == old_id) item.* = new_id;
}
// Replace in requested_modules keys (preserving insertion order)
if (self.requested_modules.getIndex(old_id)) |idx| {
self.requested_modules.keys()[idx] = new_id;
self.requested_modules.reIndex() catch {};
}
}
/// find any exports marked as 'local' that are actually 'indirect' and fix them
pub fn finalize(self: *ModuleInfo) !void {
bun.assert(!self.finalized);
var local_name_to_module_name = std.AutoArrayHashMap(StringID, struct { module_name: StringID, import_name: StringID, record_kinds_idx: usize }).init(bun.default_allocator);
defer local_name_to_module_name.deinit();
{
var i: usize = 0;
for (self.record_kinds.items, 0..) |k, idx| {
if (k == .import_info_single or k == .import_info_single_type_script) {
try local_name_to_module_name.put(self.buffer.items[i + 2], .{ .module_name = self.buffer.items[i], .import_name = self.buffer.items[i + 1], .record_kinds_idx = idx });
}
i += k.len() catch unreachable;
}
}
{
var i: usize = 0;
for (self.record_kinds.items) |*k| {
if (k.* == .export_info_local) {
if (local_name_to_module_name.get(self.buffer.items[i + 1])) |ip| {
k.* = .export_info_indirect;
self.buffer.items[i + 1] = ip.import_name;
self.buffer.items[i + 2] = ip.module_name;
// In TypeScript, the re-exported import may target a type-only
// export that was elided. Convert the import to SingleTypeScript
// so JSC tolerates it being NotFound during linking.
if (self.flags.is_typescript) {
self.record_kinds.items[ip.record_kinds_idx] = .import_info_single_type_script;
}
}
}
i += k.len() catch unreachable;
}
}
self._deserialized = .{
.strings_buf = self.strings_buf.items,
.strings_lens = self.strings_lens.items,
.requested_modules_keys = self.requested_modules.keys(),
.requested_modules_values = self.requested_modules.values(),
.buffer = self.buffer.items,
.record_kinds = self.record_kinds.items,
.flags = self.flags,
.owner = .module_info,
};
self.finalized = true;
}
};
pub const StringID = enum(u32) {
star_default = std.math.maxInt(u32),
star_namespace = std.math.maxInt(u32) - 1,
_,
};
export fn zig__renderDiff(expected_ptr: [*:0]const u8, expected_len: usize, received_ptr: [*:0]const u8, received_len: usize, globalThis: *bun.jsc.JSGlobalObject) void {
const formatter = DiffFormatter{
.received_string = received_ptr[0..received_len],
.expected_string = expected_ptr[0..expected_len],
.globalThis = globalThis,
};
bun.Output.errorWriter().print("DIFF:\n{any}\n", .{formatter}) catch {};
}
export fn zig__ModuleInfoDeserialized__toJSModuleRecord(
globalObject: *bun.jsc.JSGlobalObject,
vm: *bun.jsc.VM,
module_key: *const IdentifierArray,
source_code: *const SourceCode,
declared_variables: *VariableEnvironment,
lexical_variables: *VariableEnvironment,
res: *ModuleInfoDeserialized,
) ?*JSModuleRecord {
defer res.deinit();
var identifiers = IdentifierArray.create(res.strings_lens.len);
defer identifiers.destroy();
var offset: usize = 0;
for (0.., res.strings_lens) |index, len| {
if (res.strings_buf.len < offset + len) return null; // error!
const sub = res.strings_buf[offset..][0..len];
identifiers.setFromUtf8(index, vm, sub);
offset += len;
}
{
var i: usize = 0;
for (res.record_kinds) |k| {
if (i + (k.len() catch 0) > res.buffer.len) return null;
switch (k) {
.declared_variable => declared_variables.add(vm, identifiers, res.buffer[i]),
.lexical_variable => lexical_variables.add(vm, identifiers, res.buffer[i]),
.import_info_single, .import_info_single_type_script, .import_info_namespace, .export_info_indirect, .export_info_local, .export_info_namespace, .export_info_star => {},
else => return null,
}
i += k.len() catch unreachable; // handled above
}
}
const module_record = JSModuleRecord.create(globalObject, vm, module_key, source_code, declared_variables, lexical_variables, res.flags.contains_import_meta, res.flags.is_typescript);
for (res.requested_modules_keys, res.requested_modules_values) |reqk, reqv| {
switch (reqv) {
.none => module_record.addRequestedModuleNullAttributesPtr(identifiers, reqk),
.javascript => module_record.addRequestedModuleJavaScript(identifiers, reqk),
.webassembly => module_record.addRequestedModuleWebAssembly(identifiers, reqk),
.json => module_record.addRequestedModuleJSON(identifiers, reqk),
else => |uv| module_record.addRequestedModuleHostDefined(identifiers, reqk, @enumFromInt(@intFromEnum(uv))),
}
}
{
var i: usize = 0;
for (res.record_kinds) |k| {
if (i + (k.len() catch unreachable) > res.buffer.len) unreachable; // handled above
switch (k) {
.declared_variable, .lexical_variable => {},
.import_info_single => module_record.addImportEntrySingle(identifiers, res.buffer[i + 1], res.buffer[i + 2], res.buffer[i]),
.import_info_single_type_script => module_record.addImportEntrySingleTypeScript(identifiers, res.buffer[i + 1], res.buffer[i + 2], res.buffer[i]),
.import_info_namespace => module_record.addImportEntryNamespace(identifiers, res.buffer[i + 1], res.buffer[i + 2], res.buffer[i]),
.export_info_indirect => module_record.addIndirectExport(identifiers, res.buffer[i + 0], res.buffer[i + 1], res.buffer[i + 2]),
.export_info_local => module_record.addLocalExport(identifiers, res.buffer[i], res.buffer[i + 1]),
.export_info_namespace => module_record.addNamespaceExport(identifiers, res.buffer[i], res.buffer[i + 1]),
.export_info_star => module_record.addStarExport(identifiers, res.buffer[i]),
else => unreachable, // handled above
}
i += k.len() catch unreachable; // handled above
}
}
return module_record;
}
export fn zig__ModuleInfo__destroy(info: *ModuleInfo) void {
info.destroy();
}
const VariableEnvironment = opaque {
extern fn JSC__VariableEnvironment__add(environment: *VariableEnvironment, vm: *bun.jsc.VM, identifier_array: *IdentifierArray, identifier_index: StringID) void;
pub const add = JSC__VariableEnvironment__add;
};
const IdentifierArray = opaque {
extern fn JSC__IdentifierArray__create(len: usize) *IdentifierArray;
pub const create = JSC__IdentifierArray__create;
extern fn JSC__IdentifierArray__destroy(identifier_array: *IdentifierArray) void;
pub const destroy = JSC__IdentifierArray__destroy;
extern fn JSC__IdentifierArray__setFromUtf8(identifier_array: *IdentifierArray, n: usize, vm: *bun.jsc.VM, str: [*]const u8, len: usize) void;
pub fn setFromUtf8(self: *IdentifierArray, n: usize, vm: *bun.jsc.VM, str: []const u8) void {
JSC__IdentifierArray__setFromUtf8(self, n, vm, str.ptr, str.len);
}
};
const SourceCode = opaque {};
const JSModuleRecord = opaque {
extern fn JSC_JSModuleRecord__create(global_object: *bun.jsc.JSGlobalObject, vm: *bun.jsc.VM, module_key: *const IdentifierArray, source_code: *const SourceCode, declared_variables: *VariableEnvironment, lexical_variables: *VariableEnvironment, has_import_meta: bool, is_typescript: bool) *JSModuleRecord;
pub const create = JSC_JSModuleRecord__create;
extern fn JSC_JSModuleRecord__declaredVariables(module_record: *JSModuleRecord) *VariableEnvironment;
pub const declaredVariables = JSC_JSModuleRecord__declaredVariables;
extern fn JSC_JSModuleRecord__lexicalVariables(module_record: *JSModuleRecord) *VariableEnvironment;
pub const lexicalVariables = JSC_JSModuleRecord__lexicalVariables;
extern fn JSC_JSModuleRecord__addIndirectExport(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, export_name: StringID, import_name: StringID, module_name: StringID) void;
pub const addIndirectExport = JSC_JSModuleRecord__addIndirectExport;
extern fn JSC_JSModuleRecord__addLocalExport(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, export_name: StringID, local_name: StringID) void;
pub const addLocalExport = JSC_JSModuleRecord__addLocalExport;
extern fn JSC_JSModuleRecord__addNamespaceExport(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, export_name: StringID, module_name: StringID) void;
pub const addNamespaceExport = JSC_JSModuleRecord__addNamespaceExport;
extern fn JSC_JSModuleRecord__addStarExport(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, module_name: StringID) void;
pub const addStarExport = JSC_JSModuleRecord__addStarExport;
extern fn JSC_JSModuleRecord__addRequestedModuleNullAttributesPtr(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, module_name: StringID) void;
pub const addRequestedModuleNullAttributesPtr = JSC_JSModuleRecord__addRequestedModuleNullAttributesPtr;
extern fn JSC_JSModuleRecord__addRequestedModuleJavaScript(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, module_name: StringID) void;
pub const addRequestedModuleJavaScript = JSC_JSModuleRecord__addRequestedModuleJavaScript;
extern fn JSC_JSModuleRecord__addRequestedModuleWebAssembly(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, module_name: StringID) void;
pub const addRequestedModuleWebAssembly = JSC_JSModuleRecord__addRequestedModuleWebAssembly;
extern fn JSC_JSModuleRecord__addRequestedModuleJSON(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, module_name: StringID) void;
pub const addRequestedModuleJSON = JSC_JSModuleRecord__addRequestedModuleJSON;
extern fn JSC_JSModuleRecord__addRequestedModuleHostDefined(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, module_name: StringID, host_defined_import_type: StringID) void;
pub const addRequestedModuleHostDefined = JSC_JSModuleRecord__addRequestedModuleHostDefined;
extern fn JSC_JSModuleRecord__addImportEntrySingle(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, import_name: StringID, local_name: StringID, module_name: StringID) void;
pub const addImportEntrySingle = JSC_JSModuleRecord__addImportEntrySingle;
extern fn JSC_JSModuleRecord__addImportEntrySingleTypeScript(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, import_name: StringID, local_name: StringID, module_name: StringID) void;
pub const addImportEntrySingleTypeScript = JSC_JSModuleRecord__addImportEntrySingleTypeScript;
extern fn JSC_JSModuleRecord__addImportEntryNamespace(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, import_name: StringID, local_name: StringID, module_name: StringID) void;
pub const addImportEntryNamespace = JSC_JSModuleRecord__addImportEntryNamespace;
};
export fn zig_log(msg: [*:0]const u8) void {
bun.Output.errorWriter().print("{s}\n", .{std.mem.span(msg)}) catch {};
}
const bun = @import("bun");
const std = @import("std");
const DiffFormatter = @import("./bun.js/test/diff_format.zig").DiffFormatter;

View File

@@ -343,6 +343,8 @@ pub const api = struct {
sqlite_embedded = 17,
html = 18,
yaml = 19,
json5 = 20,
md = 21,
_,
pub fn jsonStringify(self: @This(), writer: anytype) !void {

View File

@@ -68,6 +68,7 @@ ts_enums: TsEnumsMap = .{},
/// This is a list of named exports that may exist in a CommonJS module
/// We use this with `commonjs_at_runtime` to re-export CommonJS
has_commonjs_export_names: bool = false,
has_import_meta: bool = false,
import_meta_ref: Ref = Ref.None,
pub const CommonJSNamedExport = struct {

Some files were not shown because too many files have changed in this diff Show More