Compare commits

...

495 Commits

Author SHA1 Message Date
Alistair Smith
6e3ee654f2 Merge remote-tracking branch 'origin' into ali/react 2025-11-04 07:54:17 -08:00
nkxxll
f8dce87f24 docs(bun-types): Replace depricated readableStreamToText in type docu… (#24372)
Co-authored-by: Alistair Smith <hi@alistair.sh>
2025-11-04 07:43:46 -08:00
Jarred Sumner
359f04d81f Improve NAPI property and element handling (#24358)
### What does this PR do?

Refactored NAPI property and element access to use inline methods and
improved error handling. Added comprehensive tests for default value
behavior and numeric string key operations in NAPI, ensuring correct
handling of missing properties, integer keys, and property deletion.
Updated TypeScript tests to cover new scenarios.

### How did you verify your code works?

Tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-11-04 03:21:07 -08:00
robobun
9ce2504554 fix(node:http): unref poll_ref on WebSocket upgrade to prevent CPU spin (#24271)
## Summary

Fixes 100% CPU usage on idle WebSocket servers between bun-v1.2.23 and
bun-v1.3.0.

Many users reported WebSocket server CPU usage jumping to 100% on idle
connections after upgrading to v1.3.0. Investigation revealed a missing
`poll_ref.unref()` call in the WebSocket upgrade path.

## Root Cause

In commit 625e537f5d (#23348), the `OnBeforeOpen` callback mechanism was
removed as part of refactoring the WebSocket upgrade process. However,
this callback contained a critical cleanup step:

```zig
defer ctx.this.poll_ref.unref(ctx.globalObject.bunVM());
```

When a `NodeHTTPResponse` is created, `poll_ref.ref()` is called (line
314) to keep the event loop alive while handling the HTTP request. After
a WebSocket upgrade, the HTTP response object is no longer relevant and
its `poll_ref` must be unref'd to indicate the request processing is
complete.

Without this unref, the event loop maintains an active reference even
after the upgrade completes, causing the CPU to spin at 100% waiting for
events on what should be an idle connection.

## Changes

- Added `poll_ref.unref()` call in `NodeHTTPResponse.upgrade()` after
setting the `upgraded` flag
- Added regression test to verify event loop properly exits after
WebSocket upgrade

## Test Plan

- [x] Code compiles successfully
- [x] Existing WebSocket tests pass
- [x] Manual testing confirms CPU usage returns to normal on idle
WebSocket connections

## Related Issues

Fixes issue reported by users between bun-v1.2.23 and bun-v1.3.0
regarding 100% CPU usage on idle WebSocket servers.

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-11-03 23:27:26 -08:00
Jarred Sumner
5d76a0b2f8 Revert incorrect remaining_in_buffer check 2025-11-03 23:02:22 -08:00
Ciro Spaciari
8a9249c216 fix(tls) undo some changes added in root_certs (#24350)
### What does this PR do?
Restore call to us_get_default_ca_certificates, and
X509_STORE_set_default_paths

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

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

## Summary by CodeRabbit

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

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-11-03 22:59:46 -08:00
Dylan Conway
aad4d800ff add "configVersion" to bun.lock(b) (#24236)
### What does this PR do?

Adds `"configVersion"` to bun.lock(b). The version will be used to keep
default settings the same if they would be breaking across bun versions.

fixes ENG-21389
fixes ENG-21388
### How did you verify your code works?
TODO:
- [ ] new project
- [ ] existing project without configVersion
- [ ] existing project with configVersion
- [ ] same as above but with bun.lockb
- [ ] configVersion@0 defaults to hoisted linker
- [ ] new projects use isolated linker

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-11-03 22:20:07 -08:00
Jarred Sumner
528620e9ae Add postinstall optimizer with native binlink support and script skipping (#24283)
## Summary

This PR introduces a new postinstall optimization system that
significantly reduces the need to run lifecycle scripts for certain
packages by intelligently handling their requirements at install time.

## Key Features

### 1. Native Binlink Optimization

When packages like `esbuild` ship platform-specific binaries as optional
dependencies, we now:
- Detect the native binlink pattern (enabled by default for `esbuild`)
- Find the matching platform-specific dependency based on target CPU/OS
- Link binaries directly from the platform-specific package (e.g.,
`@esbuild/darwin-arm64`)
- Fall back gracefully if the platform-specific package isn't found

**Result**: No postinstall scripts needed for esbuild and similar
packages.

### 2. Lifecycle Script Skipping

For packages like `sharp` that run heavy postinstall scripts:
- Skip lifecycle scripts entirely (enabled by default for `sharp`)
- Prevents downloading large binaries or compiling native code
unnecessarily
- Reduces install time and potential failures in restricted environments

## Configuration

Both features can be configured via `package.json`:

```json
{
  "nativeDependencies": ["esbuild", "my-custom-package"],
  "ignoreScripts": ["sharp", "another-package"]
}
```

Set to empty arrays to disable defaults:
```json
{
  "nativeDependencies": [],
  "ignoreScripts": []
}
```

Environment variable overrides:
- `BUN_FEATURE_FLAG_DISABLE_NATIVE_DEPENDENCY_LINKER=1` - disable native
binlink
- `BUN_FEATURE_FLAG_DISABLE_IGNORE_SCRIPTS=1` - disable script ignoring

## Implementation Details

### Core Components

- **`postinstall_optimizer.zig`**: New file containing the optimizer
logic
- `PostinstallOptimizer` enum with `native_binlink` and `ignore`
variants
  - `List` type to track optimization strategies per package hash
  - Defaults for `esbuild` (native binlink) and `sharp` (ignore)
  
- **`Bin.Linker` changes**: Extended to support separate target paths
  - `target_node_modules_path`: Where to find the actual binary
  - `target_package_name`: Name of the package containing the binary
  - Fallback logic when native binlink optimization fails

### Modified Components

- **PackageInstaller.zig**: Checks optimizer before:
  - Enqueueing lifecycle scripts
  - Linking binaries (with platform-specific package resolution)
  
- **isolated_install/Installer.zig**: Similar checks for isolated linker
mode
  - `maybeReplaceNodeModulesPath()` resolves platform-specific packages
  - Retry logic without optimization on failure

- **Lockfile**: Added `postinstall_optimizer` field to persist
configuration

## Changes Included

- Updated `esbuild` from 0.21.5 to 0.25.11 (testing with latest)
- VS Code launch config updates for debugging install with new flags
- New feature flags in `env_var.zig`

## Test Plan

- [x] Existing install tests pass
- [ ] Test esbuild install without postinstall scripts running
- [ ] Test sharp install with scripts skipped
- [ ] Test custom package.json configuration
- [ ] Test fallback when platform-specific package not found
- [ ] Test feature flag overrides

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

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

* **New Features**
* Native binlink optimization: installs platform-specific binaries when
available, with a safe retry fallback and verbose logging option.
* Per-package postinstall controls to optionally skip lifecycle scripts.
* New feature flags to disable native binlink optimization and to
disable lifecycle-script ignoring.

* **Tests**
* End-to-end tests and test packages added to validate native binlink
behavior across install scenarios and linker modes.

* **Documentation**
  * Bench README and sample app migrated to a Next.js-based setup.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2025-11-03 20:36:22 -08:00
robobun
7197fb1f04 Fix Module._resolveFilename to pass options.paths to overridden functions (#24325)
Fixes Next.js 16 + React Compiler build failure when using Bun runtime.

## Issue
When `Module._resolveFilename` was overridden (e.g., by Next.js's
require-hook), Bun was not passing the `options` parameter (which
contains `paths`) to the override function. This caused resolution
failures when the override tried to use custom resolution paths.

Additionally, when `Module._resolveFilename` was called directly with
`options.paths`, Bun was ignoring the paths parameter and using default
resolution.

## Root Causes
1. In `ImportMetaObject.cpp`, when calling an overridden
`_resolveFilename` function, the options object with paths was not being
passed as the 4th argument.

2. In `NodeModuleModule.cpp`, `jsFunctionResolveFileName` was calling
`Bun__resolveSync` without extracting and using the `options.paths`
parameter.

## Solution
1. In `ImportMetaObject.cpp`: When `userPathList` is provided, construct
an options object with `{paths: userPathList}` and pass it as the 4th
argument to the overridden `_resolveFilename` function.

2. In `NodeModuleModule.cpp`: Extract `options.paths` from the 4th
argument and call `Bun__resolveSyncWithPaths` when paths are provided,
instead of always using `Bun__resolveSync`.

## Reproduction
Before this fix, running:
```bash
bun --bun next build --turbopack
```
on a Next.js 16 app with React Compiler enabled would fail with:
```
Cannot find module './node_modules/babel-plugin-react-compiler'
```

## Testing
- Added comprehensive tests for `Module._resolveFilename` with
`options.paths`
- Verified Next.js 16 + React Compiler + Turbopack builds successfully
with Bun
- All 5 new tests pass with the fix, 3 fail without it
- All existing tests continue to pass

## Files Changed
- `src/bun.js/bindings/ImportMetaObject.cpp` - Pass options to override
- `src/bun.js/modules/NodeModuleModule.cpp` - Handle options.paths in
_resolveFilename
- `test/js/node/module/module-resolve-filename-paths.test.js` - New test
suite

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-03 20:28:33 -08:00
robobun
946470dcd7 Refactor: move FetchTasklet to separate file (#24330)
## Summary

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

## Changes

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

## Impact

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

## Test plan

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-11-03 02:21:49 -08:00
Michael H
d76fad3618 fix update interactive to keep npm aliases (#23903)
### What does this PR do?

fixes #23901

### How did you verify your code works?

with a test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-11-03 02:12:24 -08:00
robobun
bdaab89253 Fix bun update --interactive not installing packages (#24280)
## Summary

Fixes a bug where `bun update --interactive` only updated `package.json`
but didn't actually install the updated packages. Users had to manually
run `bun install` afterwards.

## Root Cause

The bug was in `savePackageJson()` in
`src/cli/update_interactive_command.zig`:

1. The function wrote the updated `package.json` to disk
2. But it **didn't update the in-memory cache**
(`WorkspacePackageJSONCache`)
3. When `installWithManager()` ran, it called `getWithPath()` which
returned the **stale cached version**
4. So the installation proceeded with the old dependencies

## The Fix

Update the cache entry after writing to disk (line 116):
```zig
package_json.*.source.contents = new_package_json_source;
```

This matches the behavior in `updatePackageJSONAndInstall.zig` line 269.

## Test Plan

Added comprehensive regression tests in
`test/cli/update_interactive_install.test.ts`:
-  Verifies that `package.json` is updated
-  Verifies that `node_modules` is updated (this was failing before the
fix)
-  Tests both normal update and `--latest` flag
-  Compares installed version to confirm packages were actually
installed

Run tests with:
```bash
bun bd test test/cli/update_interactive_install.test.ts
```

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-11-03 01:57:02 -08:00
Jarred Sumner
797847639a Fix process.mainModule = ${value} (#23698)
### What does this PR do?

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

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

## Implementation

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

## API

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

## Test Coverage

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

All tests pass with 24 assertions.

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-11-01 22:43:21 -07:00
Dylan Conway
f770b1b1c7 fix(install): fix optional peer resolving (#24272)
### What does this PR do?
Allows optional peers to resolve to package if possible.

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

fixes #23725
most likely fixes #23895

fixes ENG-21411

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

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

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

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

---------

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

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

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

---------

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

Updates libdeflate to version v1.25

Compare:
96836d7d9d...c8c56a20f8

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

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

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

## What does this document?

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

## Visual aids

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

## Code references

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

## Examples

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

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-01 20:59:35 -07:00
Jarred Sumner
8058d78b6a Deflake test/cli/run/cpu-prof.test.ts 2025-11-01 20:17:56 -07:00
Jarred Sumner
8b98746808 Update .coderabbit.yaml 2025-11-01 19:58:13 -07:00
Jarred Sumner
f50b44e35b Update .coderabbit.yaml
Update .coderabbit.yaml
2025-11-01 19:56:55 -07:00
Jarred Sumner
b02d46498e Don't set isIdle when it is not in fact idle (#24274)
### What does this PR do?

### How did you verify your code works?


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

## Summary by CodeRabbit

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

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

Example of creating empty buffer:

a7f62a4caa/src/binding.cc (L687)

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

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

## Changes

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

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

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

## Testing

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

## Impact

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

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

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-31 19:50:55 -07:00
robobun
c5def80191 Fix Output.enable_ansi_colors usage to check stdout vs stderr (#24212)
## Summary

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

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

## Changes

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

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

### Updated by Output Destination

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

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

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

## Test Plan

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

## Stats

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

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

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

---------

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

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

## Changes

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

## Implementation Details

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

## Testing

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

## Test Output

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

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

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-29 21:05:25 -07:00
robobun
646aede0d4 Fix CPU profiler timestamps - use setDouble() instead of setInteger() (#24206)
## Summary

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

## The Problem

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

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

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

## Root Cause

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

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

## The Fix

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

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

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

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

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

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

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

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

## Testing

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

All tests pass 

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

## Why VSCode Worked But Chrome DevTools Didn't

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

## References

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

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

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

---------

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

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

## Implementation Details

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

## Key Features

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

## Technical Challenges Solved

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

## Testing

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

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

## Example Usage

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

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

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

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

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

---------

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

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

## Changes

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

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

Received: this is new
```

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

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

Received: this is new
```

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

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

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

## Implementation Details

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

## Test Plan

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

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

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

---------

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

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

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

## Changes

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

## Test plan

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

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-29 15:41:44 -07:00
Meghan Denny
9d4a04cff9 scripts/auto-close-duplicates.ts: dont change the labels 2025-10-29 14:57:32 -07:00
Jarred Sumner
9d0ef94557 Mark test as flaky on macOS CI 2025-10-29 14:51:29 -07:00
Jarred Sumner
a5f8b0e8dd react-dom-server requires messagechannel now i guess 2025-10-29 08:14:08 +01:00
Jarred Sumner
fe1bc56637 Add workerd benchmark 2025-10-29 07:16:32 +01:00
robobun
98c04e37ec Fix source index bounds check in sourcemap decoder (#24145)
## Summary

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

## Changes

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

## Test plan

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

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-28 12:32:53 -07:00
robobun
4f1b90ad1d Fix EventEmitter crash in removeAllListeners with removeListener meta-listener (#24148)
## Summary

Fixes #24147

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

## Bug Description

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

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

## Root Cause

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

## Fix

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

## Test plan

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-28 12:32:15 -07:00
robobun
51431b6e65 Fix sourcemap comparator to use strict weak ordering (#24146)
## Summary

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

## Changes

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

## Problem

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

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

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

## Test plan

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

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-28 12:31:42 -07:00
robobun
eb77bdd286 Refactor: Split sourcemap.zig into separate struct files (#24141)
## Summary

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

## Changes

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

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

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

## Testing

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

## Before

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

## After

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-28 00:05:16 -07:00
Jarred Sumner
523fc14d76 Deflake websocket test 2025-10-27 18:58:06 -07:00
Felipe Cardozo
a0a69ee146 fix: body already used error to throw TypeError (#24114)
Should fix https://github.com/oven-sh/bun/issues/24104

### What does this PR do?

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


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

---------

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

Fixes #19111

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

## Root Cause

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

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

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

## Impact

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

## Fix

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

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

## Test Plan

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-27 15:24:38 -07:00
robobun
6580b563b0 Refactor Subprocess to use JSRef instead of hasPendingActivity (#24090)
## Summary

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

## Changes

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

## How It Works

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

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

## Benefits

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

## Testing

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

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

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

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

---------

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

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

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

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

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

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

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

## Motivation

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

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

## Test plan

Documentation-only change, no functional changes.

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-26 01:28:27 -07:00
github-actions[bot]
4c00d8f016 deps: update elysia to 1.4.13 (#24085)
## What does this PR do?

Updates elysia to version 1.4.13

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

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

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

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

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

## Changes

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

## Testing

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-25 20:43:02 -07:00
Meghan Denny
a2b262ed69 ci: update bun version to 1.3.1 (#24053) [publish images] 2025-10-25 15:53:02 -07:00
Meghan Denny
fb1fbe62e6 ci: update alpine linux to 3.22 (#24052) [publish images] 2025-10-25 15:52:34 -07:00
Jarred Sumner
d2c2842420 Autoformat 2025-10-25 00:05:28 -07:00
Jarred Sumner
0fba69d50c Add some internal deprecation @compileError messages 2025-10-24 23:42:20 -07:00
SUZUKI Sosuke
f4b6396eac Fix unhandled exception in JSC__JSPromise__wrap when resolving promise (#23961)
### What does this PR do?

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

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

### How did you verify your code works?

new and existing tests

---------

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

Fixes #23133

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

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

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

## Root Cause

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

## Solution

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

## Changes

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

## Testing

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pfg <pfg@pfg.pw>
2025-10-24 19:30:43 -07:00
robobun
5a7b824091 fix(css): process color-scheme rules inside @layer blocks (#24034)
## Summary

Fixes #20689

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

## Changes

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

## Test Plan

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

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

## Before

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

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

## After

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

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-24 19:27:14 -07:00
robobun
a3f18b9e0e feat(test): implement onTestFinished hook for bun:test (#24038)
## Summary

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

## Implementation

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

## Execution Order

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

## Test Plan

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

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

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

---------

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

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

The comments clarify:

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

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

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

### How did you verify your code works?

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

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

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

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

### How did you verify your code works?

Tests.

---------

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

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

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

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

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

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

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

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

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

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

---------

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

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

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

### How did you verify your code works?

Tests

---------

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

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

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

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

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

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

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

## Bug Fixed

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

## Changes

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

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

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

## Testing

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

## Implementation Notes

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

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

This makes the ownership semantics explicit and type-safe.

---------

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

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

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

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

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

Fixes #23966

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-22 16:15:29 -07:00
Jarred Sumner
b90abdda08 BUmp 2025-10-22 12:13:14 -07:00
Dylan Conway
89fa0f3439 Refactor napi_env to use Ref-counted NapiEnv (#23940)
### What does this PR do?

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

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

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

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

## Details

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

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

## Changes

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

## Test plan

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

Fixes the panic reported in Sentry/crash reports.

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-21 19:42:01 -07:00
Jarred Sumner
45841d6630 Check if toSlice has a bug (#23889)
### What does this PR do?
toSlice has a bug

### How did you verify your code works?

---------

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

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

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

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

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

Adds missing exception check for ReadableStream.

### How did you verify your code works?

Tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-21 18:19:34 -07:00
Jarred Sumner
1aaabcf4de Add missing error handling in ShellWriter's start() method & delete assert() footgun (#23935)
### What does this PR do?

### How did you verify your code works?

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-21 18:18:37 -07:00
Marko Vejnovic
3bc78598c6 bug(SlicedString.zig): Fix incorrect assertion in SlicedString.sub (#23934)
### What does this PR do?

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

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

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

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

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

### How did you verify your code works?

CI

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

---------

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

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

### What's included:

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

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

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

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

### How it works:

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

### Requirements:

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

## Test plan

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-21 14:57:22 -07:00
robobun
cd8043b76e Fix Bun.build() compile API to properly apply sourcemaps (#23916)
## Summary

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

## Problem

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

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

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

## Root Cause

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

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

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

## Solution

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

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

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

## Tests

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

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

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

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-21 14:25:08 -07:00
Dylan Conway
840c6ca471 fix(install): avoid sleep for peer tasks when there are none (#23881)
### What does this PR do?

### How did you verify your code works?

---------

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

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

`publicHoistPattern` only affects the isolated linker.

---

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

---

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

---

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

---------

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

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

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

### How did you verify your code works?

There is a test

---------

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

### What does this PR do?

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

Fixes #23723 

### How did you verify your code works?

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

---------

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

## Summary

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

## Root Cause

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

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

## Changes

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

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

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

## Test Plan

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

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-10-20 20:37:51 -07:00
Jarred Sumner
25a8dea38b Ensure we add sourcemappings for S.Comment (#23871)
### What does this PR do?



### How did you verify your code works?

---------

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

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

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-20 19:48:47 -07:00
robobun
b1f83d0bb2 fix: Response.json() throws TypeError for non-JSON serializable top-level values (#21258)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Meghan Denny <meghan@bun.com>
2025-10-20 19:46:22 -07:00
Jarred Sumner
32a28385dd Guard fs.watchFile's last_stat field with a mutex (#23840)
### What does this PR do?

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

Fixes BUN-MGB

### How did you verify your code works?

---------

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

Removes unused code.

### How did you verify your code works?

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

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

## Changes

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

## Test plan

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

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-20 19:28:34 -07:00
robobun
686998ed3d Fix panic when WebSocket close frame is fragmented across TCP packets (#23832)
## Summary

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

## The Bug

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

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

## Root Causes

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

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

## The Fix

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

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

## Testing

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

## Related

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

---

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

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

---------

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

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

---------

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

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

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

### How did you verify your code works?

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

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

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

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

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-20 16:32:04 -07:00
Alistair Smith
e306ac831e Merge branch 'main' into ali/react 2025-10-21 08:06:12 +09:00
robobun
ebc0cfeacd fix(yaml): double-quoted strings with '...' incorrectly trigger document end error (#23491)
### What does this PR do?

Fixes #23489

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

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

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

### Root cause:

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

### The fix:

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

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

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

### How did you verify your code works?

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

cc @dylan-conway for review

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2025-10-20 14:19:22 -07:00
Jarred Sumner
abb85018df Fixes #23649 (#23853)
### What does this PR do?

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

### How did you verify your code works?

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

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

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

## Root Cause

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

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

## Call Chain

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

## Fix

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

## Test Plan

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

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

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-20 12:31:08 -07:00
robobun
3921f76ff8 Add --only-failures flag to bun:test (#23312)
## Summary

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

## Motivation

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

## Changes

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

## Usage

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

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

Expected: 3
Received: 2

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

## Test Plan

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pfg <pfg@pfg.pw>
2025-10-19 23:31:29 -07:00
robobun
74fa49963c Fix: Error when using bun build --no-bundle with HTML entrypoint (#23572)
Fixes #23569

## Summary

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

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

## Changes

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

## Test Plan

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

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

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

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-19 23:29:29 -07:00
Dylan Conway
fb2bf3fe83 fix(pack): always include bin even if not included by files (#23606)
### What does this PR do?
Fixes #23521
### How did you verify your code works?
Added 3 previously failing tests for `"bin"`, `"directories.bin"`, and
deduplicating entry in both `"bin.directories"` and `"files"`

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-19 23:28:59 -07:00
Dylan Conway
4539d241a1 WIP: fix windows ENOTCONN (#23772)
### What does this PR do?

### How did you verify your code works?

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-19 22:27:08 -07:00
github-actions[bot]
6f3dfa79bb deps: update elysia to 1.4.12 (#23820)
## What does this PR do?

Updates elysia to version 1.4.12

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

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

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

Fixes two critical bugs in Bun Shell:

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

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

## Changes

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

## Test plan

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

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

---------

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

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

## Changes

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

## Testing

Manually tested with various test files:

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

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

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

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

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

## Notes

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

---------

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

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

## Problem

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

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

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

## Solution

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

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

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

## Test

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

## Verification

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-19 21:20:56 -07:00
Alistair Smith
ed1eb21093 Merge branch 'main' of github.com:oven-sh/bun into ali/react 2025-10-09 15:18:01 -07:00
Alistair Smith
4a4a37796b Merge branch 'main' into ali/react 2025-10-07 22:02:46 -07:00
Alistair Smith
7aef153f5d refactor: Remove experimental types and related references from the codebase 2025-10-07 18:17:00 -07:00
Alistair Smith
3cb64478d7 fix: Merge with 1.3 new Bun.serve types 2025-10-07 17:03:23 -07:00
Alistair Smith
7dfed6b986 Merge branch 'main' of github.com:oven-sh/bun into ali/react 2025-10-07 16:50:14 -07:00
Alistair Smith
5972cf24cb Merge remote-tracking branch 'origin/main' into ali/react 2025-10-06 16:24:19 -07:00
Alistair Smith
329c79364d Merge branch 'main' into ali/react 2025-10-06 16:22:38 -07:00
Alistair Smith
da5bf73494 clean up args 2025-10-03 16:53:59 -07:00
Alistair Smith
fbd58db004 changes 2025-10-03 16:11:37 -07:00
Alistair Smith
81999c26e6 extend the debug timeout a little 2025-10-03 15:05:50 -07:00
Alistair Smith
dde1f9e610 pin peechy 2025-10-03 14:26:50 -07:00
Alistair Smith
c9b5ba1c96 bump builtin react-refresh 2025-10-03 13:17:53 -07:00
Alistair Smith
74f4fcf2a6 Revert launch.json 2025-10-03 12:58:41 -07:00
Alistair Smith
031f12442d fix: We do require react/react-dom 2025-10-03 12:53:48 -07:00
autofix-ci[bot]
a20a718e48 [autofix.ci] apply automated fixes 2025-10-03 18:41:41 +00:00
Alistair Smith
33537b6ec1 Merge branch 'main' into ali/react 2025-10-03 11:38:33 -07:00
Alistair Smith
952436fc4c returnIfException() 2025-10-03 11:36:02 -07:00
Alistair Smith
31352bc646 fix test 2025-10-03 11:36:02 -07:00
Alistair Smith
ff84564c11 fix that 2025-10-03 11:36:02 -07:00
Alistair Smith
cc78a1bca1 fix: re-inject react-refresh in auto mode 2025-10-03 11:36:02 -07:00
Alistair Smith
3ca89abacf remove 2025-10-02 18:33:40 -07:00
Alistair Smith
2f02e4e31d Merge branch 'main' of github.com:oven-sh/bun into ali/react 2025-10-02 18:21:29 -07:00
Alistair Smith
efb508e2ae chore: Bump & pin React 2025-10-02 18:14:47 -07:00
Alistair Smith
86af3dd034 fix test 2025-10-02 17:33:33 -07:00
autofix-ci[bot]
a6d3808ad8 [autofix.ci] apply automated fixes 2025-10-02 22:54:04 +00:00
Alistair Smith
2153fe4163 Merge branch 'main' of github.com:oven-sh/bun into ali/react 2025-10-02 15:50:40 -07:00
Alistair Smith
6977b36215 change 2025-09-30 22:04:08 -07:00
Alistair Smith
ceaab9eda3 tests: Fix spacing in routes test expectation 2025-09-30 19:33:14 -07:00
Alistair Smith
f262e32368 tidy 2025-09-30 19:18:21 -07:00
Alistair Smith
69a76d44f9 types 2025-09-30 18:52:50 -07:00
Alistair Smith
fc9538baf1 move 2025-09-30 18:46:34 -07:00
Alistair Smith
72b7956385 remove old property 2025-09-30 18:13:46 -07:00
Alistair Smith
62b296bb43 message 2025-09-30 18:08:10 -07:00
Alistair Smith
cb14f70a43 remove dated .auto() implementation 2025-09-30 18:05:30 -07:00
Alistair Smith
38511375f8 unused for now 2025-09-30 17:50:14 -07:00
Alistair Smith
06cfe2ead1 bump react 2025-09-30 17:48:05 -07:00
Alistair Smith
4f219503fe fix production.test.ts resolving bun-framework-react 2025-09-30 17:41:22 -07:00
Alistair Smith
b2353d687e Merge branch 'main' of github.com:oven-sh/bun into ali/react 2025-09-30 17:25:53 -07:00
Alistair Smith
65e66099f7 fix: updated load expectation 2025-09-30 17:25:25 -07:00
Alistair Smith
c534f0caa0 Merge branch 'main' into ali/react 2025-09-30 15:21:39 -07:00
Alistair Smith
a873152aeb Revert bundle_v2.zig 2025-09-30 15:19:17 -07:00
Alistair Smith
a17eb07d48 revert some unnecessary changes 2025-09-30 15:15:39 -07:00
Alistair Smith
1381de4d18 Merge branch 'main' of github.com:oven-sh/bun into ali/react 2025-09-30 15:04:48 -07:00
Alistair Smith
8d8b037e94 rm 2025-09-29 16:16:22 -07:00
Alistair Smith
f43a175f72 use options 2025-09-29 16:07:49 -07:00
Alistair Smith
e1ad16f857 Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into ali/react 2025-09-29 15:42:55 -07:00
Zack Radisic
661a246039 fix 2025-09-28 18:02:58 -07:00
Zack Radisic
d0fed20c89 Revert "fix leak"
This reverts commit 1c6165e68a.
2025-09-28 17:43:20 -07:00
Zack Radisic
1c6165e68a fix leak 2025-09-27 15:39:40 -07:00
Zack Radisic
daefbfb453 Merge branch 'main' into zack/ssg-3 2025-09-27 15:09:54 -07:00
Zack Radisic
971e4679cf Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into zack/ssg-3 2025-09-27 14:57:39 -07:00
Zack Radisic
49a9dc7ddf fix banword 2025-09-27 14:55:12 -07:00
Zack Radisic
b5a5fea9ae fix 2025-09-27 00:55:48 -07:00
Zack Radisic
243a237a62 use jsc call conv 2025-09-27 00:29:20 -07:00
Zack Radisic
49cfda12a8 Merge branch 'zack/ssg-3' of https://github.com/oven-sh/bun into zack/ssg-3 2025-09-27 00:28:16 -07:00
Zack Radisic
ab579a3cc3 less confusing 2025-09-27 00:27:35 -07:00
Zack Radisic
8cd9b4eae6 update leaksan.supp 2025-09-27 00:18:34 -07:00
Zack Radisic
dd9860f501 Merge branch 'main' into zack/ssg-3 2025-09-26 23:50:10 -07:00
Zack Radisic
756e590782 fix ban words 2025-09-26 22:07:39 -07:00
Alistair Smith
c62613e765 better file hash 2025-09-26 19:50:25 -07:00
Alistair Smith
7f96bf8f13 Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into ali/react 2025-09-26 19:31:00 -07:00
Alistair Smith
cd800b02f5 decrash 2025-09-26 19:30:53 -07:00
Zack Radisic
de999f78ab resolve more comments 2025-09-26 02:04:35 -07:00
Zack Radisic
24748104ce okie dokie 2025-09-26 01:37:55 -07:00
Zack Radisic
3fca3b97d9 resolve comments 2025-09-26 01:11:29 -07:00
Alistair Smith
4cec2ecdc6 changes 2025-09-26 00:09:23 -07:00
Zack Radisic
cdeb7bfb00 proper event loop stuff 2025-09-25 20:35:42 -07:00
Alistair Smith
98b24f5797 2025-09-25 20:05:45 -07:00
Alistair Smith
678843fb59 Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into ali/react 2025-09-25 20:00:06 -07:00
Alistair Smith
7227745249 0.0.0-canary.7 2025-09-25 19:59:35 -07:00
Zack Radisic
472e2d379f fixes 2025-09-25 19:54:39 -07:00
autofix-ci[bot]
16360c9432 [autofix.ci] apply automated fixes 2025-09-26 02:46:56 +00:00
Alistair Smith
1b3d0d5c40 regen 2025-09-25 19:43:57 -07:00
Alistair Smith
799248bfb4 use vendored rsdb 2025-09-25 19:42:06 -07:00
Alistair Smith
a2689c03e9 change 2025-09-25 19:31:10 -07:00
Zack Radisic
2a7e2c9cf3 Remove unncessary dupe 2025-09-25 19:13:59 -07:00
Alistair Smith
4f0d2a5624 throw if no exports instead of silently failing 2025-09-25 18:40:49 -07:00
Alistair Smith
23230112b0 types 2025-09-25 18:31:29 -07:00
Alistair Smith
c2c2a1685a changes 2025-09-25 18:15:31 -07:00
Alistair Smith
09716704bb pageModule might not resolve 2025-09-25 17:46:18 -07:00
Alistair Smith
2d3223c5a6 Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into ali/react 2025-09-25 17:34:56 -07:00
Alistair Smith
891ea726d6 changes 2025-09-25 17:29:52 -07:00
Zack Radisic
11eddb2cf1 resolve comments 2025-09-25 15:20:27 -07:00
autofix-ci[bot]
0cc63255b1 [autofix.ci] apply automated fixes 2025-09-25 07:05:28 +00:00
Zack Radisic
71a5f9fb26 Delete console logs 2025-09-25 00:02:14 -07:00
Zack Radisic
b257967189 Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into zack/ssg-3 2025-09-25 00:00:48 -07:00
Zack Radisic
4e629753cc better way to do Response.render(...) 2025-09-24 23:57:45 -07:00
Jarred Sumner
7204820f19 Update BakeGlobalObject.cpp 2025-09-24 23:47:29 -07:00
Jarred Sumner
af3a1ffd46 Update BakeGlobalObject.cpp 2025-09-24 23:47:18 -07:00
Jarred Sumner
2ff068dad2 Update visitExpr.zig 2025-09-24 23:07:27 -07:00
Alistair Smith
927065238b allow warnings in bun install 2025-09-24 21:55:31 -07:00
Alistair Smith
fa727b22de remove 2025-09-24 21:45:23 -07:00
Alistair Smith
f20b0ced8e tidy bake harness 2025-09-24 21:41:34 -07:00
Alistair Smith
17fdb5bcdf move this 2025-09-24 21:37:25 -07:00
Alistair Smith
f65d89ff8b changes 2025-09-24 21:34:49 -07:00
Alistair Smith
c1931c11fe lots of Framework interface documentation 2025-09-24 20:24:06 -07:00
Alistair Smith
67d27499c3 canary.5 2025-09-24 19:49:34 -07:00
Alistair Smith
85db75611b canary.3 2025-09-24 19:38:24 -07:00
Alistair Smith
61519b320d reorganise 2025-09-24 19:20:30 -07:00
Alistair Smith
c129d683cd types & other changes 2025-09-24 19:08:31 -07:00
Alistair Smith
0b0ffbf250 Merge branch 'zack/ssg-3' into ali/react 2025-09-24 18:58:13 -07:00
Alistair Smith
c64dd684c8 vendor react-server-dom-bun 2025-09-24 18:55:19 -07:00
Alistair Smith
5aa5906ccf Merge branch 'main' into zack/ssg-3 2025-09-24 18:48:29 -07:00
Alistair Smith
c93d8cf12b changes 2025-09-24 13:53:46 -07:00
Alistair Smith
1a1091fd2c 2025-09-23 21:49:34 -07:00
Alistair Smith
bdf77f968c Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into ali/react 2025-09-23 21:12:39 -07:00
Zack Radisic
457b4a46b3 Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into zack/ssg-3 2025-09-23 21:11:50 -07:00
Zack Radisic
3b2bea9820 better way to escape 2025-09-23 21:11:28 -07:00
Alistair Smith
5b4b99e2c4 Merge branch 'zack/ssg-3' into ali/react 2025-09-23 21:08:04 -07:00
Alistair Smith
da2be3f582 cleanup 2025-09-23 20:55:33 -07:00
Alistair Smith
7282e92e48 try fix ci for bun-framework-react 2025-09-23 20:40:03 -07:00
Alistair Smith
80c28b6280 change 2025-09-23 18:55:03 -07:00
Alistair Smith
e40238fdc2 instant crash 2025-09-23 18:27:05 -07:00
Alistair Smith
166e961202 listen for shell 2025-09-23 18:24:18 -07:00
Zack Radisic
58ecff4e0c Merge branch 'main' into zack/ssg-3 2025-09-23 18:06:43 -07:00
Alistair Smith
a548ae7038 remove default title 2025-09-23 17:54:59 -07:00
Alistair Smith
bbaabedce6 fix: use CatchScope 2025-09-23 16:55:29 -07:00
Alistair Smith
f84f90c09f rm .app test 2025-09-23 16:51:29 -07:00
Zack Radisic
43a7b6518a fix 2025-09-23 15:46:31 -07:00
Alistair Smith
c85ab5218e feat: report "use client" warning on more well known client hooks 2025-09-23 14:53:57 -07:00
Alistair Smith
bade403361 fix: Don't report more than once for missing "use client" calls 2025-09-23 14:45:10 -07:00
Alistair Smith
047eecc90c Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into ali/react 2025-09-23 14:22:31 -07:00
Zack Radisic
f03a1ab1c9 Update 2025-09-23 13:49:33 -07:00
Zack Radisic
1e3057045c Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into zack/ssg-3 2025-09-23 13:46:11 -07:00
Zack Radisic
e92fd08930 make it work 2025-09-23 02:32:19 -07:00
autofix-ci[bot]
deb3e94948 [autofix.ci] apply automated fixes 2025-09-23 09:17:41 +00:00
Zack Radisic
1b01f7c0da Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into zack/ssg-3 2025-09-23 02:12:33 -07:00
Zack Radisic
5e256e4b1f fix 2025-09-23 02:09:43 -07:00
Alistair Smith
fc6fdbe300 rm 2025-09-22 23:20:56 -07:00
Alistair Smith
247629aded cleaning 2025-09-22 20:24:20 -07:00
Alistair Smith
2894e8d309 change 2025-09-22 20:03:16 -07:00
Alistair Smith
cc84e271ff changes 2025-09-22 18:10:57 -07:00
Alistair Smith
c07150d5b1 types 2025-09-22 16:27:10 -07:00
Alistair Smith
b0d3815cf9 Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into ali/react 2025-09-22 16:24:39 -07:00
Zack Radisic
f145d8c30c Merge branch 'main' into zack/ssg-3 2025-09-22 15:59:55 -07:00
Alistair Smith
3a23965581 Merge remote-tracking branch 'origin/zack/ssg-3' into ali/react 2025-09-22 15:56:42 -07:00
Alistair Smith
0b45b9c29e Add request property to bun:app module and enhance type definitions
- Added `request` property to the `bun:app` module for better request handling.
- Updated `hmr-runtime-server.ts` to use `RouteMetadata` for improved type safety.
- Introduced `$ERR_SSR_RESPONSE_EXPECTED` error function in builtins for SSR response handling.
2025-09-22 15:49:29 -07:00
Zack Radisic
9d679811cd get http method 2025-09-22 14:45:41 -07:00
Zack Radisic
cda3eb5396 delete stupid slop tests 2025-09-22 14:43:26 -07:00
Zack Radisic
b17dccc6e0 fix that 2025-09-21 14:31:36 -07:00
Alistair Smith
99a80a6fe6 changes 2025-09-19 18:47:08 -07:00
Alistair Smith
8b7bc0fe59 dont attempt to resolve initial rsc payload when doing first render on server 2025-09-19 18:38:53 -07:00
Alistair Smith
7e89ca3d2f link 2025-09-19 18:26:38 -07:00
Alistair Smith
d8fa01ed41 basic impl 2025-09-19 18:16:09 -07:00
Alistair Smith
361cd05676 move framework entrypoints 2025-09-19 18:09:14 -07:00
Zack Radisic
dbe15d3020 okay fuck 2025-09-19 17:44:08 -07:00
Alistair Smith
3a200e8097 overlay: print err message with whitespace formatting 2025-09-19 17:43:05 -07:00
Alistair Smith
2701292a9f edit react framework 2025-09-19 17:34:38 -07:00
Alistair Smith
61b1aded3e push 2025-09-19 17:27:14 -07:00
Alistair Smith
36a414c087 change import to type and add error handling for synthetic modules 2025-09-19 17:22:28 -07:00
Alistair Smith
ac02036879 Merge remote-tracking branch 'origin/zack/ssg-3' into ali/react 2025-09-19 17:01:07 -07:00
Alistair Smith
612d41185b change versions 2025-09-19 17:00:40 -07:00
Alistair Smith
59b34efea8 link 2025-09-19 16:58:51 -07:00
Alistair Smith
243f3652f1 remove old commented code 2025-09-19 16:52:03 -07:00
Alistair Smith
11dc2fae56 revert HotReloadEvent.zig 2025-09-19 16:36:54 -07:00
Alistair Smith
0919f237a5 remove 2025-09-19 16:13:59 -07:00
Alistair Smith
691e731404 changes 2025-09-19 16:12:32 -07:00
Alistair Smith
1a19be07ee remove unnecessary data output in development mode 2025-09-19 16:10:37 -07:00
Alistair Smith
903ac7bdd5 Refactor DevServer: remove unused bakeDebug output and clean up route bundling logic 2025-09-19 16:00:55 -07:00
Alistair Smith
0ac6b17d4a revert some changes 2025-09-19 15:53:49 -07:00
Alistair Smith
921e3578b1 change 2025-09-19 15:51:05 -07:00
Alistair Smith
101bcb1ea0 there is no is_built_in_react anymore 2025-09-19 15:45:11 -07:00
Alistair Smith
f691ea1e96 rm 2025-09-19 15:44:23 -07:00
Alistair Smith
53208e2538 .staticRouters is not implemented 2025-09-19 15:35:10 -07:00
Alistair Smith
53299d78b1 refactor framework definition and options interface in bun-types; remove package load logic from Framework struct 2025-09-19 15:20:34 -07:00
Alistair Smith
363c4a5c06 revert 2025-09-19 14:29:48 -07:00
Alistair Smith
6e6120640e remove react special case resolution 2025-09-19 14:29:02 -07:00
Alistair Smith
6556138c7b types 2025-09-19 14:08:00 -07:00
Alistair Smith
aea7b196e6 Revert visitExpr 2025-09-19 14:07:51 -07:00
Zack Radisic
b3f92b0889 fix test 2025-09-19 13:52:35 -07:00
Zack Radisic
dab797b834 fix test 2025-09-18 20:52:35 -07:00
Alistair Smith
a8ff3f8ac3 move module map 2025-09-18 18:58:12 -07:00
Alistair Smith
b516eedc67 fix mod 2025-09-18 17:57:46 -07:00
Alistair Smith
bcea163fd2 update framework def 2025-09-18 17:55:28 -07:00
Alistair Smith
a47cbef4ca restore bundler options 2025-09-18 17:39:48 -07:00
Alistair Smith
90e68fa095 use different react bundles 2025-09-18 17:33:49 -07:00
Alistair Smith
da0b090834 use the specific bundles 2025-09-18 17:25:26 -07:00
Alistair Smith
e6aced6637 remove 2025-09-18 17:17:27 -07:00
Alistair Smith
ce560cd318 Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into ali/react 2025-09-18 17:16:07 -07:00
Alistair Smith
e554c4e1ca Update bun-framework-react dependencies and imports
- Changed the version of `react-server-dom-bun` from a local link to a specific experimental version in `package.json` and `bun.lock`.
- Updated the import path for `renderToPipeableStream` to use the `.node` variant for compatibility.
- Added `neo-async` as a dependency for `react-server-dom-bun` to ensure proper functionality.
2025-09-18 14:18:11 -07:00
Zack Radisic
731f42ca72 fix test 2025-09-17 20:49:55 -07:00
Zack Radisic
f33a852a80 merge 2025-09-17 17:14:56 -07:00
Zack Radisic
f5122bdbf1 use import instead of class 2025-09-17 17:09:18 -07:00
Alistair Smith
c29c69b9b5 types 2025-09-17 13:55:46 -07:00
Zack Radisic
916d44fc45 Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into zack/ssg-3 2025-09-16 23:12:15 -07:00
Zack Radisic
421a4f37cd FIX the concurrent request bug 2025-09-16 21:55:05 -07:00
Alistair Smith
d0da7076e6 types 2025-09-16 16:35:41 -07:00
Alistair Smith
ea78d564da bump react 2025-09-16 16:29:45 -07:00
Alistair Smith
6338d55f70 continue 2025-09-16 15:56:29 -07:00
Alistair Smith
d3bdc77274 types 2025-09-16 15:56:24 -07:00
Alistair Smith
ecd2fed665 try with redo of react-server-dom-bun 2025-09-16 15:11:22 -07:00
Alistair Smith
28447ab578 Refactor HotReloadEvent and comment out unused code in BundleV2
- Updated `HotReloadEvent.zig` to use duplicated strings for extra files to prevent potential memory issues.
- Commented out unused code related to "bun:app" in `bundle_v2.zig` to improve clarity and maintainability.
2025-09-15 21:55:59 -07:00
Alistair Smith
3e798f1787 type only import 2025-09-15 21:24:12 -07:00
Alistair Smith
a64f073ad3 minimize 2025-09-15 21:13:45 -07:00
Alistair Smith
bb19610f0d Update Bun framework to use react-server-dom-webpack and upgrade dependencies
- Changed module imports from "react-server-dom-bun" to "react-server-dom-webpack" in multiple files.
- Updated dependencies in package.json and bun.lock to use newer versions of React, React DOM, React Refresh, and the new react-server-dom-webpack package.
- Adjusted type definitions in bun-types to reflect changes in import sources.

This update enhances compatibility with the latest React features and improves the overall framework structure.
2025-09-15 21:00:46 -07:00
Alistair Smith
ed4a887047 Merge branch 'zack/ssg-3' into ali/react 2025-09-15 16:38:40 -07:00
Alistair Smith
894a654e26 print errors during framework resolution 2025-09-15 16:38:27 -07:00
Zack Radisic
99dd08bccb Merge branch 'main' into zack/ssg-3 2025-09-15 16:26:34 -07:00
Alistair Smith
7339d1841b specify absolute path 2025-09-15 15:15:52 -07:00
Alistair Smith
1217e87379 remove builtInModules in zig 2025-09-15 15:07:32 -07:00
Alistair Smith
704661e96f remove support for builtInModules 2025-09-15 15:05:32 -07:00
autofix-ci[bot]
8e659b2dc8 [autofix.ci] apply automated fixes 2025-09-15 20:44:31 +00:00
Alistair Smith
93007de396 Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into ali/react 2025-09-15 13:39:44 -07:00
Zack Radisic
2166f0c200 Merge branch 'main' into zack/ssg-3 2025-09-13 18:43:47 -07:00
Zack Radisic
1a0a081e75 woops 2025-09-13 14:49:13 -07:00
Zack Radisic
2eb33628d1 use jsc call conv 2025-09-12 23:38:47 -07:00
Zack Radisic
56e9c92b4a Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into zack/ssg-3 2025-09-12 19:27:09 -07:00
Zack Radisic
34cfdf039a Fix 2025-09-12 19:26:42 -07:00
Alistair Smith
d4a9c7a161 some helpful logs 2025-09-12 18:38:12 -07:00
Alistair Smith
b5c16dcc1b Enhance DevServer logging for framework initialization and route scanning
This update adds detailed logging to the DevServer's initialization process, including framework configuration details such as server components, React Fast Refresh, and file system router types. Additionally, it logs the directory being scanned for routes and the number of routes found, improving visibility into the server's setup and routing process.
2025-09-12 17:49:45 -07:00
Alistair Smith
0ba166eea3 cleaning 2025-09-12 17:31:43 -07:00
autofix-ci[bot]
1920a7c63c [autofix.ci] apply automated fixes 2025-09-12 23:39:19 +00:00
Zack Radisic
d56005b520 Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into zack/ssg-3 2025-09-12 16:36:03 -07:00
Alistair Smith
2bd5d68047 Add support for --app flag in CLI to run bun.app.ts or bun.app.js
This update allows users to specify the `--app` flag when running Bun commands. If the flag is provided without additional arguments, the CLI will automatically look for and execute the bun.app.ts or bun.app.js file in the current working directory. If the file is not found, an error message will be displayed, guiding users to the expected file locations.
2025-09-12 16:16:17 -07:00
Zack Radisic
9c5c4edac4 Bun.SSRResponse -> import { Response } from 'bun:app' 2025-09-12 15:47:26 -07:00
Alistair Smith
cae0673dc4 load the framework 2025-09-12 14:44:51 -07:00
Alistair Smith
51e18d379f try this 2025-09-12 13:32:13 -07:00
Claude Bot
199781bf4f Fix banned words and package.json lint errors
- Replace bun.outOfMemory() with bun.handleOom(err)
- Replace std.mem.indexOfAny with bun.strings.indexOfAny
- Replace arguments_old with argumentsAsArray
- Fix peechy version to be exact (remove ^)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-12 04:22:33 +00:00
Zack Radisic
ffeb21c49b add the bun:app module 2025-09-11 17:51:49 -07:00
Alistair Smith
d54ffd8012 dont use dom libs 2025-09-11 17:43:45 -07:00
Alistair Smith
dca34819b6 remove uninit state for a store 2025-09-11 16:45:55 -07:00
Alistair Smith
b4add533e6 fix a bunch of typescript problems in our test suite 2025-09-11 15:30:41 -07:00
autofix-ci[bot]
7afcc8416f [autofix.ci] apply automated fixes 2025-09-11 04:35:31 +00:00
Zack Radisic
1ef578a0b4 Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into zack/ssg-3 2025-09-10 21:33:59 -07:00
Zack Radisic
8be4fb61d0 make it better 2025-09-10 21:33:40 -07:00
Zack Radisic
208ac7fb60 smol changes 2025-09-10 21:33:20 -07:00
Zack Radisic
29b6faadf8 Make MiString 2025-09-10 21:16:36 -07:00
autofix-ci[bot]
99df2e071f [autofix.ci] apply automated fixes 2025-09-11 02:43:47 +00:00
Zack Radisic
a3d91477a8 merge 2025-09-10 19:42:10 -07:00
Zack Radisic
52c3e2e3f8 remove dead code 2025-09-10 19:35:07 -07:00
Zack Radisic
a7e95718ac fix some more stuff 2025-09-10 19:29:06 -07:00
Zack Radisic
db2960d27b fix some C++ stuff 2025-09-10 19:23:17 -07:00
Zack Radisic
bbfac709cc dev server source provider destructor 2025-09-10 19:18:52 -07:00
Zack Radisic
41fbeacee1 escape json if needed 2025-09-10 19:18:40 -07:00
Zack Radisic
24b2929c9a update IncrementalGraph 2025-09-10 18:56:50 -07:00
Zack Radisic
bf992731c6 use correct allocator 2025-09-10 18:50:28 -07:00
Zack Radisic
eafc04cc5d remove that 2025-09-10 18:41:57 -07:00
Zack Radisic
95cacdc6be fix slop tests 2025-09-10 18:05:54 -07:00
Zack Radisic
6cf46e67f6 Merge branch 'zack/ssg-3-bun' into zack/ssg-3 2025-09-10 17:06:27 -07:00
Zack Radisic
f28670ac68 update 2025-09-10 17:05:59 -07:00
Zack Radisic
0df21d7f30 handle scope exceptions 2025-09-10 16:51:06 -07:00
Zack Radisic
39e7e55802 Move SSRResonse -> Bun.SSRResponse 2025-09-10 16:49:30 -07:00
Alistair Smith
a63888ed6d Improve type safety of DOM element creation utils
The improved types ensure only valid HTML attributes can be set for each
element type, making the code more type-safe and self-documenting.
2025-09-09 21:55:48 -07:00
Alistair Smith
e50385879b Fix Router navigation state handling
The changes improve state handling during client-side navigation by: -
Using correct function updates with setAppState - Preserving abort
controller on updates - Adding proper cache ID comparison - Moving
router instance to constants
2025-09-09 21:39:19 -07:00
Alistair Smith
20d2f3805e force passing a cacheId 2025-09-09 21:21:03 -07:00
Alistair Smith
d984f8f5ad Merge branch 'ali/react' of github.com:oven-sh/bun into ali/react 2025-09-09 21:09:58 -07:00
Alistair Smith
9ea2ec876e Refactor the client a lot 2025-09-09 21:06:37 -07:00
Zack Radisic
0919e45c23 clean up 2025-09-09 20:54:55 -07:00
Zack Radisic
fd41a41ab9 remove dead code 2025-09-09 20:49:59 -07:00
Zack Radisic
fc06e1cf14 yoops 2025-09-09 20:18:32 -07:00
Zack Radisic
1778713cbf forgot to deinit 2025-09-09 20:17:13 -07:00
autofix-ci[bot]
02d9da73bd [autofix.ci] apply automated fixes 2025-09-10 02:43:59 +00:00
Alistair Smith
6562275d15 Merge remote-tracking branch 'origin/zack/ssg-3' into ali/react 2025-09-09 19:39:18 -07:00
Alistair Smith
cccae0cc79 Start splitting up the client 2025-09-09 19:37:58 -07:00
Zack Radisic
c10d184448 fix the test 2025-09-09 18:49:45 -07:00
Alistair Smith
0f8a232466 delete sources (now that they're gen'd on build) 2025-09-09 18:42:18 -07:00
autofix-ci[bot]
f47df15c18 [autofix.ci] apply automated fixes 2025-09-10 01:39:39 +00:00
Alistair Smith
f2d3141767 Merge remote-tracking branch 'origin/zack/ssg-3' into ali/react 2025-09-09 18:36:50 -07:00
Zack Radisic
c8b21f207d Fix node test that is failing 2025-09-09 17:25:26 -07:00
Zack Radisic
6357978b90 change that up 2025-09-09 15:05:15 -07:00
Alistair Smith
151d8bb413 refine types for RSC payload handling in bun-framework-react 2025-09-08 19:51:33 -07:00
Alistair Smith
42bfccee3c revert buildstep changes 2025-09-08 19:40:19 -07:00
Alistair Smith
f219a29248 enqueueChunks 2025-09-08 19:28:45 -07:00
Alistair Smith
b588512237 change build 2025-09-08 18:53:39 -07:00
Alistair Smith
3a42ad8b1f make the build simpelr 2025-09-08 18:20:22 -07:00
Alistair Smith
cc1fff363d types 2025-09-08 18:02:17 -07:00
Alistair Smith
ba5e4784aa rm 2025-09-08 17:57:52 -07:00
Alistair Smith
3e747886aa typescript casting 2025-09-08 17:42:31 -07:00
Zack Radisic
9504d14b7a cache the wrap component function 2025-09-08 17:38:38 -07:00
Alistair Smith
911b670621 move types 2025-09-08 17:38:06 -07:00
Alistair Smith
679282b8c6 types 2025-09-08 17:32:50 -07:00
autofix-ci[bot]
1f79bc15a3 [autofix.ci] apply automated fixes 2025-09-09 00:24:14 +00:00
Alistair Smith
80a945f03f fix that 2025-09-08 17:22:06 -07:00
Zack Radisic
43054c9a7f fix it for errors 2025-09-08 17:17:08 -07:00
Zack Radisic
2fad71dd45 use .bytes() but it is broken on errors 2025-09-08 16:59:02 -07:00
Alistair Smith
6b2c3e61ea refactor: update bun-framework-react structure and types
- Remove unused components and utility files from bun-framework-react.
- Update type definitions in bake.private.d.ts to allow for synthetic modules.
- Modify exports in package.json to simplify module access.
- Ensure proper registration of bun:app in the HMR module system.
2025-09-08 16:57:53 -07:00
Alistair Smith
43d447f9fe register bun:app properly 2025-09-08 16:19:50 -07:00
Zack Radisic
8b35b5634a Update stuff 2025-09-08 15:56:21 -07:00
Alistair Smith
811f0888c8 - Change unique symbol types to unknown in bake.private.d.ts for better type flexibility.
- Update onServerSideReload function return type in rendering.d.ts to void.
- Modify onServerSideReload declaration in hmr-module.ts to accept both Promise<void> and void.
- Enhance type safety in registerSynthetic function with a generic interface for built-in modules.
2025-09-08 15:28:51 -07:00
Alistair Smith
a5d7830862 build: add bun-framework-react to cmake source tracking
- Include packages/bun-framework-react in build dependencies
  - Update Sources.json to glob React framework source files
  - Fix TypeScript types in bun-framework-react (Uint8Array generics, assertions)
  - Add package.json exports for React framework modules
2025-09-08 15:18:10 -07:00
Alistair Smith
ef17dc57e4 refactor: update types in bake.private.d.ts and tsconfig.json; remove unused client and server rendering files 2025-09-08 15:08:29 -07:00
Alistair Smith
e58cb4511e changes to overlay and client.tsx entry 2025-09-08 15:02:56 -07:00
Alistair Smith
d44b3db1cb refactor: update server and SSR manifest types in hmr-module.ts 2025-09-08 14:45:38 -07:00
alii
857e25d88c bun scripts/glob-sources.mjs 2025-09-08 21:41:31 +00:00
Alistair Smith
6eee2eeaf6 some ssr changes 2025-09-08 14:40:46 -07:00
Alistair Smith
cc3e4d8319 types changes 2025-09-08 14:24:40 -07:00
Alistair Smith
278c2e7fb6 fix relative path in bake.zig 2025-09-08 14:14:28 -07:00
Alistair Smith
e296928ab9 abortcontroller bun-types tests 2025-09-08 14:14:28 -07:00
Alistair Smith
39c1bf38f5 fix: AbortController missing a definition 2025-09-08 14:14:28 -07:00
Alistair Smith
91d30b4da0 update bun-types from main 2025-09-08 14:14:28 -07:00
autofix-ci[bot]
c2812fff79 [autofix.ci] apply automated fixes 2025-09-08 21:12:05 +00:00
Alistair Smith
e0337f5649 fix types for rendering api 2025-09-08 14:08:23 -07:00
alii
d05768cc18 bun scripts/glob-sources.mjs 2025-09-08 20:58:26 +00:00
Alistair Smith
1ad67908fc nuke bun-react 2025-09-08 13:58:05 -07:00
Alistair Smith
f55e320f41 start extracting parts of the framework out 2025-09-08 13:56:42 -07:00
Zack Radisic
8e0cf4c5e0 update 2025-09-08 13:38:12 -07:00
Zack Radisic
5dcf8a8076 merge 2025-09-08 13:34:37 -07:00
Zack Radisic
d6b155f056 add test 2025-09-08 13:04:32 -07:00
Zack Radisic
5f8393cc99 better comment 2025-09-05 20:12:40 -07:00
Zack Radisic
ee7dfefbe0 Better Response -> BakeResponse transform 2025-09-05 20:10:08 -07:00
Zack Radisic
6d132e628f yoops 2025-09-05 18:04:02 -07:00
Zack Radisic
ae9ecc99c9 cache react element symbols and use JSBunRequest for cookies 2025-09-05 18:03:03 -07:00
Zack Radisic
eeecbfa790 okie dokie 2025-09-05 15:58:38 -07:00
Zack Radisic
862f7378e4 wip response object c++ class thingy 2025-09-04 14:09:34 -07:00
Zack Radisic
636e597b60 transform Response -> SSRResponse 2025-09-04 12:48:23 -07:00
Zack Radisic
6abb9f81eb that took forever to find and fix 2025-09-03 17:29:21 -07:00
Zack Radisic
aa33b11a7a Forgot to commit test file 2025-09-02 13:18:49 -07:00
Zack Radisic
21266f5263 fix compile error 2025-09-02 12:09:02 -07:00
Zack Radisic
c5fc729fde fix tests 2025-09-01 17:18:14 -07:00
Zack Radisic
03d1e48004 holy moly fix all the leaks 2025-09-01 15:45:17 -07:00
Zack Radisic
19b9c4a850 Properly error when using functions not available when streaming = true 2025-08-27 17:26:06 -07:00
Zack Radisic
842503ecb1 fix errors 2025-08-27 16:39:41 -07:00
Zack Radisic
cb9c45c26c always use dev.allocator() to allocate sourcemaps
we honestly should remove this dev.allocator() and just use leak
sanitizer
2025-08-26 14:56:02 -07:00
Zack Radisic
917dcc846f Merge branch 'zack/ssg-3' of github.com:oven-sh/bun into zack/ssg-3 2025-08-26 13:13:34 -07:00
Zack Radisic
0fb277a56e fix more compile errors 2025-08-26 13:12:34 -07:00
autofix-ci[bot]
c343aca21e [autofix.ci] apply automated fixes 2025-08-26 01:33:55 +00:00
Zack Radisic
e89a0f3807 Merge branch 'main' into zack/ssg-3 2025-08-25 18:23:47 -07:00
Zack Radisic
59f12d30b3 response redirect 2025-08-25 17:33:32 -07:00
Zack Radisic
f0d4fa8b63 support return Response.render(...) 2025-08-25 15:36:55 -07:00
Zack Radisic
3fb0a824cb wip 2025-08-21 18:07:19 -07:00
Zack Radisic
ab3566627d comment 2025-08-20 15:11:07 -07:00
Zack Radisic
3906407e5d stuff 2025-08-20 15:07:39 -07:00
Zack Radisic
33447ef2db that was way more complicated then need be 2025-08-20 15:00:46 -07:00
Zack Radisic
3760407908 stuff 2025-08-19 20:07:10 -07:00
Zack Radisic
c1f0ce277d comment that cursed shit 2025-08-19 19:54:31 -07:00
Zack Radisic
bfe3041179 cookie + request 2025-08-19 19:50:10 -07:00
Zack Radisic
5b6344cf3c make it work 2025-08-19 19:29:25 -07:00
Zack Radisic
b4fdf41ea5 WIP 2025-08-19 16:18:28 -07:00
Zack Radisic
b9da6b71f9 stupid hack 2025-08-19 00:36:34 -07:00
Zack Radisic
87487468f3 wip 2025-08-19 00:07:31 -07:00
Zack Radisic
cfdeb42023 WIP 2025-08-18 22:23:30 -07:00
Zack Radisic
20e4c094ac support `streaming = false | true= 2025-08-18 17:13:31 -07:00
Zack Radisic
17be416250 Merge branch 'main' into zack/ssg-3 2025-08-18 16:54:59 -07:00
Zack Radisic
9745f01041 Merge branch 'zack/dev-server-sourcemaps-server-side' into zack/ssg-3 2025-08-13 16:32:48 -07:00
Zack Radisic
16131f92e1 Merge branch 'main' into zack/dev-server-sourcemaps-server-side 2025-08-13 16:32:02 -07:00
Zack Radisic
59a4d0697b fix 2025-08-13 16:31:27 -07:00
Zack Radisic
78a2ae44aa move change back 2025-08-13 16:30:44 -07:00
Zack Radisic
7f295919a9 Merge branch 'main' into zack/ssg-3 2025-08-13 16:28:49 -07:00
Zack Radisic
1d0984b5c4 Merge branch 'main' into zack/dev-server-sourcemaps-server-side 2025-08-08 17:23:33 -07:00
Zack Radisic
dfa93a8ede small 2025-08-08 17:18:19 -07:00
Zack Radisic
c8773c5e30 error modal on ssr error 2025-08-07 20:04:58 -07:00
Zack Radisic
0f74fafc59 cleanup 2025-08-07 18:24:03 -07:00
Zack Radisic
47d6e161fe fix that 2025-08-07 18:10:05 -07:00
Zack Radisic
160625c37c remove debugging stuff 2025-08-06 18:17:46 -07:00
Zack Radisic
1b9b686772 fix compile errors from merge 2025-08-05 20:22:09 -07:00
Zack Radisic
6f3e098bac Merge branch 'main' into zack/dev-server-sourcemaps-server-side 2025-08-05 17:14:04 -07:00
Zack Radisic
4c6b296a7c okie dokie 2025-08-05 17:04:54 -07:00
Zack Radisic
2ab962bf6b small stuff 2025-07-31 15:32:34 -07:00
Zack Radisic
f556fc987c test 2025-07-30 21:56:09 -07:00
Zack Radisic
3a1b12ee61 no need to percent encode or add "file://" to server-side sourcemaps 2025-07-30 17:55:52 -07:00
Zack Radisic
a952b4200e fix that 2025-07-30 15:58:50 -07:00
Zack Radisic
24485fb432 WIP 2025-07-29 17:24:53 -07:00
Zack Radisic
b10fda0487 allow app configuration form Bun.serve(...) 2025-07-28 15:21:39 -07:00
Zack Radisic
740cdaba3d - fix catch-all routes not working in dev server
- fix crash
- fix require bug
2025-07-27 18:31:01 -07:00
Zack Radisic
68be15361a fix use after free 2025-07-27 01:19:53 -07:00
Zack Radisic
c57be8dcdb extra option 2025-07-27 00:57:29 -07:00
Zack Radisic
5115a88126 Merge branch 'main' into zack/ssg-3 2025-07-23 13:49:18 -07:00
Zack Radisic
e992b804c8 fix 2025-07-23 13:47:55 -07:00
Zack Radisic
b92555e099 better error message 2025-07-23 11:35:23 -07:00
Zack Radisic
381848cd69 WIP less noisy errors 2025-07-22 16:40:46 -07:00
Zack Radisic
61f9845f80 Merge branch 'main' into zack/ssg-3 2025-07-21 23:46:54 -07:00
Zack Radisic
abc52da7bb add check for React.useState 2025-07-21 13:31:51 -07:00
517 changed files with 68405 additions and 9799 deletions

View File

@@ -108,9 +108,9 @@ const buildPlatforms = [
{ os: "linux", arch: "x64", distro: "amazonlinux", release: "2023", features: ["docker"] },
{ os: "linux", arch: "x64", baseline: true, distro: "amazonlinux", release: "2023", features: ["docker"] },
{ os: "linux", arch: "x64", profile: "asan", distro: "amazonlinux", release: "2023", features: ["docker"] },
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.21" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.21" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.21" },
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.22" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.22" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.22" },
{ os: "windows", arch: "x64", release: "2019" },
{ os: "windows", arch: "x64", baseline: true, release: "2019" },
];
@@ -133,9 +133,9 @@ const testPlatforms = [
{ os: "linux", arch: "x64", distro: "ubuntu", release: "24.04", tier: "latest" },
{ os: "linux", arch: "x64", baseline: true, distro: "ubuntu", release: "25.04", tier: "latest" },
{ os: "linux", arch: "x64", baseline: true, distro: "ubuntu", release: "24.04", tier: "latest" },
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.21", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.21", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.21", tier: "latest" },
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.22", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.22", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.22", tier: "latest" },
{ os: "windows", arch: "x64", release: "2019", tier: "oldest" },
{ os: "windows", arch: "x64", release: "2019", baseline: true, tier: "oldest" },
];
@@ -343,7 +343,7 @@ function getZigPlatform() {
arch: "aarch64",
abi: "musl",
distro: "alpine",
release: "3.21",
release: "3.22",
};
}

View File

@@ -0,0 +1,43 @@
---
allowed-tools: Bash(gh issue view:*), Bash(gh search:*), Bash(gh issue list:*), Bash(gh api:*), Bash(gh issue comment:*)
description: Find duplicate GitHub issues
---
# Issue deduplication command
Find up to 3 likely duplicate issues for a given GitHub issue.
To do this, follow these steps precisely:
1. Use an agent to check if the GitHub issue (a) is closed, (b) does not need to be deduped (eg. because it is broad product feedback without a specific solution, or positive feedback), or (c) already has a duplicate detection comment (check for the exact HTML marker `<!-- dedupe-bot:marker -->` in the issue comments - ignore other bot comments). If so, do not proceed.
2. Use an agent to view a GitHub issue, and ask the agent to return a summary of the issue
3. Then, launch 5 parallel agents to search GitHub for duplicates of this issue, using diverse keywords and search approaches, using the summary from Step 2. **IMPORTANT**: Always scope searches with `repo:owner/repo` to constrain results to the current repository only.
4. Next, feed the results from Steps 2 and 3 into another agent, so that it can filter out false positives, that are likely not actually duplicates of the original issue. If there are no duplicates remaining, do not proceed.
5. Finally, comment back on the issue with a list of up to three duplicate issues (or zero, if there are no likely duplicates)
Notes (be sure to tell this to your agents, too):
- Use `gh` to interact with GitHub, rather than web fetch
- Do not use other tools, beyond `gh` (eg. don't use other MCP servers, file edit, etc.)
- Make a todo list first
- Always scope searches with `repo:owner/repo` to prevent cross-repo false positives
- For your comment, follow the following format precisely (assuming for this example that you found 3 suspected duplicates):
---
Found 3 possible duplicate issues:
1. <link to issue>
2. <link to issue>
3. <link to issue>
This issue will be automatically closed as a duplicate in 3 days.
- If your issue is a duplicate, please close it and 👍 the existing issue instead
- To prevent auto-closure, add a comment or 👎 this comment
🤖 Generated with [Claude Code](https://claude.ai/code)
<!-- dedupe-bot:marker -->
---

143
.coderabbit.yaml Normal file
View File

@@ -0,0 +1,143 @@
language: en-US
reviews:
profile: assertive
request_changes_workflow: false
high_level_summary: false
high_level_summary_placeholder: "@coderabbitai summary"
high_level_summary_in_walkthrough: true
auto_title_placeholder: "@coderabbitai"
review_status: false
commit_status: false
fail_commit_status: false
collapse_walkthrough: false
changed_files_summary: true
sequence_diagrams: false
estimate_code_review_effort: false
assess_linked_issues: true
related_issues: true
related_prs: true
suggested_labels: false
suggested_reviewers: true
in_progress_fortune: false
poem: false
abort_on_close: true
path_filters:
- "!test/js/node/test/"
auto_review:
enabled: true
auto_incremental_review: true
drafts: false
finishing_touches:
docstrings:
enabled: false
unit_tests:
enabled: false
pre_merge_checks:
docstrings:
mode: off
title:
mode: warning
description:
mode: warning
issue_assessment:
mode: warning
tools:
shellcheck:
enabled: true
ruff:
enabled: true
markdownlint:
enabled: true
github-checks:
enabled: true
timeout_ms: 90000
languagetool:
enabled: true
enabled_only: false
level: default
biome:
enabled: true
hadolint:
enabled: true
swiftlint:
enabled: true
phpstan:
enabled: true
level: default
phpmd:
enabled: true
phpcs:
enabled: true
golangci-lint:
enabled: true
yamllint:
enabled: true
gitleaks:
enabled: true
checkov:
enabled: true
detekt:
enabled: true
eslint:
enabled: true
flake8:
enabled: true
rubocop:
enabled: true
buf:
enabled: true
regal:
enabled: true
actionlint:
enabled: true
pmd:
enabled: true
clang:
enabled: true
cppcheck:
enabled: true
semgrep:
enabled: true
circleci:
enabled: true
clippy:
enabled: true
sqlfluff:
enabled: true
prismaLint:
enabled: true
pylint:
enabled: true
oxc:
enabled: true
shopifyThemeCheck:
enabled: true
luacheck:
enabled: true
brakeman:
enabled: true
dotenvLint:
enabled: true
htmlhint:
enabled: true
checkmake:
enabled: true
osvScanner:
enabled: true
chat:
auto_reply: true
knowledge_base:
opt_out: false
code_guidelines:
enabled: true
filePatterns:
- "**/.cursor/rules/*.mdc"
- "**/CLAUDE.md"

1
.gitattributes vendored
View File

@@ -47,6 +47,7 @@ examples/**/* linguist-documentation
vendor/*.c linguist-vendored
vendor/brotli/** linguist-vendored
packages/bun-framework-react/vendor/** linguist-vendored -diff -merge
test/js/node/test/fixtures linguist-vendored
test/js/node/test/common linguist-vendored

View File

@@ -0,0 +1,29 @@
name: Auto-close duplicate issues
on:
schedule:
- cron: "0 9 * * *"
workflow_dispatch:
jobs:
auto-close-duplicates:
runs-on: ubuntu-latest
timeout-minutes: 10
concurrency:
group: auto-close-duplicates-${{ github.repository }}
cancel-in-progress: true
permissions:
contents: read
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Auto-close duplicate issues
run: bun run scripts/auto-close-duplicates.ts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}

View File

@@ -0,0 +1,34 @@
name: Claude Issue Dedupe
on:
issues:
types: [opened]
workflow_dispatch:
inputs:
issue_number:
description: 'Issue number to process for duplicate detection'
required: true
type: string
jobs:
claude-dedupe-issues:
runs-on: ubuntu-latest
timeout-minutes: 10
concurrency:
group: claude-dedupe-issues-${{ github.event.issue.number || inputs.issue_number }}
cancel-in-progress: true
permissions:
contents: read
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Run Claude Code slash command
uses: anthropics/claude-code-base-action@beta
with:
prompt: "/dedupe ${{ github.repository }}/issues/${{ github.event.issue.number || inputs.issue_number }}"
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_args: "--model claude-sonnet-4-5-20250929"
claude_env: |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -76,7 +76,8 @@ test("my feature", async () => {
- Use `normalizeBunSnapshot` to normalize snapshot output of the test.
- NEVER write tests that check for no "panic" or "uncaught exception" or similar in the test output. That is NOT a valid test.
- Use `tempDir` from `"harness"` to create a temporary directory. **Do not** use `tmpdirSync` or `fs.mkdtempSync` to create temporary directories.
- When spawning processes, tests should assert the output BEFORE asserting the exit code. This gives you a more useful error message on test failure.
- When spawning processes, tests should expect(stdout).toBe(...) BEFORE expect(exitCode).toBe(0). This gives you a more useful error message on test failure.
- **CRITICAL**: Do not write flaky tests. Do not use `setTimeout` in tests. Instead, `await` the condition to be met. You are not testing the TIME PASSING, you are testing the CONDITION.
- **CRITICAL**: Verify your test fails with `USE_SYSTEM_BUN=1 bun test <file>` and passes with `bun bd test <file>`. Your test is NOT VALID if it passes with `USE_SYSTEM_BUN=1`.
## Code Architecture

2
LATEST
View File

@@ -1 +1 @@
1.3.0
1.3.1

View File

@@ -1,40 +1,29 @@
# `install` benchmark
# Create T3 App
Requires [`hyperfine`](https://github.com/sharkdp/hyperfine). The goal of this benchmark is to compare installation performance of Bun with other package managers _when caches are hot_.
This is a [T3 Stack](https://create.t3.gg/) project bootstrapped with `create-t3-app`.
### With lockfile, online mode
## What's next? How do I make an app with this?
To run the benchmark with the standard "install" command for each package manager:
We try to keep this project as simple as possible, so you can start with just the scaffolding we set up for you, and add additional things later when they become necessary.
```sh
$ hyperfine --prepare 'rm -rf node_modules' --warmup 1 --runs 3 'bun install' 'pnpm install' 'yarn' 'npm install'
```
If you are not familiar with the different technologies used in this project, please refer to the respective docs. If you still are in the wind, please join our [Discord](https://t3.gg/discord) and ask for help.
### With lockfile, offline mode
- [Next.js](https://nextjs.org)
- [NextAuth.js](https://next-auth.js.org)
- [Prisma](https://prisma.io)
- [Drizzle](https://orm.drizzle.team)
- [Tailwind CSS](https://tailwindcss.com)
- [tRPC](https://trpc.io)
Even though all packages are cached, some tools may hit the npm API during the version resolution step. (This is not the same as re-downloading a package.) To entirely avoid network calls, the other package managers require `--prefer-offline/--offline` flag. To run the benchmark using "offline" mode:
## Learn More
```sh
$ hyperfine --prepare 'rm -rf node_modules' --runs 1 'bun install' 'pnpm install --prefer-offline' 'yarn --offline' 'npm install --prefer-offline'
```
To learn more about the [T3 Stack](https://create.t3.gg/), take a look at the following resources:
### Without lockfile, offline mode
- [Documentation](https://create.t3.gg/)
- [Learn the T3 Stack](https://create.t3.gg/en/faq#what-learning-resources-are-currently-available) — Check out these awesome tutorials
To run the benchmark with offline mode but without lockfiles:
You can check out the [create-t3-app GitHub repository](https://github.com/t3-oss/create-t3-app) — your feedback and contributions are welcome!
```sh
$ hyperfine --prepare 'rm -rf node_modules' --warmup 1 'rm bun.lock && bun install' 'rm pnpm-lock.yaml && pnpm install --prefer-offline' 'rm yarn.lock && yarn --offline' 'rm package-lock.json && npm install --prefer-offline'
```
## How do I deploy this?
##
To check that the app is working as expected:
```
$ bun run dev
$ npm run dev
$ yarn dev
$ pnpm dev
```
Then visit [http://localhost:3000](http://localhost:3000).
Follow our deployment guides for [Vercel](https://create.t3.gg/en/deployment/vercel), [Netlify](https://create.t3.gg/en/deployment/netlify) and [Docker](https://create.t3.gg/en/deployment/docker) for more information.

View File

@@ -1,18 +0,0 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/docs/en/main/file-conventions/entry.client
*/
import { RemixBrowser } from "@remix-run/react";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>,
);
});

View File

@@ -1,101 +0,0 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/docs/en/main/file-conventions/entry.server
*/
import type { EntryContext } from "@remix-run/node";
import { Response } from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import isbot from "isbot";
import { PassThrough } from "node:stream";
import { renderToPipeableStream } from "react-dom/server";
const ABORT_DELAY = 5_000;
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return isbot(request.headers.get("user-agent"))
? handleBotRequest(request, responseStatusCode, responseHeaders, remixContext)
: handleBrowserRequest(request, responseStatusCode, responseHeaders, remixContext);
}
function handleBotRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return new Promise((resolve, reject) => {
const { pipe, abort } = renderToPipeableStream(
<RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
{
onAllReady() {
const body = new PassThrough();
responseHeaders.set("Content-Type", "text/html");
resolve(
new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
}),
);
pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
console.error(error);
},
},
);
setTimeout(abort, ABORT_DELAY);
});
}
function handleBrowserRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return new Promise((resolve, reject) => {
const { pipe, abort } = renderToPipeableStream(
<RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
{
onShellReady() {
const body = new PassThrough();
responseHeaders.set("Content-Type", "text/html");
resolve(
new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
}),
);
pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
console.error(error);
responseStatusCode = 500;
},
},
);
setTimeout(abort, ABORT_DELAY);
});
}

View File

@@ -1,20 +0,0 @@
import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration } from "@remix-run/react";
export default function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}

View File

@@ -1,30 +0,0 @@
import type { V2_MetaFunction } from "@remix-run/node";
export const meta: V2_MetaFunction = () => {
return [{ title: "New Remix App" }];
};
export default function Index() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Welcome to Remix</h1>
<ul>
<li>
<a target="_blank" href="https://remix.run/tutorials/blog" rel="noreferrer">
15m Quickstart Blog Tutorial
</a>
</li>
<li>
<a target="_blank" href="https://remix.run/tutorials/jokes" rel="noreferrer">
Deep Dive Jokes App Tutorial
</a>
</li>
<li>
<a target="_blank" href="https://remix.run/docs" rel="noreferrer">
Remix Docs
</a>
</li>
</ul>
</div>
);
}

488
bench/install/bun.lock Normal file
View File

@@ -0,0 +1,488 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "installbench",
"dependencies": {
"@auth/drizzle-adapter": "^1.7.2",
"@t3-oss/env-nextjs": "^0.12.0",
"@tanstack/react-query": "^5.69.0",
"@trpc/client": "^11.0.0",
"@trpc/react-query": "^11.0.0",
"@trpc/server": "^11.0.0",
"drizzle-orm": "^0.41.0",
"esbuild": "^0.25.11",
"next": "^15.2.3",
"next-auth": "5.0.0-beta.25",
"postgres": "^3.4.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"server-only": "^0.0.1",
"superjson": "^2.2.1",
"zod": "^3.24.2",
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@tailwindcss/postcss": "^4.0.15",
"@types/node": "^20.14.10",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"drizzle-kit": "^0.30.5",
"postcss": "^8.5.3",
"tailwindcss": "^4.0.15",
"typescript": "^5.8.2",
},
},
},
"packages": {
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
"@auth/core": ["@auth/core@0.41.1", "", { "dependencies": { "@panva/hkdf": "1.2.1", "jose": "6.1.0", "oauth4webapi": "3.8.2", "preact": "10.24.3", "preact-render-to-string": "6.5.11" } }, "sha512-t9cJ2zNYAdWMacGRMT6+r4xr1uybIdmYa49calBPeTqwgAFPV/88ac9TEvCR85pvATiSPt8VaNf+Gt24JIT/uw=="],
"@auth/drizzle-adapter": ["@auth/drizzle-adapter@1.11.1", "", { "dependencies": { "@auth/core": "0.41.1" } }, "sha512-cQTvDZqsyF7RPhDm/B6SvqdVP9EzQhy3oM4Muu7fjjmSYFLbSR203E6dH631ZHSKDn2b4WZkfMnjPDzRsPSAeA=="],
"@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="],
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="],
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="],
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="],
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="],
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="],
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="],
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="],
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="],
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="],
"@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="],
"@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "0.18.20", "source-map-support": "0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="],
"@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "3.3.2", "get-tsconfig": "4.13.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.11", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.11", "", { "os": "android", "cpu": "arm" }, "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.11", "", { "os": "android", "cpu": "arm64" }, "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.11", "", { "os": "android", "cpu": "x64" }, "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.11", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.11", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.11", "", { "os": "linux", "cpu": "arm" }, "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.11", "", { "os": "linux", "cpu": "ia32" }, "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.11", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.11", "", { "os": "linux", "cpu": "s390x" }, "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.11", "", { "os": "linux", "cpu": "x64" }, "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.11", "", { "os": "none", "cpu": "x64" }, "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.11", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.11", "", { "os": "openbsd", "cpu": "x64" }, "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.11", "", { "os": "sunos", "cpu": "x64" }, "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.11", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.11", "", { "os": "win32", "cpu": "x64" }, "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA=="],
"@img/colour": ["@img/colour@1.0.0", "", {}, "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw=="],
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.3" }, "os": "darwin", "cpu": "arm64" }, "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA=="],
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.3" }, "os": "darwin", "cpu": "x64" }, "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg=="],
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw=="],
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA=="],
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.3", "", { "os": "linux", "cpu": "arm" }, "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA=="],
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ=="],
"@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg=="],
"@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w=="],
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.3", "", { "os": "linux", "cpu": "x64" }, "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg=="],
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw=="],
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.3", "", { "os": "linux", "cpu": "x64" }, "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g=="],
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.3" }, "os": "linux", "cpu": "arm" }, "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA=="],
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.3" }, "os": "linux", "cpu": "arm64" }, "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ=="],
"@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.3" }, "os": "linux", "cpu": "ppc64" }, "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ=="],
"@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.3" }, "os": "linux", "cpu": "s390x" }, "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw=="],
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.3" }, "os": "linux", "cpu": "x64" }, "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A=="],
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.3" }, "os": "linux", "cpu": "arm64" }, "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA=="],
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.3" }, "os": "linux", "cpu": "x64" }, "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg=="],
"@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.4", "", { "dependencies": { "@emnapi/runtime": "1.6.0" }, "cpu": "none" }, "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA=="],
"@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA=="],
"@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw=="],
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.4", "", { "os": "win32", "cpu": "x64" }, "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "3.1.2", "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
"@next/env": ["@next/env@15.5.6", "", {}, "sha512-3qBGRW+sCGzgbpc5TS1a0p7eNxnOarGVQhZxfvTdnV0gFI61lX7QNtQ4V1TSREctXzYn5NetbUsLvyqwLFJM6Q=="],
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.5.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ES3nRz7N+L5Umz4KoGfZ4XX6gwHplwPhioVRc25+QNsDa7RtUF/z8wJcbuQ2Tffm5RZwuN2A063eapoJ1u4nPg=="],
"@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.5.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-JIGcytAyk9LQp2/nuVZPAtj8uaJ/zZhsKOASTjxDug0SPU9LAM3wy6nPU735M1OqacR4U20LHVF5v5Wnl9ptTA=="],
"@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-qvz4SVKQ0P3/Im9zcS2RmfFL/UCQnsJKJwQSkissbngnB/12c6bZTCB0gHTexz1s6d/mD0+egPKXAIRFVS7hQg=="],
"@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-FsbGVw3SJz1hZlvnWD+T6GFgV9/NYDeLTNQB2MXoPN5u9VA9OEDy6fJEfePfsUKAhJufFbZLgp0cPxMuV6SV0w=="],
"@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-3QnHGFWlnvAgyxFxt2Ny8PTpXtQD7kVEeaFat5oPAHHI192WKYB+VIKZijtHLGdBBvc16tiAkPTDmQNOQ0dyrA=="],
"@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-OsGX148sL+TqMK9YFaPFPoIaJKbFJJxFzkXZljIgA9hjMjdruKht6xDCEv1HLtlLNfkx3c5w2GLKhj7veBQizQ=="],
"@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.5.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-ONOMrqWxdzXDJNh2n60H6gGyKed42Ieu6UTVPZteXpuKbLZTH4G4eBMsr5qWgOBA+s7F+uB4OJbZnrkEDnZ5Fg=="],
"@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-pxK4VIjFRx1MY92UycLOOw7dTdvccWsNETQ0kDHkBlcFH1GrTLUjSiHU1ohrznnux6TqRHgv5oflhfIWZwVROQ=="],
"@panva/hkdf": ["@panva/hkdf@1.2.1", "", {}, "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw=="],
"@petamoriken/float16": ["@petamoriken/float16@3.9.3", "", {}, "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g=="],
"@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="],
"@t3-oss/env-core": ["@t3-oss/env-core@0.12.0", "", { "optionalDependencies": { "typescript": "5.9.3", "zod": "3.25.76" } }, "sha512-lOPj8d9nJJTt81mMuN9GMk8x5veOt7q9m11OSnCBJhwp1QrL/qR+M8Y467ULBSm9SunosryWNbmQQbgoiMgcdw=="],
"@t3-oss/env-nextjs": ["@t3-oss/env-nextjs@0.12.0", "", { "dependencies": { "@t3-oss/env-core": "0.12.0" }, "optionalDependencies": { "typescript": "5.9.3", "zod": "3.25.76" } }, "sha512-rFnvYk1049RnNVUPvY8iQ55AuQh1Rr+qZzQBh3t++RttCGK4COpXGNxS4+45afuQq02lu+QAOy/5955aU8hRKw=="],
"@tailwindcss/node": ["@tailwindcss/node@4.1.16", "", { "dependencies": { "@jridgewell/remapping": "2.3.5", "enhanced-resolve": "5.18.3", "jiti": "2.6.1", "lightningcss": "1.30.2", "magic-string": "0.30.21", "source-map-js": "1.2.1", "tailwindcss": "4.1.16" } }, "sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw=="],
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.16", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.16", "@tailwindcss/oxide-darwin-arm64": "4.1.16", "@tailwindcss/oxide-darwin-x64": "4.1.16", "@tailwindcss/oxide-freebsd-x64": "4.1.16", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.16", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.16", "@tailwindcss/oxide-linux-arm64-musl": "4.1.16", "@tailwindcss/oxide-linux-x64-gnu": "4.1.16", "@tailwindcss/oxide-linux-x64-musl": "4.1.16", "@tailwindcss/oxide-wasm32-wasi": "4.1.16", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.16", "@tailwindcss/oxide-win32-x64-msvc": "4.1.16" } }, "sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg=="],
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.16", "", { "os": "android", "cpu": "arm64" }, "sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA=="],
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.16", "", { "os": "darwin", "cpu": "arm64" }, "sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA=="],
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.16", "", { "os": "darwin", "cpu": "x64" }, "sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg=="],
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.16", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg=="],
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16", "", { "os": "linux", "cpu": "arm" }, "sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw=="],
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w=="],
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ=="],
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.16", "", { "os": "linux", "cpu": "x64" }, "sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew=="],
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.16", "", { "os": "linux", "cpu": "x64" }, "sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw=="],
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.16", "", { "cpu": "none" }, "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q=="],
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.16", "", { "os": "win32", "cpu": "arm64" }, "sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A=="],
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.16", "", { "os": "win32", "cpu": "x64" }, "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg=="],
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.16", "", { "dependencies": { "@alloc/quick-lru": "5.2.0", "@tailwindcss/node": "4.1.16", "@tailwindcss/oxide": "4.1.16", "postcss": "8.5.6", "tailwindcss": "4.1.16" } }, "sha512-Qn3SFGPXYQMKR/UtqS+dqvPrzEeBZHrFA92maT4zijCVggdsXnDBMsPFJo1eArX3J+O+Gi+8pV4PkqjLCNBk3A=="],
"@tanstack/query-core": ["@tanstack/query-core@5.90.5", "", {}, "sha512-wLamYp7FaDq6ZnNehypKI5fNvxHPfTYylE0m/ZpuuzJfJqhR5Pxg9gvGBHZx4n7J+V5Rg5mZxHHTlv25Zt5u+w=="],
"@tanstack/react-query": ["@tanstack/react-query@5.90.5", "", { "dependencies": { "@tanstack/query-core": "5.90.5" }, "peerDependencies": { "react": "19.2.0" } }, "sha512-pN+8UWpxZkEJ/Rnnj2v2Sxpx1WFlaa9L6a4UO89p6tTQbeo+m0MS8oYDjbggrR8QcTyjKoYWKS3xJQGr3ExT8Q=="],
"@trpc/client": ["@trpc/client@11.7.1", "", { "peerDependencies": { "@trpc/server": "11.7.1", "typescript": "5.9.3" } }, "sha512-uOnAjElKI892/U6aQMcBHYs3x7mme3Cvv1F87ytBL56rBvs7+DyK7r43zgaXKf13+GtPEI6ex5xjVUfyDW8XcQ=="],
"@trpc/react-query": ["@trpc/react-query@11.7.1", "", { "peerDependencies": { "@tanstack/react-query": "5.90.5", "@trpc/client": "11.7.1", "@trpc/server": "11.7.1", "react": "19.2.0", "react-dom": "19.2.0", "typescript": "5.9.3" } }, "sha512-dEHDjIqSTzO8nLlCbtiFBMBwhbSkK1QP7aYVo3nP3sYBna0b+iCtrPXdxVPCSopr9/aIqDTEh+dMRZa7yBgjfQ=="],
"@trpc/server": ["@trpc/server@11.7.1", "", { "peerDependencies": { "typescript": "5.9.3" } }, "sha512-N3U8LNLIP4g9C7LJ/sLkjuPHwqlvE3bnspzC4DEFVdvx2+usbn70P80E3wj5cjOTLhmhRiwJCSXhlB+MHfGeCw=="],
"@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="],
"@types/node": ["@types/node@20.19.24", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-FE5u0ezmi6y9OZEzlJfg37mqqf6ZDSF2V/NLjUyGrR9uTZ7Sb9F7bLNZ03S4XVUNRWGA7Ck4c1kK+YnuWjl+DA=="],
"@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "3.1.3" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
"@types/react-dom": ["@types/react-dom@19.2.2", "", { "peerDependencies": { "@types/react": "19.2.2" } }, "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw=="],
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
"caniuse-lite": ["caniuse-lite@1.0.30001752", "", {}, "sha512-vKUk7beoukxE47P5gcVNKkDRzXdVofotshHwfR9vmpeFKxmI5PBpgOMC18LUJUA/DvJ70Y7RveasIBraqsyO/g=="],
"client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="],
"cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="],
"copy-anything": ["copy-anything@4.0.5", "", { "dependencies": { "is-what": "5.5.0" } }, "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"drizzle-kit": ["drizzle-kit@0.30.6", "", { "dependencies": { "@drizzle-team/brocli": "0.10.2", "@esbuild-kit/esm-loader": "2.6.5", "esbuild": "0.19.12", "esbuild-register": "3.6.0", "gel": "2.1.1" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-U4wWit0fyZuGuP7iNmRleQyK2V8wCuv57vf5l3MnG4z4fzNTjY/U13M8owyQ5RavqvqxBifWORaR3wIUzlN64g=="],
"drizzle-orm": ["drizzle-orm@0.41.0", "", { "optionalDependencies": { "gel": "2.1.1", "postgres": "3.4.7" } }, "sha512-7A4ZxhHk9gdlXmTdPj/lREtP+3u8KvZ4yEN6MYVxBzZGex5Wtdc+CWSbu7btgF6TB0N+MNPrvW7RKBbxJchs/Q=="],
"enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "4.2.11", "tapable": "2.3.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="],
"env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="],
"esbuild": ["esbuild@0.25.11", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.11", "@esbuild/android-arm": "0.25.11", "@esbuild/android-arm64": "0.25.11", "@esbuild/android-x64": "0.25.11", "@esbuild/darwin-arm64": "0.25.11", "@esbuild/darwin-x64": "0.25.11", "@esbuild/freebsd-arm64": "0.25.11", "@esbuild/freebsd-x64": "0.25.11", "@esbuild/linux-arm": "0.25.11", "@esbuild/linux-arm64": "0.25.11", "@esbuild/linux-ia32": "0.25.11", "@esbuild/linux-loong64": "0.25.11", "@esbuild/linux-mips64el": "0.25.11", "@esbuild/linux-ppc64": "0.25.11", "@esbuild/linux-riscv64": "0.25.11", "@esbuild/linux-s390x": "0.25.11", "@esbuild/linux-x64": "0.25.11", "@esbuild/netbsd-arm64": "0.25.11", "@esbuild/netbsd-x64": "0.25.11", "@esbuild/openbsd-arm64": "0.25.11", "@esbuild/openbsd-x64": "0.25.11", "@esbuild/openharmony-arm64": "0.25.11", "@esbuild/sunos-x64": "0.25.11", "@esbuild/win32-arm64": "0.25.11", "@esbuild/win32-ia32": "0.25.11", "@esbuild/win32-x64": "0.25.11" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q=="],
"esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "4.4.3" }, "peerDependencies": { "esbuild": "0.19.12" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="],
"gel": ["gel@2.1.1", "", { "dependencies": { "@petamoriken/float16": "3.9.3", "debug": "4.4.3", "env-paths": "3.0.0", "semver": "7.7.3", "shell-quote": "1.8.3", "which": "4.0.0" }, "bin": { "gel": "dist/cli.mjs" } }, "sha512-Newg9X7mRYskoBjSw70l1YnJ/ZGbq64VPyR821H5WVkTGpHG2O0mQILxCeUhxdYERLFY9B4tUyKLyf3uMTjtKw=="],
"get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="],
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
"is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="],
"isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="],
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"jose": ["jose@6.1.0", "", {}, "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA=="],
"lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "2.1.2" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"next": ["next@15.5.6", "", { "dependencies": { "@next/env": "15.5.6", "@swc/helpers": "0.5.15", "caniuse-lite": "1.0.30001752", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.5.6", "@next/swc-darwin-x64": "15.5.6", "@next/swc-linux-arm64-gnu": "15.5.6", "@next/swc-linux-arm64-musl": "15.5.6", "@next/swc-linux-x64-gnu": "15.5.6", "@next/swc-linux-x64-musl": "15.5.6", "@next/swc-win32-arm64-msvc": "15.5.6", "@next/swc-win32-x64-msvc": "15.5.6", "sharp": "0.34.4" }, "peerDependencies": { "react": "19.2.0", "react-dom": "19.2.0" }, "bin": { "next": "dist/bin/next" } }, "sha512-zTxsnI3LQo3c9HSdSf91O1jMNsEzIXDShXd4wVdg9y5shwLqBXi4ZtUUJyB86KGVSJLZx0PFONvO54aheGX8QQ=="],
"next-auth": ["next-auth@5.0.0-beta.25", "", { "dependencies": { "@auth/core": "0.37.2" }, "peerDependencies": { "next": "15.5.6", "react": "19.2.0" } }, "sha512-2dJJw1sHQl2qxCrRk+KTQbeH+izFbGFPuJj5eGgBZFYyiYYtvlrBeUw1E/OJJxTRjuxbSYGnCTkUIRsIIW0bog=="],
"oauth4webapi": ["oauth4webapi@3.8.2", "", {}, "sha512-FzZZ+bht5X0FKe7Mwz3DAVAmlH1BV5blSak/lHMBKz0/EBMhX6B10GlQYI51+oRp8ObJaX0g6pXrAxZh5s8rjw=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "3.3.11", "picocolors": "1.1.1", "source-map-js": "1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
"postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="],
"preact": ["preact@10.24.3", "", {}, "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA=="],
"preact-render-to-string": ["preact-render-to-string@6.5.11", "", { "peerDependencies": { "preact": "10.24.3" } }, "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw=="],
"pretty-format": ["pretty-format@3.8.0", "", {}, "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="],
"react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
"react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "0.27.0" }, "peerDependencies": { "react": "19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
"semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"server-only": ["server-only@0.0.1", "", {}, "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA=="],
"sharp": ["sharp@0.34.4", "", { "dependencies": { "@img/colour": "1.0.0", "detect-libc": "2.1.2", "semver": "7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.4", "@img/sharp-darwin-x64": "0.34.4", "@img/sharp-libvips-darwin-arm64": "1.2.3", "@img/sharp-libvips-darwin-x64": "1.2.3", "@img/sharp-libvips-linux-arm": "1.2.3", "@img/sharp-libvips-linux-arm64": "1.2.3", "@img/sharp-libvips-linux-ppc64": "1.2.3", "@img/sharp-libvips-linux-s390x": "1.2.3", "@img/sharp-libvips-linux-x64": "1.2.3", "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", "@img/sharp-libvips-linuxmusl-x64": "1.2.3", "@img/sharp-linux-arm": "0.34.4", "@img/sharp-linux-arm64": "0.34.4", "@img/sharp-linux-ppc64": "0.34.4", "@img/sharp-linux-s390x": "0.34.4", "@img/sharp-linux-x64": "0.34.4", "@img/sharp-linuxmusl-arm64": "0.34.4", "@img/sharp-linuxmusl-x64": "0.34.4", "@img/sharp-wasm32": "0.34.4", "@img/sharp-win32-arm64": "0.34.4", "@img/sharp-win32-ia32": "0.34.4", "@img/sharp-win32-x64": "0.34.4" } }, "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA=="],
"shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "1.1.2", "source-map": "0.6.1" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
"styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": "19.2.0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="],
"superjson": ["superjson@2.2.5", "", { "dependencies": { "copy-anything": "4.0.5" } }, "sha512-zWPTX96LVsA/eVYnqOM2+ofcdPqdS1dAF1LN4TS2/MWuUpfitd9ctTa87wt4xrYnZnkLtS69xpBdSxVBP5Rm6w=="],
"tailwindcss": ["tailwindcss@4.1.16", "", {}, "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA=="],
"tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
"which": ["which@4.0.0", "", { "dependencies": { "isexe": "3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
"drizzle-kit/esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="],
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "3.3.11", "picocolors": "1.1.1", "source-map-js": "1.2.1" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
"next-auth/@auth/core": ["@auth/core@0.37.2", "", { "dependencies": { "@panva/hkdf": "1.2.1", "@types/cookie": "0.6.0", "cookie": "0.7.1", "jose": "5.10.0", "oauth4webapi": "3.8.2", "preact": "10.11.3", "preact-render-to-string": "5.2.3" } }, "sha512-kUvzyvkcd6h1vpeMAojK2y7+PAV5H+0Cc9+ZlKYDFhDY31AlvsB+GW5vNO4qE3Y07KeQgvNO9U0QUx/fN62kBw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
"drizzle-kit/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="],
"drizzle-kit/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.19.12", "", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="],
"drizzle-kit/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.19.12", "", { "os": "android", "cpu": "arm64" }, "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA=="],
"drizzle-kit/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.19.12", "", { "os": "android", "cpu": "x64" }, "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew=="],
"drizzle-kit/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.19.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g=="],
"drizzle-kit/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.19.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A=="],
"drizzle-kit/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.19.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA=="],
"drizzle-kit/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.19.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg=="],
"drizzle-kit/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.19.12", "", { "os": "linux", "cpu": "arm" }, "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w=="],
"drizzle-kit/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.19.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA=="],
"drizzle-kit/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.19.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA=="],
"drizzle-kit/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA=="],
"drizzle-kit/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w=="],
"drizzle-kit/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.19.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg=="],
"drizzle-kit/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg=="],
"drizzle-kit/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.19.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg=="],
"drizzle-kit/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.19.12", "", { "os": "linux", "cpu": "x64" }, "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg=="],
"drizzle-kit/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.19.12", "", { "os": "none", "cpu": "x64" }, "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA=="],
"drizzle-kit/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.19.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw=="],
"drizzle-kit/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.19.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA=="],
"drizzle-kit/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.19.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A=="],
"drizzle-kit/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.19.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ=="],
"drizzle-kit/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="],
"next-auth/@auth/core/jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="],
"next-auth/@auth/core/preact": ["preact@10.11.3", "", {}, "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg=="],
"next-auth/@auth/core/preact-render-to-string": ["preact-render-to-string@5.2.3", "", { "dependencies": { "pretty-format": "3.8.0" }, "peerDependencies": { "preact": "10.11.3" } }, "sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA=="],
}
}

5
bench/install/next-env.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@@ -0,0 +1,10 @@
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
*/
import "./src/env.js";
/** @type {import("next").NextConfig} */
const config = {};
export default config;

View File

@@ -1,31 +1,52 @@
{
"name": "installbench",
"version": "0.1.0",
"private": true,
"sideEffects": false,
"type": "module",
"scripts": {
"build": "remix build",
"dev": "remix dev",
"start": "remix-serve build",
"typecheck": "tsc",
"clean": "rm -rf node_modules",
"bench": "hyperfine --prepare 'rm -rf node_modules' --warmup 1 --runs 3 'bun install' 'pnpm install' 'yarn' 'npm install'"
"build": "next build",
"check": "biome check .",
"check:unsafe": "biome check --write --unsafe .",
"check:write": "biome check --write .",
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:push": "drizzle-kit push",
"db:studio": "drizzle-kit studio",
"dev": "next dev --turbo",
"preview": "next build && next start",
"start": "next start",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@remix-run/node": "^1.15.0",
"@remix-run/react": "^1.15.0",
"@remix-run/serve": "^1.15.0",
"isbot": "^3.6.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"@auth/drizzle-adapter": "^1.7.2",
"@t3-oss/env-nextjs": "^0.12.0",
"@tanstack/react-query": "^5.69.0",
"@trpc/client": "^11.0.0",
"@trpc/react-query": "^11.0.0",
"@trpc/server": "^11.0.0",
"drizzle-orm": "^0.41.0",
"esbuild": "^0.25.11",
"next": "^15.2.3",
"next-auth": "5.0.0-beta.25",
"postgres": "^3.4.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"server-only": "^0.0.1",
"superjson": "^2.2.1",
"zod": "^3.24.2"
},
"devDependencies": {
"@remix-run/dev": "^1.15.0",
"@remix-run/eslint-config": "^1.15.0",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.8",
"eslint": "^8.27.0",
"typescript": "^4.8.4"
"@biomejs/biome": "1.9.4",
"@tailwindcss/postcss": "^4.0.15",
"@types/node": "^20.14.10",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"drizzle-kit": "^0.30.5",
"postcss": "^8.5.3",
"tailwindcss": "^4.0.15",
"typescript": "^5.8.2"
},
"engines": {
"node": ">=14"
"ct3aMetadata": {
"initVersion": "7.39.3"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,14 +0,0 @@
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
ignoredRouteFiles: ["**/.*"],
// appDirectory: "app",
// assetsBuildDirectory: "public/build",
// serverBuildPath: "build/index.js",
// publicPath: "/build/",
future: {
v2_errorBoundary: true,
v2_meta: true,
v2_normalizeFormMethod: true,
v2_routeConvention: true,
},
};

View File

@@ -1,2 +0,0 @@
/// <reference types="@remix-run/dev" />
/// <reference types="@remix-run/node" />

View File

@@ -1,22 +0,0 @@
{
"include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2019"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"resolveJsonModule": true,
"target": "ES2019",
"strict": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
// Remix takes care of building everything in `remix build`.
"noEmit": true
}
}

View File

@@ -4,20 +4,16 @@
"": {
"name": "react-hello-world",
"dependencies": {
"react": "next",
"react-dom": "next",
"react": "^19.2.0",
"react-dom": "^19.2.0",
},
},
},
"packages": {
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
"react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
"react": ["react@18.3.0-next-b72ed698f-20230303", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-l6RbwXa9Peerh9pQEq62DDypxSQfavbybY0wV1vwZ63X0P5VaaEesZAz1KPpnVvXjTtQaOMQsIPvnQwmaVqzTQ=="],
"react-dom": ["react-dom@18.3.0-next-b72ed698f-20230303", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "0.24.0-next-b72ed698f-20230303" }, "peerDependencies": { "react": "18.3.0-next-b72ed698f-20230303" } }, "sha512-0Gh/gmTT6H8KxswIQB/8shdTTfs6QIu86nNqZf3Y0RBqIwgTVxRaQVz14/Fw4/Nt81nK/Jt6KT4bx3yvOxZDGQ=="],
"scheduler": ["scheduler@0.24.0-next-b72ed698f-20230303", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-ct4DMMFbc2kFxCdvbG+i/Jn1S1oqrIFSn2VX/mam+Ya0iuNy+lb8rgT7A+YBUqrQNDaNEqABYI2sOQgqoRxp7w=="],
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
}
}

View File

@@ -4,13 +4,14 @@
"description": "",
"main": "react-hello-world.node.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"build:workerd": "bun build react-hello-world.workerd.jsx --outfile=react-hello-world.workerd.js --format=esm --production && (echo '// MessageChannel polyfill for workerd'; echo 'if (typeof MessageChannel === \"undefined\") {'; echo ' globalThis.MessageChannel = class MessageChannel {'; echo ' constructor() {'; echo ' this.port1 = { onmessage: null, postMessage: () => {} };'; echo ' this.port2 = {'; echo ' postMessage: (msg) => {'; echo ' if (this.port1.onmessage) {'; echo ' queueMicrotask(() => this.port1.onmessage({ data: msg }));'; echo ' }'; echo ' }'; echo ' };'; echo ' }'; echo ' };'; echo '}'; cat react-hello-world.workerd.js) > temp.js && mv temp.js react-hello-world.workerd.js"
},
"keywords": [],
"author": "Colin McDonnell",
"license": "ISC",
"dependencies": {
"react": "next",
"react-dom": "next"
"react": "^19.2.0",
"react-dom": "^19.2.0"
}
}

View File

@@ -0,0 +1,23 @@
using Workerd = import "/workerd/workerd.capnp";
const config :Workerd.Config = (
services = [
(name = "main", worker = .mainWorker),
],
sockets = [
( name = "http",
address = "*:3001",
http = (),
service = "main"
),
]
);
const mainWorker :Workerd.Worker = (
modules = [
(name = "worker", esModule = embed "react-hello-world.workerd.js"),
],
compatibilityDate = "2025-01-01",
compatibilityFlags = ["nodejs_compat_v2"],
);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,40 @@
// Cloudflare Workers version with export default fetch
// Run with: workerd serve react-hello-world.workerd.config.capnp
// Polyfill MessageChannel for workerd
if (typeof MessageChannel === 'undefined') {
globalThis.MessageChannel = class MessageChannel {
constructor() {
this.port1 = { onmessage: null, postMessage: () => {} };
this.port2 = {
postMessage: (msg) => {
if (this.port1.onmessage) {
queueMicrotask(() => this.port1.onmessage({ data: msg }));
}
}
};
}
};
}
import React from "react";
import { renderToReadableStream } from "react-dom/server";
const headers = {
"Content-Type": "text/html",
};
const App = () => (
<html>
<body>
<h1>Hello World</h1>
<p>This is an example.</p>
</body>
</html>
);
export default {
async fetch(request) {
return new Response(await renderToReadableStream(<App />), { headers });
},
};

View File

@@ -41,6 +41,7 @@
},
"overrides": {
"@types/bun": "workspace:packages/@types/bun",
"@types/node": "24.3.1",
"bun-types": "workspace:packages/bun-types",
},
"packages": {
@@ -160,7 +161,7 @@
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
"@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="],
"@types/node": ["@types/node@24.3.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g=="],
"@types/react": ["@types/react@19.1.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="],

View File

@@ -215,46 +215,6 @@ if(ENABLE_ASSERTIONS)
DESCRIPTION "Do not eliminate null-pointer checks"
-fno-delete-null-pointer-checks
)
register_compiler_definitions(
DESCRIPTION "Enable libc++ assertions"
_LIBCPP_ENABLE_ASSERTIONS=1
_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE ${RELEASE}
_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG ${DEBUG}
)
# Nix glibc already sets _FORTIFY_SOURCE, don't override it
if(NOT DEFINED ENV{NIX_CC})
register_compiler_definitions(
DESCRIPTION "Enable fortified sources (Release only)"
_FORTIFY_SOURCE=3 ${RELEASE}
)
endif()
if(LINUX)
register_compiler_definitions(
DESCRIPTION "Enable glibc++ assertions"
_GLIBCXX_ASSERTIONS=1
)
endif()
else()
register_compiler_definitions(
DESCRIPTION "Disable debug assertions"
NDEBUG=1
)
register_compiler_definitions(
DESCRIPTION "Disable libc++ assertions"
_LIBCPP_ENABLE_ASSERTIONS=0
_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE
)
if(LINUX)
register_compiler_definitions(
DESCRIPTION "Disable glibc++ assertions"
_GLIBCXX_ASSERTIONS=0
)
endif()
endif()
# --- Diagnostics ---
@@ -305,14 +265,6 @@ if(UNIX AND CI)
)
endif()
# --- Features ---
# Valgrind cannot handle SSE4.2 instructions
# This is needed for picohttpparser
if(ENABLE_VALGRIND AND ARCH STREQUAL "x64")
register_compiler_definitions(__SSE4_2__=0)
endif()
# --- Other ---
# Workaround for CMake and clang-cl bug.

View File

@@ -136,13 +136,6 @@ else()
set(WARNING WARNING)
endif()
# TODO: This causes flaky zig builds in CI, so temporarily disable it.
# if(CI)
# set(DEFAULT_VENDOR_PATH ${CACHE_PATH}/vendor)
# else()
# set(DEFAULT_VENDOR_PATH ${CWD}/vendor)
# endif()
optionx(VENDOR_PATH FILEPATH "The path to the vendor directory" DEFAULT ${CWD}/vendor)
optionx(TMP_PATH FILEPATH "The path to the temporary directory" DEFAULT ${BUILD_PATH}/tmp)
@@ -917,10 +910,6 @@ function(register_compiler_flags)
endforeach()
endfunction()
function(register_compiler_definitions)
endfunction()
# register_linker_flags()
# Description:
# Registers a linker flag, similar to `add_link_options()`.

View File

@@ -140,11 +140,6 @@ if(ENABLE_ASAN AND ENABLE_LTO)
setx(ENABLE_LTO OFF)
endif()
if(USE_VALGRIND AND NOT USE_BASELINE)
message(WARNING "If valgrind is enabled, baseline must also be enabled")
setx(USE_BASELINE ON)
endif()
if(BUILDKITE_COMMIT)
set(DEFAULT_REVISION ${BUILDKITE_COMMIT})
else()

View File

@@ -27,6 +27,10 @@
"paths": ["src/bake/*.ts", "src/bake/*/*.{ts,css}"],
"exclude": ["src/bake/generated.ts"]
},
{
"output": "BunFrameworkReactSources.txt",
"paths": ["packages/bun-framework-react/*.{ts,tsx,js,jsx}", "packages/bun-framework-react/src/**/*.{ts,tsx,js,jsx}"]
},
{
"output": "BindgenSources.txt",
"paths": ["src/**/*.bind.ts"]

View File

@@ -1,33 +0,0 @@
# https://cppcheck.sourceforge.io/
find_command(
VARIABLE
CPPCHECK_EXECUTABLE
COMMAND
cppcheck
REQUIRED
OFF
)
set(CPPCHECK_COMMAND ${CPPCHECK_EXECUTABLE}
--cppcheck-build-dir=${BUILD_PATH}/cppcheck
--project=${BUILD_PATH}/compile_commands.json
--clang=${CMAKE_CXX_COMPILER}
--std=c++${CMAKE_CXX_STANDARD}
--report-progress
--showtime=summary
)
register_command(
TARGET
cppcheck
COMMENT
"Running cppcheck"
COMMAND
${CMAKE_COMMAND} -E make_directory cppcheck
&& ${CPPCHECK_COMMAND}
CWD
${BUILD_PATH}
TARGETS
${bun}
)

View File

@@ -1,22 +0,0 @@
find_command(
VARIABLE
CPPLINT_PROGRAM
COMMAND
cpplint
REQUIRED
OFF
)
register_command(
TARGET
cpplint
COMMENT
"Running cpplint"
COMMAND
${CPPLINT_PROGRAM}
${BUN_CPP_SOURCES}
CWD
${BUILD_PATH}
TARGETS
${bun}
)

View File

@@ -1,67 +0,0 @@
# IWYU = "Include What You Use"
# https://include-what-you-use.org/
setx(IWYU_SOURCE_PATH ${CACHE_PATH}/iwyu-${LLVM_VERSION})
setx(IWYU_BUILD_PATH ${IWYU_SOURCE_PATH}/build)
setx(IWYU_PROGRAM ${IWYU_BUILD_PATH}/bin/include-what-you-use)
register_repository(
NAME
iwyu
REPOSITORY
include-what-you-use/include-what-you-use
BRANCH
clang_${LLVM_VERSION}
PATH
${IWYU_SOURCE_PATH}
)
register_command(
TARGET
build-iwyu
COMMENT
"Building iwyu"
COMMAND
${CMAKE_COMMAND}
-B${IWYU_BUILD_PATH}
-G${CMAKE_GENERATOR}
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER}
-DIWYU_LLVM_ROOT_PATH=${LLVM_PREFIX}
&& ${CMAKE_COMMAND}
--build ${IWYU_BUILD_PATH}
CWD
${IWYU_SOURCE_PATH}
TARGETS
clone-iwyu
)
find_command(
VARIABLE
PYTHON_EXECUTABLE
COMMAND
python3
python
VERSION
>=3.0.0
REQUIRED
OFF
)
register_command(
TARGET
iwyu
COMMENT
"Running iwyu"
COMMAND
${CMAKE_COMMAND}
-E env IWYU_BINARY=${IWYU_PROGRAM}
${PYTHON_EXECUTABLE}
${IWYU_SOURCE_PATH}/iwyu_tool.py
-p ${BUILD_PATH}
CWD
${BUILD_PATH}
TARGETS
build-iwyu
${bun}
)

View File

@@ -45,12 +45,6 @@ else()
endif()
set(LLVM_ZIG_CODEGEN_THREADS 0)
# This makes the build slower, so we turn it off for now.
# if (DEBUG)
# include(ProcessorCount)
# ProcessorCount(CPU_COUNT)
# set(LLVM_ZIG_CODEGEN_THREADS ${CPU_COUNT})
# endif()
# --- Dependencies ---
@@ -71,9 +65,6 @@ set(BUN_DEPENDENCIES
)
include(CloneZstd)
# foreach(dependency ${BUN_DEPENDENCIES})
# include(Clone${dependency})
# endforeach()
# --- Codegen ---
@@ -819,7 +810,7 @@ set_target_properties(${bun} PROPERTIES
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS YES
CXX_VISIBILITY_PRESET hidden
C_STANDARD 23
C_STANDARD 17 # Cannot uprev to C23 because MSVC doesn't have support.
C_STANDARD_REQUIRED YES
VISIBILITY_INLINES_HIDDEN YES
)
@@ -944,7 +935,7 @@ if(NOT WIN32)
if (NOT ABI STREQUAL "musl")
target_compile_options(${bun} PUBLIC
-fsanitize=null
-fsanitize-recover=all
-fno-sanitize-recover=all
-fsanitize=bounds
-fsanitize=return
-fsanitize=nullability-arg
@@ -999,6 +990,20 @@ if(NOT WIN32)
)
if(ENABLE_ASAN)
target_compile_options(${bun} PUBLIC
-fsanitize=null
-fno-sanitize-recover=all
-fsanitize=bounds
-fsanitize=return
-fsanitize=nullability-arg
-fsanitize=nullability-assign
-fsanitize=nullability-return
-fsanitize=returns-nonnull-attribute
-fsanitize=unreachable
)
target_link_libraries(${bun} PRIVATE
-fsanitize=null
)
target_compile_options(${bun} PUBLIC -fsanitize=address)
target_link_libraries(${bun} PUBLIC -fsanitize=address)
endif()
@@ -1247,15 +1252,9 @@ if(LINUX)
target_link_libraries(${bun} PUBLIC libatomic.so)
endif()
if(USE_SYSTEM_ICU)
target_link_libraries(${bun} PRIVATE libicudata.a)
target_link_libraries(${bun} PRIVATE libicui18n.a)
target_link_libraries(${bun} PRIVATE libicuuc.a)
else()
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicudata.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicui18n.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicuuc.a)
endif()
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicudata.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicui18n.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicuuc.a)
endif()
if(WIN32)
@@ -1308,32 +1307,32 @@ if(NOT BUN_CPP_ONLY)
OUTPUTS
${BUILD_PATH}/${bunStripExe}
)
# Then sign both executables on Windows
if(WIN32 AND ENABLE_WINDOWS_CODESIGNING)
set(SIGN_SCRIPT "${CMAKE_SOURCE_DIR}/.buildkite/scripts/sign-windows.ps1")
# Verify signing script exists
if(NOT EXISTS "${SIGN_SCRIPT}")
message(FATAL_ERROR "Windows signing script not found: ${SIGN_SCRIPT}")
endif()
# Use PowerShell for Windows code signing (native Windows, no path issues)
find_program(POWERSHELL_EXECUTABLE
find_program(POWERSHELL_EXECUTABLE
NAMES pwsh.exe powershell.exe
PATHS
PATHS
"C:/Program Files/PowerShell/7"
"C:/Program Files (x86)/PowerShell/7"
"C:/Windows/System32/WindowsPowerShell/v1.0"
DOC "Path to PowerShell executable"
)
if(NOT POWERSHELL_EXECUTABLE)
set(POWERSHELL_EXECUTABLE "powershell.exe")
endif()
message(STATUS "Using PowerShell executable: ${POWERSHELL_EXECUTABLE}")
# Sign both bun-profile.exe and bun.exe after stripping
register_command(
TARGET

View File

@@ -4,7 +4,7 @@ register_repository(
REPOSITORY
ebiggers/libdeflate
COMMIT
96836d7d9d10e3e0d53e6edb54eb908514e336c4
c8c56a20f8f621e6a966b716b31f1dedab6a41e3
)
register_cmake_command(

View File

@@ -1,4 +1,4 @@
FROM alpine:3.20 AS build
FROM alpine:3.22 AS build
# https://github.com/oven-sh/bun/releases
ARG BUN_VERSION=latest
@@ -44,7 +44,7 @@ RUN apk --no-cache add ca-certificates curl dirmngr gpg gpg-agent unzip \
&& rm -f "bun-linux-$build.zip" SHASUMS256.txt.asc SHASUMS256.txt \
&& chmod +x /usr/local/bin/bun
FROM alpine:3.20
FROM alpine:3.22
# Disable the runtime transpiler cache by default inside Docker containers.
# On ephemeral containers, the cache is not useful

View File

@@ -257,12 +257,13 @@ $ bun test --watch
Bun supports the following lifecycle hooks:
| Hook | Description |
| ------------ | --------------------------- |
| `beforeAll` | Runs once before all tests. |
| `beforeEach` | Runs before each test. |
| `afterEach` | Runs after each test. |
| `afterAll` | Runs once after all tests. |
| Hook | Description |
| ---------------- | -------------------------------------------------------- |
| `beforeAll` | Runs once before all tests. |
| `beforeEach` | Runs before each test. |
| `afterEach` | Runs after each test. |
| `afterAll` | Runs once after all tests. |
| `onTestFinished` | Runs after a test finishes, including after `afterEach`. |
These hooks can be defined inside test files, or in a separate file that is preloaded with the `--preload` flag.

View File

@@ -24,8 +24,8 @@ import { watch } from "fs";
const watcher = watch(
import.meta.dir,
{ recursive: true },
(event, filename) => {
console.log(`Detected ${event} in ${filename}`);
(event, relativePath) => {
console.log(`Detected ${event} in ${relativePath}`);
},
);
```

View File

@@ -249,6 +249,41 @@ This is useful for:
The `--concurrent` CLI flag will override this setting when specified.
### `test.onlyFailures`
When enabled, only failed tests are displayed in the output. This helps reduce noise in large test suites by hiding passing tests. Default `false`.
```toml
[test]
onlyFailures = true
```
This is equivalent to using the `--only-failures` flag when running `bun test`.
### `test.reporter`
Configure the test reporter settings.
#### `test.reporter.dots`
Enable the dots reporter, which displays a compact output showing a dot for each test. Default `false`.
```toml
[test.reporter]
dots = true
```
#### `test.reporter.junit`
Enable JUnit XML reporting and specify the output file path.
```toml
[test.reporter]
junit = "test-results.xml"
```
This generates a JUnit XML report that can be consumed by CI systems and other tools.
### `test.randomize`
Run tests in random order. Default `false`.

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "bun",
"version": "1.3.1",
"version": "1.3.2",
"workspaces": [
"./packages/bun-types",
"./packages/@types/bun"
@@ -23,7 +23,8 @@
},
"resolutions": {
"bun-types": "workspace:packages/bun-types",
"@types/bun": "workspace:packages/@types/bun"
"@types/bun": "workspace:packages/@types/bun",
"@types/node": "24.3.1"
},
"scripts": {
"build": "bun --silent run build:debug",
@@ -86,9 +87,10 @@
"clean:zig": "rm -rf build/debug/cache/zig build/debug/CMakeCache.txt 'build/debug/*.o' .zig-cache zig-out || true",
"machine:linux:ubuntu": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=linux --distro=ubuntu --release=25.04",
"machine:linux:debian": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=linux --distro=debian --release=12",
"machine:linux:alpine": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=linux --distro=alpine --release=3.21",
"machine:linux:alpine": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=linux --distro=alpine --release=3.22",
"machine:linux:amazonlinux": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=linux --distro=amazonlinux --release=2023",
"machine:windows:2019": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=windows --release=2019",
"machine:freebsd": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.large --os=freebsd --release=14.3",
"sync-webkit-source": "bun ./scripts/sync-webkit-source.ts"
}
}

View File

@@ -0,0 +1 @@
bun-framework-react*.tgz

View File

@@ -0,0 +1,10 @@
<img src="https://bun.com/logo.png" height="36" />
# `bun-framework-react`
An implementation of the Bun Rendering API for React, with RSC (React Server Components)
1. `bun add bun-framework-react --dev`
2. Make a `pages/index.tsx` file, with a page component defualt export
3. Run `bun --app`
4. Open [localhost:3000](https://localhost:3000) 🎉

View File

@@ -0,0 +1,32 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "bun-framework-react",
"dependencies": {
"react": "0.0.0-experimental-a757cb76-20251002",
"react-dom": "0.0.0-experimental-a757cb76-20251002",
"react-refresh": "0.0.0-experimental-a757cb76-20251002",
},
"devDependencies": {
"@types/react": "^19.1.13",
"@types/react-dom": "^19.1.9",
},
},
},
"packages": {
"@types/react": ["@types/react@19.1.13", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ=="],
"@types/react-dom": ["@types/react-dom@19.1.9", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"react": ["react@0.0.0-experimental-a757cb76-20251002", "", {}, "sha512-7ZcE4sSUGgrXgUWa84iwC9DqwDFbQBgffFmu2DoNqFseruA/JjxQDXKwpV5acdxOM/0uzfSGrapHU3C3ZLiU2g=="],
"react-dom": ["react-dom@0.0.0-experimental-a757cb76-20251002", "", { "dependencies": { "scheduler": "0.0.0-experimental-a757cb76-20251002" }, "peerDependencies": { "react": "0.0.0-experimental-a757cb76-20251002" } }, "sha512-XjIkmW8mMx9kURHJUY+dhv1Ugan3RmEJIwrZEbAFcJA4S8RXL1wl+xsQJpDCh8kmeX/n25VAmFY8/j1MzqUHfA=="],
"react-refresh": ["react-refresh@0.0.0-experimental-a757cb76-20251002", "", {}, "sha512-uYd+N2W8/LymZQyY5u1BMWVvLlBV+5SxztBsFjOGuitE4x7sSCj8TwgS+8bxIEBucEVJglfOhDPCPohL/uEQdg=="],
"scheduler": ["scheduler@0.0.0-experimental-a757cb76-20251002", "", {}, "sha512-YCVGuzmF7u5HIpOdPFD4tZTPzQlOrtViag7uaWjJXfFx37C8sypfNeSXNXoYJeT/ICybxP1EsbHh2oByQHC2Cg=="],
}
}

View File

@@ -0,0 +1,64 @@
import { onServerSideReload } from "bun:app/client";
import { hydrateRoot } from "react-dom/client";
import { initialRscPayloadThen } from "./src/client/app.ts";
import { router } from "./src/client/constants.ts";
import { Root } from "./src/client/root.tsx";
hydrateRoot(document, <Root />, {
onUncaughtError(e) {
console.error(e);
},
});
const firstPageId = Date.now();
{
history.replaceState(firstPageId, "", location.href);
initialRscPayloadThen(result => {
if (router.hasNavigatedSinceDOMContentLoaded()) return;
// Collect the list of CSS files that were added from SSR
const links = document.querySelectorAll<HTMLLinkElement>("link[data-bake-ssr]");
router.css.clear();
for (let i = 0; i < links.length; i++) {
const link = links[i];
if (!link) continue;
const href = new URL(link.href).pathname;
router.css.push(href);
// Hack: cannot add this to `cssFiles` because React owns the element, and
// it will be removed when any navigation is performed.
}
router.setCachedPage(firstPageId, {
css: [...router.css.getList()],
element: result,
});
});
if (document.startViewTransition !== undefined) {
// View transitions are used by navigations to ensure that the page rerender
// all happens in one operation. Additionally, developers may animate
// different elements. The default fade animation is disabled so that the
// out-of-the-box experience feels like there are no view transitions.
// This is done client-side because a React error will unmount all elements.
const sheet = new CSSStyleSheet();
document.adoptedStyleSheets.push(sheet);
sheet.replaceSync(":where(*)::view-transition-group(root){animation:none}");
}
}
window.addEventListener("popstate", async event => {
const state = typeof event.state === "number" ? event.state : undefined;
await router.navigate(location.href, state);
});
if (import.meta.env.DEV) {
// Frameworks can call `onServerSideReload` to hook into server-side hot
// module reloading.
onServerSideReload(async () => {
const newId = Date.now();
history.replaceState(newId, "", location.href);
await router.navigate(location.href, newId);
});
}

View File

@@ -0,0 +1,35 @@
import type { Framework } from "bun:app";
function resolve(specifier: string) {
return Bun.fileURLToPath(import.meta.resolve(specifier));
}
const framework: Framework = {
serverComponents: {
separateSSRGraph: true,
serverRuntimeImportSource: resolve("./vendor/react-server-dom-bun/server.node.js"),
},
reactFastRefresh: {
importSource: resolve("react-refresh/runtime"),
},
fileSystemRouterTypes: [
{
root: "pages",
clientEntryPoint: resolve("./client.tsx"),
serverEntryPoint: resolve("./server.tsx"),
extensions: [".tsx", ".jsx"],
style: "nextjs-pages",
layouts: true,
ignoreUnderscores: true,
prefix: "/",
ignoreDirs: ["node_modules", ".git"],
},
],
// bundlerOptions: {
// ssr: {
// conditions: ["react-server"],
// },
// },
};
export default framework;

View File

@@ -0,0 +1,36 @@
{
"name": "bun-framework-react",
"version": "0.0.0-canary.10",
"devDependencies": {
"@types/react": "^19.1.13",
"@types/react-dom": "^19.1.9"
},
"exports": {
".": "./index.ts",
"./package.json": "./package.json",
"./ssr.tsx": "./ssr.tsx",
"./server.tsx": "./server.tsx",
"./client.tsx": "./client.tsx",
"./*": "./src/components/*.tsx"
},
"description": "React framework integration with RSC, for the Bun Rendering API",
"files": [
"./vendor",
"./src",
"./*.ts",
"./*.tsx",
"./README.md"
],
"keywords": [
"bun",
"react",
"framework",
"bake"
],
"type": "module",
"dependencies": {
"react": "0.0.0-experimental-a757cb76-20251002",
"react-dom": "0.0.0-experimental-a757cb76-20251002",
"react-refresh": "0.0.0-experimental-a757cb76-20251002"
}
}

View File

@@ -1,23 +1,24 @@
import type { Bake } from "bun";
import { renderToHtml, renderToStaticHtml } from "bun-framework-react/ssr.tsx" with { bunBakeGraph: "ssr" };
import { serverManifest } from "bun:bake/server";
import * as Bake from "bun:app";
import { serverManifest } from "bun:app/server";
import type { AsyncLocalStorage } from "node:async_hooks";
import { PassThrough } from "node:stream";
import { renderToPipeableStream } from "react-server-dom-bun/server.node.unbundled.js";
import type { RequestContext } from "../hmr-runtime-server";
import type { RequestContext } from "../../src/bake/hmr-runtime-server.ts";
import { renderToPipeableStream } from "./vendor/react-server-dom-bun/server.node.unbundled.js";
function assertReactComponent(Component: any) {
function assertReactComponent(Component: unknown): asserts Component is React.JSXElementConstructor<unknown> {
if (typeof Component !== "function") {
console.log("Expected a React component", Component, typeof Component);
throw new Error("Expected a React component");
}
}
// This function converts the route information into a React component tree.
function getPage(meta: Bake.RouteMetadata & { request?: Request }, styles: readonly string[]) {
function getPage(meta: Bake.RouteMetadata & { request?: Request | undefined }, styles: readonly string[]) {
let route = component(meta.pageModule, meta.params, meta.request);
for (const layout of meta.layouts) {
const Layout = layout.default;
const Layout = layout.default as typeof layout.default & { displayName?: string };
Layout.displayName ??= "Layout";
if (import.meta.env.DEV) assertReactComponent(Layout);
route = <Layout params={meta.params}>{route}</Layout>;
}
@@ -26,7 +27,6 @@ function getPage(meta: Bake.RouteMetadata & { request?: Request }, styles: reado
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Bun + React Server Components</title>
{styles.map(url => (
// `data-bake-ssr` is used on the client-side to construct the styles array.
<link key={url} rel="stylesheet" href={url} data-bake-ssr />
@@ -37,8 +37,12 @@ function getPage(meta: Bake.RouteMetadata & { request?: Request }, styles: reado
);
}
function component(mod: any, params: Record<string, string> | null, request?: Request) {
function component(mod: any, params: Record<string, string | string[]> | null, request?: Request) {
if (!mod || !mod.default) {
throw new Error("Pages must have a default export that is a React component");
}
const Page = mod.default;
let props = {};
if (import.meta.env.DEV) assertReactComponent(Page);
@@ -51,7 +55,6 @@ function component(mod: any, params: Record<string, string> | null, request?: Re
props = method();
}
// Pass request prop if mode is 'ssr'
if (mod.mode === "ssr" && request) {
props.request = request;
}
@@ -76,7 +79,7 @@ export async function render(
const skipSSR = request.headers.get("Accept")?.includes("text/x-component");
// Check if the page module has a streaming export, default to false
const streaming = meta.pageModule.streaming ?? false;
const streaming = meta.pageModule?.streaming ?? false;
// Do not render <link> tags if the request is skipping SSR.
const page = getPage(meta, skipSSR ? [] : meta.styles);
@@ -104,7 +107,6 @@ export async function render(
// Mark as aborted and call the abort function
signal.aborted = err;
// @ts-expect-error
signal.abort(err);
rscPayload.destroy(err);
},
@@ -236,5 +238,5 @@ export const contentTypeToStaticFile = {
export interface MiniAbortSignal {
aborted: Error | undefined;
/** Caller must set `aborted` to true before calling. */
abort: () => void;
abort: (reason?: any) => void;
}

View File

@@ -0,0 +1,96 @@
import type { ReactNode, SetStateAction } from "react";
import { createFromReadableStream } from "../../vendor/react-server-dom-bun/client.browser.js";
import { store, useStore, type Store } from "./store.ts";
export type NonNullishReactNode = Exclude<ReactNode, null | undefined>;
export type RenderableRscPayload = Promise<NonNullishReactNode> | NonNullishReactNode;
const encoder = new TextEncoder();
function enqueueChunks(
controller: ReadableStreamDefaultController<Uint8Array<ArrayBuffer>>,
...chunks: (string | Uint8Array<ArrayBuffer>)[]
) {
for (let chunk of chunks) {
if (typeof chunk === "string") {
chunk = encoder.encode(chunk);
}
controller.enqueue(chunk);
}
}
export interface AppState {
/**
* The renderable RSC payload
*/
rsc: RenderableRscPayload;
/**
* A controller that aborts on the first render
*/
abortOnRender?: AbortController | undefined;
}
// The initial RSC payload is put into inline <script> tags that follow the pattern
// `(self.__bun_f ??= []).push(chunk)`, which is converted into a ReadableStream
// here for React hydration. Since inline scripts are executed immediately, and
// this file is loaded asynchronously, the `__bun_f` becomes a clever way to
// stream the arbitrary data while HTML is loading. In a static build, this is
// setup as an array with one string.
const initialRscPayload: Promise<NonNullishReactNode> =
typeof document === "undefined"
? Promise.resolve(false)
: createFromReadableStream(
new ReadableStream<NonNullishReactNode>({
start(controller) {
const bunF = (self.__bun_f ??= []);
const originalPush = bunF.push;
bunF.push = function (this: typeof bunF, ...chunks: (string | Uint8Array<ArrayBuffer>)[]) {
enqueueChunks(controller, ...chunks);
return originalPush.apply(this, chunks);
}.bind(bunF);
bunF.forEach(chunk => enqueueChunks(controller, chunk));
if (document.readyState === "loading") {
document.addEventListener(
"DOMContentLoaded",
() => {
controller.close();
},
{ once: true },
);
} else {
controller.close();
}
},
}),
);
declare global {
interface Window {
__bun_f: Array<string | Uint8Array<ArrayBuffer>>;
}
}
const appStore: Store<AppState> = store<AppState>({
rsc: initialRscPayload,
});
export function setAppState(element: SetStateAction<AppState>): void {
appStore.write(element);
}
export function useAppState(): AppState {
return useStore(appStore);
}
export function getAppState(): AppState {
return appStore.read();
}
export function initialRscPayloadThen(then: (rsc: NonNullishReactNode) => void): void {
void initialRscPayload.then(then);
}

View File

@@ -0,0 +1,3 @@
import { Router } from "./router.ts";
export const router: Router = new Router();

View File

@@ -0,0 +1,355 @@
export class BakeCSSManager {
private readonly td = new TextDecoder();
// It is the framework's responsibility to ensure that client-side navigation
// loads CSS files. The implementation here loads all CSS files as <link> tags,
// and uses the ".disabled" property to enable/disable them.
private readonly cssFiles = new Map<string, { promise: Promise<void> | null; link: HTMLLinkElement }>();
private currentCssList: string[] | null = null;
public async set(list: string[]): Promise<void> {
this.currentCssList = list;
await this.ensureCssIsReady(this.currentCssList);
}
/**
* Get the actual list instance. Mutating this list will update the current
* CSS list (it is the actual array).
*/
public getList(): string[] {
return (this.currentCssList ??= []);
}
public clear(): void {
this.currentCssList = [];
}
public push(href: string): void {
const arr = this.getList();
arr.push(href);
}
/** This function blocks until all CSS files are loaded. */
ensureCssIsReady(cssList: string[] = this.currentCssList ?? []): Promise<void[]> | void {
const wait: Promise<void>[] = [];
for (const href of cssList) {
const existing = this.cssFiles.get(href);
if (existing) {
const { promise, link } = existing;
if (promise) {
wait.push(promise);
}
link.disabled = false;
} else {
const link = document.createElement("link");
let entry: { promise: Promise<void> | null; link: HTMLLinkElement };
const promise = new Promise<void>((resolve, reject) => {
link.rel = "stylesheet";
link.onload = resolve.bind(null, undefined);
link.onerror = reject;
link.href = href;
document.head.appendChild(link);
}).finally(() => {
entry.promise = null;
});
entry = { promise, link };
this.cssFiles.set(href, entry);
wait.push(promise);
}
}
if (wait.length === 0) {
return;
}
return Promise.all(wait);
}
public disableUnusedCssFilesIfNeeded(): void {
if (this.currentCssList) {
this.disableUnusedCssFiles();
}
}
disableUnusedCssFiles(): void {
// TODO: create a list of files that should be updated instead of a full loop
for (const [href, { link }] of this.cssFiles) {
if (!this.currentCssList!.includes(href)) {
link.disabled = true;
}
}
}
async readCssMetadata(
stream: ReadableStream<Uint8Array<ArrayBuffer>>,
): Promise<ReadableStream<Uint8Array<ArrayBuffer>>> {
let reader: ReadableStreamBYOBReader;
try {
// Using BYOB reader allows reading an exact amount of bytes, which allows
// passing the stream to react without creating a wrapped stream.
reader = stream.getReader({ mode: "byob" });
} catch (e) {
return this.readCssMetadataFallback(stream);
}
const header = (await reader.read(new Uint32Array(1))).value;
if (!header) {
if (import.meta.env.DEV) {
throw new Error("Did not read all bytes! This is a bug in bun-framework-react");
} else {
location.reload();
}
}
const first = header?.[0];
if (first !== undefined && first > 0) {
const cssRaw = (await reader.read(new Uint8Array(first))).value;
if (!cssRaw) {
if (import.meta.env.DEV) {
throw new Error("Did not read all bytes! This is a bug in bun-framework-react");
} else {
location.reload();
}
}
this.set(this.td.decode(cssRaw).split("\n"));
} else {
this.clear();
}
reader.releaseLock();
return stream;
}
/**
* Like readCssMetadata, but does NOT mutate the current CSS list. It returns
* the remaining stream after consuming the CSS header and the parsed list of
* CSS hrefs so callers can preload styles without switching the active list.
*/
async readCssMetadataForPrefetch(
stream: ReadableStream<Uint8Array<ArrayBuffer>>,
): Promise<{ stream: ReadableStream<Uint8Array<ArrayBuffer>>; list: string[] }> {
let reader: ReadableStreamBYOBReader;
try {
reader = stream.getReader({ mode: "byob" });
} catch (e) {
const s = await this.readCssMetadataFallbackForPrefetch(stream);
return { stream: s.stream, list: s.list };
}
const header = (await reader.read(new Uint32Array(1))).value;
if (!header) {
if (import.meta.env.DEV) {
throw new Error("Did not read all bytes! This is a bug in bun-framework-react");
} else {
location.reload();
}
}
const first = header?.[0];
let list: string[] = [];
if (first !== undefined && first > 0) {
const cssRaw = (await reader.read(new Uint8Array(first))).value;
if (!cssRaw) {
if (import.meta.env.DEV) {
throw new Error("Did not read all bytes! This is a bug in bun-framework-react");
} else {
location.reload();
}
}
list = this.td.decode(cssRaw).split("\n");
}
reader.releaseLock();
return { stream, list };
}
// Prefetch fallback variant that does not mutate currentCssList.
async readCssMetadataFallbackForPrefetch(
stream: ReadableStream<Uint8Array<ArrayBuffer>>,
): Promise<{ stream: ReadableStream<Uint8Array<ArrayBuffer>>; list: string[] }> {
const reader = stream.getReader();
const chunks: Uint8Array<ArrayBuffer>[] = [];
let totalBytes = 0;
const readChunk = async (size: number) => {
while (totalBytes < size) {
const { value, done } = await reader.read();
if (!done) {
chunks.push(value);
totalBytes += value.byteLength;
} else if (totalBytes < size) {
if (import.meta.env.DEV) {
throw new Error("Not enough bytes, expected " + size + " but got " + totalBytes);
} else {
location.reload();
}
}
}
if (chunks.length === 1) {
const first = chunks[0]!;
if (first.byteLength >= size) {
chunks[0] = first.subarray(size);
totalBytes -= size;
return first.subarray(0, size);
} else {
chunks.length = 0;
totalBytes = 0;
return first;
}
} else {
const buffer = new Uint8Array(size);
let i = 0;
let chunk: Uint8Array<ArrayBuffer> | undefined;
let len;
while (size > 0) {
chunk = chunks.shift();
if (!chunk) continue;
const { byteLength } = chunk;
len = Math.min(byteLength, size);
buffer.set(len === byteLength ? chunk : chunk.subarray(0, len), i);
i += len;
size -= len;
}
if (chunk !== undefined && len !== undefined && chunk.byteLength > len) {
chunks.unshift(chunk.subarray(len));
}
totalBytes -= size;
return buffer;
}
};
const header = new Uint32Array(await readChunk(4))[0];
let list: string[] = [];
if (header === 0) {
list = [];
} else if (header !== undefined) {
list = this.td.decode(await readChunk(header)).split("\n");
}
if (chunks.length === 0) {
return { stream, list };
}
// New readable stream that includes the remaining data
const remainingStream = new ReadableStream<Uint8Array<ArrayBuffer>>({
async start(controller) {
for (const chunk of chunks) {
controller.enqueue(chunk);
}
while (true) {
const { value, done } = await reader.read();
if (done) {
controller.close();
return;
}
controller.enqueue(value);
}
},
cancel() {
reader.cancel();
},
});
return { stream: remainingStream, list };
}
// Safari does not support BYOB reader. When this is resolved, this fallback
// should be kept for a few years since Safari on iOS is versioned to the OS.
// https://bugs.webkit.org/show_bug.cgi?id=283065
async readCssMetadataFallback(
stream: ReadableStream<Uint8Array<ArrayBuffer>>,
): Promise<ReadableStream<Uint8Array<ArrayBuffer>>> {
const reader = stream.getReader();
const chunks: Uint8Array<ArrayBuffer>[] = [];
let totalBytes = 0;
const readChunk = async (size: number) => {
while (totalBytes < size) {
const { value, done } = await reader.read();
if (!done) {
chunks.push(value);
totalBytes += value.byteLength;
} else if (totalBytes < size) {
if (import.meta.env.DEV) {
throw new Error("Not enough bytes, expected " + size + " but got " + totalBytes);
} else {
location.reload();
}
}
}
if (chunks.length === 1) {
const first = chunks[0]!;
if (first.byteLength >= size) {
chunks[0] = first.subarray(size);
totalBytes -= size;
return first.subarray(0, size);
} else {
chunks.length = 0;
totalBytes = 0;
return first;
}
} else {
const buffer = new Uint8Array(size);
let i = 0;
let chunk: Uint8Array<ArrayBuffer> | undefined;
let len;
while (size > 0) {
chunk = chunks.shift();
if (!chunk) continue;
const { byteLength } = chunk;
len = Math.min(byteLength, size);
buffer.set(len === byteLength ? chunk : chunk.subarray(0, len), i);
i += len;
size -= len;
}
if (chunk !== undefined && len !== undefined && chunk.byteLength > len) {
chunks.unshift(chunk.subarray(len));
}
totalBytes -= size;
return buffer;
}
};
const header = new Uint32Array(await readChunk(4))[0];
if (header === 0) {
this.clear();
} else if (header !== undefined) {
this.set(this.td.decode(await readChunk(header)).split("\n"));
}
if (chunks.length === 0) {
return stream;
}
// New readable stream that includes the remaining data
return new ReadableStream<Uint8Array<ArrayBuffer>>({
async start(controller) {
for (const chunk of chunks) {
controller.enqueue(chunk);
}
while (true) {
const { value, done } = await reader.read();
if (done) {
controller.close();
return;
}
controller.enqueue(value);
}
},
cancel() {
reader.cancel();
},
});
}
}

View File

@@ -0,0 +1,3 @@
export function isThenable<T>(payload: PromiseLike<T> | unknown): payload is PromiseLike<T> {
return payload !== null && typeof payload === "object" && "then" in payload;
}

View File

@@ -0,0 +1,29 @@
import { use, useLayoutEffect, type ReactNode } from "react";
import { useAppState } from "./app.ts";
import { router } from "./constants.ts";
import { isThenable } from "./lib/util.ts";
// This is a function component that uses the `use` hook, which unwraps a
// promise. The promise results in a component containing suspense boundaries.
// This is the same logic that happens on the server, except there is also a
// hook to update the promise when the client navigates. The `Root` component
// also updates CSS files when navigating between routes.
export function Root(): ReactNode {
const app = useAppState();
// Layout effects are executed right before the browser paints,
// which is the perfect time to make CSS visible.
useLayoutEffect(() => {
if (app.abortOnRender) {
try {
app.abortOnRender.abort();
} catch {}
}
requestAnimationFrame(() => {
router.css.disableUnusedCssFilesIfNeeded();
});
});
return isThenable(app.rsc) ? use(app.rsc) : app.rsc;
}

View File

@@ -0,0 +1,215 @@
import { flushSync } from "react-dom";
import { createFromReadableStream } from "../../vendor/react-server-dom-bun/client.browser.js";
import { getAppState, setAppState, type AppState, type NonNullishReactNode } from "./app.ts";
import { BakeCSSManager } from "./css.ts";
export interface CachedPage {
css: string[];
element: NonNullishReactNode;
}
export class Router {
private lastNavigationId: number = 0;
private lastNavigationController: AbortController | null = null;
// Keep a cache of page objects to avoid re-fetching a page when pressing the
// back button. The cache is indexed by the date it was created.
private readonly cachedPages = new Map<number, CachedPage>();
// Track in-flight RSC fetches keyed by the resolved request URL so that
// navigations can adopt an existing stream instead of issuing a duplicate
// request.
private readonly inflight = new Map<
string,
{ controller: AbortController; css: string[]; model: Promise<NonNullishReactNode> }
>();
public readonly css: BakeCSSManager = new BakeCSSManager();
public hasNavigatedSinceDOMContentLoaded(): boolean {
return this.lastNavigationId !== 0;
}
public setCachedPage(id: number, page: CachedPage): void {
this.cachedPages.set(id, page);
}
/** Start fetching an RSC payload for a given href without committing UI. */
public async prefetch(href: string): Promise<void> {
const requestUrl = this.computeRequestUrl(href);
if (this.inflight.has(requestUrl)) return;
const controller = new AbortController();
const signal = controller.signal;
let response: Response;
try {
response = await fetch(requestUrl, {
headers: { Accept: "text/x-component" },
signal,
});
if (!response.ok) return;
} catch {
return;
}
// Parse CSS list without mutating the active CSS set, and keep the stream
// intact for React consumption.
const { stream, list } = await this.css.readCssMetadataForPrefetch(response.body!);
const model = createFromReadableStream(stream) as Promise<NonNullishReactNode>;
this.inflight.set(requestUrl, { controller, css: list, model });
// Cleanup when the model settles to avoid leaks (if we never navigate).
void model.finally(() => {
// Do not delete if it's currently adopted by a navigation (i.e. lastNavigationController === controller)
if (this.inflight.get(requestUrl)?.controller === controller) return;
this.inflight.delete(requestUrl);
});
}
private computeRequestUrl(href: string): string {
const url = new URL(href, location.href);
url.hash = "";
if (import.meta.env.STATIC) {
// For static, fetch the .rsc artifact
const path = url.pathname.replace(/\/(?:index)?$/, "") + "/index.rsc";
return new URL(path + url.search, location.origin).toString();
}
return url.toString();
}
async navigate(href: string, cacheId: number | undefined): Promise<void> {
const thisNavigationId = ++this.lastNavigationId;
const olderController = this.lastNavigationController;
// If there is an in-flight prefetch for this href, adopt it.
const requestUrl = this.computeRequestUrl(href);
const adopted = this.inflight.get(requestUrl);
this.lastNavigationController = adopted?.controller ?? new AbortController();
const signal = this.lastNavigationController.signal;
signal.addEventListener(
"abort",
() => {
olderController?.abort();
},
{ once: true },
);
// If the page is cached, use the cached promise instead of fetching it again.
const cached = cacheId !== undefined && this.cachedPages.get(cacheId);
if (cached) {
await this.css.set(cached.css);
const state: AppState = {
rsc: cached.element,
};
if (olderController?.signal.aborted === false) {
state.abortOnRender = olderController;
}
setAppState(state);
return;
}
let p: NonNullishReactNode;
if (adopted) {
// Adopt prefetch: set CSS list and await the same model.
await this.css.set(adopted.css);
const cssWaitPromise = this.css.ensureCssIsReady();
{
const result = await adopted.model;
if (result == null) {
throw new Error("RSC payload was empty");
}
p = result as NonNullishReactNode;
}
if (thisNavigationId !== this.lastNavigationId) return;
if (cssWaitPromise) {
await cssWaitPromise;
if (thisNavigationId !== this.lastNavigationId) return;
}
// Remove from inflight now that it's adopted
this.inflight.delete(requestUrl);
} else {
let response: Response;
try {
response = await fetch(requestUrl, {
headers: { Accept: "text/x-component" },
signal,
});
if (!response.ok) {
throw new Error(`Failed to fetch ${href}: ${response.status} ${response.statusText}`);
}
} catch (err) {
if (thisNavigationId === this.lastNavigationId) {
// Bail out to browser navigation if this fetch fails.
console.error(err);
location.href = href;
}
return;
}
if (thisNavigationId !== this.lastNavigationId) return;
let stream = response.body!;
stream = await this.css.readCssMetadata(stream);
if (thisNavigationId !== this.lastNavigationId) return;
const cssWaitPromise = this.css.ensureCssIsReady();
{
const model = createFromReadableStream(stream) as Promise<NonNullishReactNode | undefined | null>;
const result = await model;
if (result == null) {
throw new Error("RSC payload was empty");
}
p = result as NonNullishReactNode;
}
if (thisNavigationId !== this.lastNavigationId) return;
if (cssWaitPromise) {
await cssWaitPromise;
if (thisNavigationId !== this.lastNavigationId) return;
}
}
// Save this promise so that pressing the back button in the browser navigates
// to the same instance of the old page, instead of re-fetching it.
if (cacheId !== undefined) {
this.cachedPages.set(cacheId, {
css: [...this.css.getList()],
element: p,
});
}
// Defer aborting a previous request until VERY late. If a previous stream is
// aborted while rendering, it will cancel the render, resulting in a flash of
// a blank page.
if (olderController?.signal.aborted === false) {
getAppState().abortOnRender = olderController;
}
// Tell react about the new page promise
if (document.startViewTransition) {
document.startViewTransition(() => {
flushSync(() => {
if (thisNavigationId === this.lastNavigationId) {
setAppState(old => ({
rsc: p,
abortOnRender: olderController ?? old.abortOnRender,
}));
}
});
});
} else {
setAppState(old => ({
rsc: p,
abortOnRender: olderController ?? old.abortOnRender,
}));
}
}
}

View File

@@ -0,0 +1,39 @@
import { useSyncExternalStore, type SetStateAction } from "react";
export interface Store<T> {
read(): T;
write(value: SetStateAction<T>): void;
subscribe(callback: () => void): () => boolean;
}
function notify(set: Set<() => void>) {
for (const callback of set) callback();
}
export function store<T>(init: T): Store<T> {
let value = init;
const subscribers = new Set<() => void>();
return {
read() {
return value;
},
write(next) {
const current = this.read();
const resolved = next instanceof Function ? next(current) : next;
if (Object.is(current, resolved)) return;
value = resolved;
notify(subscribers);
},
subscribe(callback) {
subscribers.add(callback);
return () => subscribers.delete(callback);
},
};
}
export function useStore<T>(store: Store<T>): T {
return useSyncExternalStore(store.subscribe, store.read, store.read);
}

View File

@@ -0,0 +1,31 @@
"use client";
import { router } from "../client/constants.ts";
export interface LinkProps extends React.ComponentProps<"a"> {
/**
* The URL to navigate to
*/
href: string;
}
export function Link(props: LinkProps): React.JSX.Element {
return (
<a
{...props}
onMouseEnter={e => {
void router.prefetch(props.href).catch(() => {});
if (props.onMouseEnter) props.onMouseEnter(e);
}}
onClick={async e => {
if (props.onClick) {
await (props.onClick(e) as void | Promise<void>);
if (e.defaultPrevented) return;
}
e.preventDefault();
await router.navigate(props.href, undefined);
}}
/>
);
}

View File

@@ -1,18 +1,14 @@
// This file is loaded in the SSR graph, meaning the `react-server` condition is
// no longer set. This means we can import client components, using `react-dom`
// to perform Server-side rendering (creating HTML) out of the RSC payload.
import { ssrManifest } from "bun:bake/server";
import { ssrManifest } from "bun:app/server";
import { EventEmitter } from "node:events";
import type { Readable } from "node:stream";
import * as React from "react";
import type { RenderToPipeableStreamOptions } from "react-dom/server";
import { renderToPipeableStream } from "react-dom/server.node";
import { createFromNodeStream, type Manifest } from "react-server-dom-bun/client.node.unbundled.js";
import type { MiniAbortSignal } from "./server";
// Verify that React 19 is being used.
if (!React.use) {
throw new Error("Bun's React integration requires React 19");
}
import type { MiniAbortSignal } from "./server.tsx";
import { createFromNodeStream, type Manifest } from "./vendor/react-server-dom-bun/client.node.unbundled.js";
const createFromNodeStreamOptions: Manifest = {
moduleMap: ssrManifest,
@@ -34,27 +30,29 @@ const createFromNodeStreamOptions: Manifest = {
// - https://github.com/devongovett/rsc-html-stream
export function renderToHtml(
rscPayload: Readable,
bootstrapModules: readonly string[],
bootstrapModules: string[],
signal: MiniAbortSignal,
): ReadableStream {
// Bun supports a special type of readable stream type called "direct",
// which provides a raw handle to the controller. We can bypass all of
// the Web Streams API (slow) and use the controller directly.
let stream: RscInjectionStream | null = null;
let abort: () => void;
let abort: (reason?: any) => void;
return new ReadableStream({
type: "direct",
pull(controller) {
// `createFromNodeStream` turns the RSC payload into a React component.
const promise = createFromNodeStream(rscPayload, {
// React takes in a manifest mapping client-side assets
// to the imports needed for server-side rendering.
moduleMap: ssrManifest,
moduleLoading: { prefix: "/" },
});
const promise: Promise<React.ReactNode> = createFromNodeStream(rscPayload, createFromNodeStreamOptions);
// The root is this "Root" component that unwraps the streamed promise
// with `use`, and then returning the parsed React component for the UI.
const Root: any = () => React.use(promise);
const Root: React.JSXElementConstructor<{}> = () => React.use(promise);
// If the signal is already aborted, we should not proceed
if (signal.aborted) {
controller.close(signal.aborted);
return Promise.reject(signal.aborted);
}
// If the signal is already aborted, we should not proceed
if (signal.aborted) {
@@ -64,13 +62,20 @@ export function renderToHtml(
// `renderToPipeableStream` is what actually generates HTML.
// Here is where React is told what script tags to inject.
let pipe: (stream: any) => void;
let pipe: (stream: NodeJS.WritableStream) => void;
stream = new RscInjectionStream(rscPayload, controller);
({ pipe, abort } = renderToPipeableStream(<Root />, {
bootstrapModules,
onShellReady() {
// The shell (including <head>) has been fully rendered
stream?.onShellReady();
},
onError(error) {
if (!signal.aborted) {
// Abort the rendering and close the stream
signal.aborted = error;
signal.aborted = error as Error;
abort();
if (signal.abort) signal.abort();
if (stream) {
@@ -80,7 +85,6 @@ export function renderToHtml(
},
}));
stream = new RscInjectionStream(rscPayload, controller);
pipe(stream);
return stream.finished;
@@ -97,16 +101,22 @@ export function renderToHtml(
// Static builds can not stream suspense boundaries as they finish, but instead
// produce a single HTML blob. The approach is otherwise similar to `renderToHtml`.
export function renderToStaticHtml(rscPayload: Readable, bootstrapModules: readonly string[]): Promise<Blob> {
export function renderToStaticHtml(
rscPayload: Readable,
bootstrapModules: NonNullable<RenderToPipeableStreamOptions["bootstrapModules"]>,
): Promise<Blob> {
const stream = new StaticRscInjectionStream(rscPayload);
const promise = createFromNodeStream(rscPayload, createFromNodeStreamOptions);
const Root = () => React.use(promise);
const promise = createFromNodeStream<React.ReactNode>(rscPayload, createFromNodeStreamOptions);
const Root: React.JSXElementConstructor<{}> = () => React.use(promise);
const { pipe } = renderToPipeableStream(<Root />, {
bootstrapModules,
// Only begin flowing HTML once all of it is ready. This tells React
// to not emit the flight chunks, just the entire HTML.
onAllReady: () => pipe(stream),
});
return stream.result;
}
@@ -116,14 +126,14 @@ const continueScriptTag = "<script>__bun_f.push(";
const enum HtmlState {
/** HTML is flowing, it is not an okay time to inject RSC data. */
Flowing,
Flowing = 1,
/** It is safe to inject RSC data. */
Boundary,
}
const enum RscState {
/** No RSC data has been written yet */
Waiting,
Waiting = 1,
/** Some but not all RSC data has been written */
Paused,
/** All RSC data has been written */
@@ -142,11 +152,13 @@ class RscInjectionStream extends EventEmitter {
rscHasEnded = false;
/** Shared state for decoding RSC data into UTF-8 strings */
decoder = new TextDecoder("utf-8", { fatal: true });
/** Track if the shell (including head) has been fully rendered */
shellReady = false;
/** Resolved when all data is written */
finished: Promise<void>;
finalize: () => void;
reject: (err: any) => void;
reject: (err: unknown) => void;
constructor(rscPayload: Readable, controller: ReadableStreamDirectController) {
super();
@@ -154,7 +166,7 @@ class RscInjectionStream extends EventEmitter {
const { resolve, promise, reject } = Promise.withResolvers<void>();
this.finished = promise;
this.finalize = x => (controller.close(), resolve(x));
this.finalize = () => (controller.close(), resolve());
this.reject = reject;
rscPayload.on("data", this.writeRscData.bind(this));
@@ -170,8 +182,12 @@ class RscInjectionStream extends EventEmitter {
});
}
write(data: Uint8Array) {
if (import.meta.env.DEV && process.env.VERBOSE_SSR)
onShellReady() {
this.shellReady = true;
}
write(data: Uint8Array<ArrayBuffer>) {
if (import.meta.env.DEV && process.env.VERBOSE_SSR) {
console.write(
"write" +
Bun.inspect(
@@ -182,6 +198,8 @@ class RscInjectionStream extends EventEmitter {
) +
"\n",
);
}
if (endsWithClosingScript(data)) {
// The HTML is not done yet, but it's a suitible time to inject RSC data.
const { controller } = this;
@@ -256,12 +274,14 @@ class RscInjectionStream extends EventEmitter {
destroy(e) {}
end(e) {}
end() {
return this;
}
}
class StaticRscInjectionStream extends EventEmitter {
rscPayloadChunks: Uint8Array[] = [];
chunks: (Uint8Array | string)[] = [];
rscPayloadChunks: Uint8Array<ArrayBuffer>[] = [];
chunks: (Uint8Array<ArrayBuffer> | string)[] = [];
result: Promise<Blob>;
finalize: (blob: Blob) => void;
reject: (error: Error) => void;
@@ -276,7 +296,7 @@ class StaticRscInjectionStream extends EventEmitter {
rscPayload.on("data", chunk => this.rscPayloadChunks.push(chunk));
}
write(chunk) {
write(chunk: Uint8Array<ArrayBuffer>) {
this.chunks.push(chunk);
}
@@ -285,7 +305,7 @@ class StaticRscInjectionStream extends EventEmitter {
const lastChunk = this.chunks[this.chunks.length - 1];
// Release assertions for React's behavior. If these break there will be malformed HTML.
if (typeof lastChunk === "string") {
if (typeof lastChunk === "string" || !lastChunk) {
this.destroy(new Error("The last chunk was expected to be a Uint8Array"));
return;
}
@@ -305,7 +325,7 @@ class StaticRscInjectionStream extends EventEmitter {
// Ignore flush requests from React.
}
destroy(error) {
destroy(error: Error) {
this.reject(error);
}
}
@@ -336,7 +356,7 @@ function writeManyFlightScriptData(
decoder: TextDecoder,
controller: { write: (str: string) => void },
) {
if (chunks.length === 1) return writeSingleFlightScriptData(chunks[0], decoder, controller);
if (chunks.length === 1) return writeSingleFlightScriptData(chunks[0]!, decoder, controller);
let i = 0;
try {
@@ -355,6 +375,7 @@ function writeManyFlightScriptData(
controller.write('Uint8Array.from(atob("');
for (; i < chunks.length; i++) {
const chunk = chunks[i];
if (!chunk) continue;
const base64 = btoa(String.fromCodePoint(...chunk));
controller.write(base64.slice(1, -1));
}

View File

@@ -0,0 +1,24 @@
{
"compilerOptions": {
"lib": ["ESNext", "DOM"],
"moduleResolution": "NodeNext",
"module": "NodeNext",
"target": "ESNext",
"strict": true,
"noEmit": true,
"useUnknownInCatchVariables": true,
"noImplicitOverride": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true,
"noImplicitReturns": true,
"noUncheckedIndexedAccess": true,
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"isolatedDeclarations": true,
"declaration": true,
"jsx": "react-jsx"
}
}

View File

@@ -0,0 +1 @@
*

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) Meta Platforms, Inc. and affiliates.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,5 @@
# react-server-dom-bun
Experimental React Flight bindings for DOM using Bun.
**Use it at your own risk.**

View File

@@ -0,0 +1 @@
export function createFromReadableStream<T>(readable: ReadableStream<T>): Promise<T>;

View File

@@ -0,0 +1,7 @@
'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react-server-dom-bun-client.browser.production.js');
} else {
module.exports = require('./cjs/react-server-dom-bun-client.browser.development.js');
}

View File

@@ -0,0 +1,3 @@
'use strict';
module.exports = require('./client.browser');

View File

@@ -0,0 +1,7 @@
'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react-server-dom-bun-client.node.production.js');
} else {
module.exports = require('./cjs/react-server-dom-bun-client.node.development.js');
}

View File

@@ -0,0 +1,20 @@
import type { SSRManifest } from "bun:app/server";
import type { Readable } from "node:stream";
export interface Manifest {
moduleMap: SSRManifest;
moduleLoading?: ModuleLoading;
}
export interface ModuleLoading {
prefix: string;
crossOrigin?: string;
}
export interface Options {
encodeFormAction?: any;
findSourceMapURL?: any;
environmentName?: string;
}
export function createFromNodeStream<T = any>(readable: Readable, manifest?: Manifest): Promise<T>;

View File

@@ -0,0 +1,7 @@
'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react-server-dom-bun-client.node.unbundled.production.js');
} else {
module.exports = require('./cjs/react-server-dom-bun-client.node.unbundled.development.js');
}

View File

@@ -0,0 +1,3 @@
{
"type": "module"
}

View File

@@ -0,0 +1,12 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
'use strict';
throw new Error('Use react-server-dom-bun/client instead.');

View File

@@ -0,0 +1,91 @@
{
"name": "react-server-dom-bun",
"description": "React Server Components bindings for DOM using Bun. This is intended to be integrated into meta-frameworks. It is not intended to be imported directly.",
"version": "0.0.0-364a46e8-20250924",
"keywords": [
"react"
],
"homepage": "https://react.dev/",
"bugs": "https://github.com/facebook/react/issues",
"license": "MIT",
"files": [
"LICENSE",
"README.md",
"index.js",
"plugin.js",
"client.js",
"client.browser.js",
"client.node.js",
"client.node.unbundled.js",
"server.js",
"server.browser.js",
"server.node.js",
"server.node.unbundled.js",
"static.js",
"static.browser.js",
"static.node.js",
"static.node.unbundled.js",
"node-register.js",
"cjs/",
"esm/"
],
"exports": {
".": "./index.js",
"./plugin": "./plugin.js",
"./client": {
"node": "./client.node.js",
"browser": "./client.browser.js",
"default": "./client.browser.js"
},
"./client.browser": "./client.browser.js",
"./client.node": "./client.node.js",
"./client.node.unbundled": "./client.node.unbundled.js",
"./server": {
"react-server": {
"deno": "./server.browser.js",
"node": {
"webpack": "./server.node.js",
"default": "./server.node.unbundled.js"
},
"browser": "./server.browser.js"
},
"default": "./server.js"
},
"./server.browser": "./server.browser.js",
"./server.node": "./server.node.js",
"./server.node.unbundled": "./server.node.unbundled.js",
"./static": {
"react-server": {
"deno": "./static.browser.js",
"node": {
"webpack": "./static.node.js",
"default": "./static.node.unbundled.js"
},
"browser": "./static.browser.js"
},
"default": "./static.js"
},
"./static.browser": "./static.browser.js",
"./static.node": "./static.node.js",
"./static.node.unbundled": "./static.node.unbundled.js",
"./node-loader": "./esm/react-server-dom-webpack-node-loader.production.js",
"./node-register": "./node-register.js",
"./package.json": "./package.json"
},
"main": "index.js",
"repository": {
"type": "git",
"url": "https://github.com/facebook/react.git",
"directory": "packages/react-server-dom-bun"
},
"engines": {
"node": ">=0.10.0"
},
"peerDependencies": {
"react": "19.2.0-canary-364a46e8-20250924",
"react-dom": "19.2.0-canary-364a46e8-20250924"
},
"dependencies": {
"neo-async": "^2.6.1"
}
}

View File

@@ -0,0 +1,3 @@
'use strict';
module.exports = require('./cjs/react-server-dom-bun-plugin.js');

View File

@@ -0,0 +1,17 @@
'use strict';
var s;
if (process.env.NODE_ENV === 'production') {
s = require('./cjs/react-server-dom-bun-server.browser.production.js');
} else {
s = require('./cjs/react-server-dom-bun-server.browser.development.js');
}
exports.renderToReadableStream = s.renderToReadableStream;
exports.decodeReply = s.decodeReply;
exports.decodeAction = s.decodeAction;
exports.decodeFormState = s.decodeFormState;
exports.registerServerReference = s.registerServerReference;
exports.registerClientReference = s.registerClientReference;
exports.createClientModuleProxy = s.createClientModuleProxy;
exports.createTemporaryReferenceSet = s.createTemporaryReferenceSet;

View File

@@ -0,0 +1,6 @@
'use strict';
throw new Error(
'The React Server Writer cannot be used outside a react-server environment. ' +
'You must configure Node.js using the `--conditions react-server` flag.'
);

View File

@@ -0,0 +1,20 @@
'use strict';
var s;
if (process.env.NODE_ENV === 'production') {
s = require('./cjs/react-server-dom-bun-server.node.production.js');
} else {
s = require('./cjs/react-server-dom-bun-server.node.development.js');
}
exports.renderToReadableStream = s.renderToReadableStream;
exports.renderToPipeableStream = s.renderToPipeableStream;
exports.decodeReply = s.decodeReply;
exports.decodeReplyFromBusboy = s.decodeReplyFromBusboy;
exports.decodeReplyFromAsyncIterable = s.decodeReplyFromAsyncIterable;
exports.decodeAction = s.decodeAction;
exports.decodeFormState = s.decodeFormState;
exports.registerServerReference = s.registerServerReference;
exports.registerClientReference = s.registerClientReference;
exports.createClientModuleProxy = s.createClientModuleProxy;
exports.createTemporaryReferenceSet = s.createTemporaryReferenceSet;

View File

@@ -0,0 +1,23 @@
import type { ServerManifest } from "bun:app/server";
import type { ReactElement } from "react";
export interface PipeableStream<T> {
/** Returns the input, which should match the Node.js writable interface */
pipe: <T extends NodeJS.WritableStream>(destination: T) => T;
abort: () => void;
}
export function renderToPipeableStream<T = any>(
model: ReactElement,
webpackMap: ServerManifest,
options?: RenderToPipeableStreamOptions,
): PipeableStream<T>;
export interface RenderToPipeableStreamOptions {
onError?: (error: Error) => void;
identifierPrefix?: string;
onPostpone?: () => void;
temporaryReferences?: any;
environmentName?: string;
filterStackFrame?: () => boolean;
}

View File

@@ -0,0 +1,20 @@
'use strict';
var s;
if (process.env.NODE_ENV === 'production') {
s = require('./cjs/react-server-dom-bun-server.node.unbundled.production.js');
} else {
s = require('./cjs/react-server-dom-bun-server.node.unbundled.development.js');
}
exports.renderToReadableStream = s.renderToReadableStream;
exports.renderToPipeableStream = s.renderToPipeableStream;
exports.decodeReply = s.decodeReply;
exports.decodeReplyFromBusboy = s.decodeReplyFromBusboy;
exports.decodeReplyFromAsyncIterable = s.decodeReplyFromAsyncIterable;
exports.decodeAction = s.decodeAction;
exports.decodeFormState = s.decodeFormState;
exports.registerServerReference = s.registerServerReference;
exports.registerClientReference = s.registerClientReference;
exports.createClientModuleProxy = s.createClientModuleProxy;
exports.createTemporaryReferenceSet = s.createTemporaryReferenceSet;

View File

@@ -0,0 +1,12 @@
'use strict';
var s;
if (process.env.NODE_ENV === 'production') {
s = require('./cjs/react-server-dom-bun-server.browser.production.js');
} else {
s = require('./cjs/react-server-dom-bun-server.browser.development.js');
}
if (s.unstable_prerender) {
exports.unstable_prerender = s.unstable_prerender;
}

View File

@@ -0,0 +1,6 @@
'use strict';
throw new Error(
'The React Server Writer cannot be used outside a react-server environment. ' +
'You must configure Node.js using the `--conditions react-server` flag.'
);

View File

@@ -0,0 +1,15 @@
'use strict';
var s;
if (process.env.NODE_ENV === 'production') {
s = require('./cjs/react-server-dom-bun-server.node.production.js');
} else {
s = require('./cjs/react-server-dom-bun-server.node.development.js');
}
if (s.unstable_prerender) {
exports.unstable_prerender = s.unstable_prerender;
}
if (s.unstable_prerenderToNodeStream) {
exports.unstable_prerenderToNodeStream = s.unstable_prerenderToNodeStream;
}

View File

@@ -0,0 +1,12 @@
'use strict';
var s;
if (process.env.NODE_ENV === 'production') {
s = require('./cjs/react-server-dom-bun-server.node.unbundled.production.js');
} else {
s = require('./cjs/react-server-dom-bun-server.node.unbundled.development.js');
}
if (s.unstable_prerenderToNodeStream) {
exports.unstable_prerenderToNodeStream = s.unstable_prerenderToNodeStream;
}

1550
packages/bun-types/app.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -5791,11 +5791,11 @@ declare module "bun" {
* @category Process Management
*
* ```js
* const subprocess = Bun.spawn({
* const proc = Bun.spawn({
* cmd: ["echo", "hello"],
* stdout: "pipe",
* });
* const text = await readableStreamToText(subprocess.stdout);
* const text = await proc.stdout.text();
* console.log(text); // "hello\n"
* ```
*
@@ -5829,8 +5829,8 @@ declare module "bun" {
* Spawn a new process
*
* ```js
* const {stdout} = Bun.spawn(["echo", "hello"]);
* const text = await readableStreamToText(stdout);
* const proc = Bun.spawn(["echo", "hello"]);
* const text = await proc.stdout.text();
* console.log(text); // "hello\n"
* ```
*

View File

@@ -1,278 +0,0 @@
declare module "bun" {
export namespace __experimental {
/**
* Base interface for static site generation route parameters.
*
* Supports both single string values and arrays of strings for dynamic route segments.
* This is typically used for route parameters like `[slug]`, `[...rest]`, or `[id]`.
*
* @warning These APIs are experimental and might be moved/changed in future releases.
*
* @example
* ```tsx
* // Simple slug parameter
* type BlogParams = { slug: string };
*
* // Multiple parameters
* type ProductParams = {
* category: string;
* id: string;
* };
*
* // Catch-all routes with string arrays
* type DocsParams = {
* path: string[];
* };
* ```
*/
export interface SSGParamsLike {
[key: string]: string | string[];
}
/**
* Configuration object for a single static route to be generated.
*
* Each path object contains the parameters needed to render a specific
* instance of a dynamic route at build time.
*
* @warning These APIs are experimental and might be moved/changed in future releases.
*
* @template Params - The shape of route parameters for this path
*
* @example
* ```tsx
* // Single blog post path
* const blogPath: SSGPath<{ slug: string }> = {
* params: { slug: "my-first-post" }
* };
*
* // Product page with multiple params
* const productPath: SSGPath<{ category: string; id: string }> = {
* params: {
* category: "electronics",
* id: "laptop-123"
* }
* };
*
* // Documentation with catch-all route
* const docsPath: SSGPath<{ path: string[] }> = {
* params: { path: ["getting-started", "installation"] }
* };
* ```
*/
export interface SSGPath<Params extends SSGParamsLike = SSGParamsLike> {
params: Params;
}
/**
* Array of static paths to be generated at build time.
*
* This type represents the collection of all route configurations
* that should be pre-rendered for a dynamic route.
*
* @warning These APIs are experimental and might be moved/changed in future releases.
*
* @template Params - The shape of route parameters for these paths
*
* @example
* ```tsx
* // Array of blog post paths
* const blogPaths: SSGPaths<{ slug: string }> = [
* { params: { slug: "introduction-to-bun" } },
* { params: { slug: "performance-benchmarks" } },
* { params: { slug: "getting-started-guide" } }
* ];
*
* // Mixed parameter types
* const productPaths: SSGPaths<{ category: string; id: string }> = [
* { params: { category: "books", id: "javascript-guide" } },
* { params: { category: "electronics", id: "smartphone-x" } }
* ];
* ```
*/
export type SSGPaths<Params extends SSGParamsLike = SSGParamsLike> = SSGPath<Params>[];
/**
* Props interface for SSG page components.
*
* This interface defines the shape of props that will be passed to your
* static page components during the build process. The `params` object
* contains the route parameters extracted from the URL pattern.
*
* @warning These APIs are experimental and might be moved/changed in future releases.
*
* @template Params - The shape of route parameters for this page
*
* @example
* ```tsx
* // Blog post component props
* interface BlogPageProps extends SSGPageProps<{ slug: string }> {
* // params: { slug: string } is automatically included
* }
*
* // Product page component props
* interface ProductPageProps extends SSGPageProps<{
* category: string;
* id: string;
* }> {
* // params: { category: string; id: string } is automatically included
* }
*
* // Usage in component
* function BlogPost({ params }: BlogPageProps) {
* const { slug } = params; // TypeScript knows slug is a string
* return <h1>Blog post: {slug}</h1>;
* }
* ```
*/
export interface SSGPageProps<Params extends SSGParamsLike = SSGParamsLike> {
params: Params;
}
/**
* React component type for SSG pages that can be statically generated.
*
* This type represents a React component that receives SSG page props
* and can be rendered at build time. The component can be either a regular
* React component or an async React Server Component for advanced use cases
* like data fetching during static generation.
*
* @warning These APIs are experimental and might be moved/changed in future releases.
*
* @template Params - The shape of route parameters for this page component
*
* @example
* ```tsx
* // Regular synchronous SSG page component
* const BlogPost: SSGPage<{ slug: string }> = ({ params }) => {
* return (
* <article>
* <h1>Blog Post: {params.slug}</h1>
* <p>This content was generated at build time!</p>
* </article>
* );
* };
*
* // Async React Server Component for data fetching
* const AsyncBlogPost: SSGPage<{ slug: string }> = async ({ params }) => {
* // Fetch data during static generation
* const post = await fetchBlogPost(params.slug);
* const author = await fetchAuthor(post.authorId);
*
* return (
* <article>
* <h1>{post.title}</h1>
* <p>By {author.name}</p>
* <div dangerouslySetInnerHTML={{ __html: post.content }} />
* </article>
* );
* };
*
* // Product page with multiple params and async data fetching
* const ProductPage: SSGPage<{ category: string; id: string }> = async ({ params }) => {
* const [product, reviews] = await Promise.all([
* fetchProduct(params.category, params.id),
* fetchProductReviews(params.id)
* ]);
*
* return (
* <div>
* <h1>{product.name}</h1>
* <p>Category: {params.category}</p>
* <p>Price: ${product.price}</p>
* <div>
* <h2>Reviews ({reviews.length})</h2>
* {reviews.map(review => (
* <div key={review.id}>{review.comment}</div>
* ))}
* </div>
* </div>
* );
* };
* ```
*/
export type SSGPage<Params extends SSGParamsLike = SSGParamsLike> = import("react").ComponentType<
SSGPageProps<Params>
>;
/**
* getStaticPaths is Bun's implementation of SSG (Static Site Generation) path determination.
*
* This function is called at your app's build time to determine which
* dynamic routes should be pre-rendered as static pages. It returns an
* array of path parameters that will be used to generate static pages for
* dynamic routes (e.g., [slug].tsx, [category]/[id].tsx).
*
* The function can be either synchronous or asynchronous, allowing you to
* fetch data from APIs, databases, or file systems to determine which paths
* should be statically generated.
*
* @warning These APIs are experimental and might be moved/changed in future releases.
*
* @template Params - The shape of route parameters for the dynamic route
*
* @returns An object containing an array of paths to be statically generated
*
* @example
* ```tsx
* // In pages/blog/[slug].tsx ———————————————————╮
* export const getStaticPaths: GetStaticPaths<{ slug: string }> = async () => {
* // Fetch all blog posts from your CMS or API at build time
* const posts = await fetchBlogPosts();
*
* return {
* paths: posts.map((post) => ({
* params: { slug: post.slug }
* }))
* };
* };
*
* // In pages/products/[category]/[id].tsx
* export const getStaticPaths: GetStaticPaths<{
* category: string;
* id: string;
* }> = async () => {
* // Fetch products from database
* const products = await db.products.findMany({
* select: { id: true, category: { slug: true } }
* });
*
* return {
* paths: products.map(product => ({
* params: {
* category: product.category.slug,
* id: product.id
* }
* }))
* };
* };
*
* // In pages/docs/[...path].tsx (catch-all route)
* export const getStaticPaths: GetStaticPaths<{ path: string[] }> = async () => {
* // Read documentation structure from file system
* const docPaths = await getDocumentationPaths('./content/docs');
*
* return {
* paths: docPaths.map(docPath => ({
* params: { path: docPath.split('/') }
* }))
* };
* };
*
* // Synchronous example with static data
* export const getStaticPaths: GetStaticPaths<{ id: string }> = () => {
* const staticIds = ['1', '2', '3', '4', '5'];
*
* return {
* paths: staticIds.map(id => ({
* params: { id }
* }))
* };
* };
* ```
*/
export type GetStaticPaths<Params extends SSGParamsLike = SSGParamsLike> = () => MaybePromise<{
paths: SSGPaths<Params>;
}>;
}
}

View File

@@ -20,10 +20,10 @@
/// <reference path="./deprecated.d.ts" />
/// <reference path="./redis.d.ts" />
/// <reference path="./shell.d.ts" />
/// <reference path="./experimental.d.ts" />
/// <reference path="./serve.d.ts" />
/// <reference path="./sql.d.ts" />
/// <reference path="./security.d.ts" />
/// <reference path="./app.d.ts" />
/// <reference path="./bun.ns.d.ts" />

View File

@@ -202,6 +202,16 @@ declare module "bun" {
*/
isSubscribed(topic: string): boolean;
/**
* Returns an array of all topics the client is currently subscribed to.
*
* @example
* ws.subscribe("chat");
* ws.subscribe("notifications");
* console.log(ws.subscriptions); // ["chat", "notifications"]
*/
readonly subscriptions: string[];
/**
* Batches `send()` and `publish()` operations, which makes it faster to send data.
*

View File

@@ -358,6 +358,28 @@ declare module "bun:test" {
fn: (() => void | Promise<unknown>) | ((done: (err?: unknown) => void) => void),
options?: HookOptions,
): void;
/**
* Runs a function after a test finishes, including after all afterEach hooks.
*
* This is useful for cleanup tasks that need to run at the very end of a test,
* after all other hooks have completed.
*
* Can only be called inside a test, not in describe blocks.
*
* @example
* test("my test", () => {
* onTestFinished(() => {
* // This runs after all afterEach hooks
* console.log("Test finished!");
* });
* });
*
* @param fn the function to run
*/
export function onTestFinished(
fn: (() => void | Promise<unknown>) | ((done: (err?: unknown) => void) => void),
options?: HookOptions,
): void;
/**
* Sets the default timeout for all tests in the current file. If a test specifies a timeout, it will
* override this value. The default timeout is 5000ms (5 seconds).

View File

@@ -203,8 +203,6 @@ STACK_OF(X509) *us_get_root_extra_cert_instances() {
}
STACK_OF(X509) *us_get_root_system_cert_instances() {
if (!us_should_use_system_ca())
return NULL;
// Ensure single-path initialization via us_internal_init_root_certs
auto certs = us_get_default_ca_certificates();
return certs->root_system_cert_instances;
@@ -216,13 +214,9 @@ extern "C" X509_STORE *us_get_default_ca_store() {
return NULL;
}
// Only load system default paths when NODE_USE_SYSTEM_CA=1
// Otherwise, rely on bundled certificates only (like Node.js behavior)
if (us_should_use_system_ca()) {
if (!X509_STORE_set_default_paths(store)) {
X509_STORE_free(store);
return NULL;
}
if (!X509_STORE_set_default_paths(store)) {
X509_STORE_free(store);
return NULL;
}
us_default_ca_certificates *default_ca_certificates = us_get_default_ca_certificates();

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