mirror of
https://github.com/oven-sh/bun
synced 2026-02-04 16:08:53 +00:00
Compare commits
4 Commits
ali/react
...
claude/css
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d299786ee1 | ||
|
|
60388f3625 | ||
|
|
a1e904a36a | ||
|
|
cde03cc3e7 |
@@ -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.22" },
|
||||
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.22" },
|
||||
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.22" },
|
||||
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.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: "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.22", tier: "latest" },
|
||||
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.22", tier: "latest" },
|
||||
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.22", tier: "latest" },
|
||||
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.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: "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.22",
|
||||
release: "3.21",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
---
|
||||
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 -->
|
||||
|
||||
---
|
||||
@@ -92,39 +92,7 @@ if (argv0 === "timeout") {
|
||||
|
||||
// Check if it's "bun bd" or "bun-debug bd" without other positional args
|
||||
if (actualCommand === "bun" || actualCommand.includes("bun-debug")) {
|
||||
// Claude is a sneaky fucker
|
||||
let positionalArgs = restArgs.filter(arg => !arg.startsWith("-"));
|
||||
const redirectStderrToStdoutIndex = positionalArgs.findIndex(arg => arg === "2>&1");
|
||||
if (redirectStderrToStdoutIndex !== -1) {
|
||||
positionalArgs.splice(redirectStderrToStdoutIndex, 1);
|
||||
}
|
||||
const redirectStdoutToStderrIndex = positionalArgs.findIndex(arg => arg === "1>&2");
|
||||
if (redirectStdoutToStderrIndex !== -1) {
|
||||
positionalArgs.splice(redirectStdoutToStderrIndex, 1);
|
||||
}
|
||||
|
||||
const redirectToFileIndex = positionalArgs.findIndex(arg => arg === ">");
|
||||
if (redirectToFileIndex !== -1) {
|
||||
positionalArgs.splice(redirectToFileIndex, 2);
|
||||
}
|
||||
|
||||
const redirectToFileAppendIndex = positionalArgs.findIndex(arg => arg === ">>");
|
||||
if (redirectToFileAppendIndex !== -1) {
|
||||
positionalArgs.splice(redirectToFileAppendIndex, 2);
|
||||
}
|
||||
|
||||
const redirectTOFileInlineIndex = positionalArgs.findIndex(arg => arg.startsWith(">"));
|
||||
if (redirectTOFileInlineIndex !== -1) {
|
||||
positionalArgs.splice(redirectTOFileInlineIndex, 1);
|
||||
}
|
||||
|
||||
const pipeIndex = positionalArgs.findIndex(arg => arg === "|");
|
||||
if (pipeIndex !== -1) {
|
||||
positionalArgs = positionalArgs.slice(0, pipeIndex);
|
||||
}
|
||||
|
||||
positionalArgs = positionalArgs.map(arg => arg.trim()).filter(Boolean);
|
||||
|
||||
const positionalArgs = restArgs.filter(arg => !arg.startsWith("-"));
|
||||
if (positionalArgs.length === 1 && positionalArgs[0] === "bd") {
|
||||
denyWithReason("error: Run `bun bd` without a timeout");
|
||||
}
|
||||
|
||||
143
.coderabbit.yaml
143
.coderabbit.yaml
@@ -1,143 +0,0 @@
|
||||
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"
|
||||
@@ -30,7 +30,7 @@ bun bd <file> <...args>
|
||||
Debug logs look like this:
|
||||
|
||||
```zig
|
||||
const log = bun.Output.scoped(.${SCOPE}, .hidden);
|
||||
const log = bun.Output.scoped(.${SCOPE}, false);
|
||||
|
||||
// ...later
|
||||
log("MY DEBUG LOG", .{})
|
||||
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -47,7 +47,6 @@ 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
|
||||
|
||||
29
.github/workflows/auto-close-duplicates.yml
vendored
29
.github/workflows/auto-close-duplicates.yml
vendored
@@ -1,29 +0,0 @@
|
||||
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 }}
|
||||
34
.github/workflows/claude-dedupe-issues.yml
vendored
34
.github/workflows/claude-dedupe-issues.yml
vendored
@@ -1,34 +0,0 @@
|
||||
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 }}
|
||||
3
.github/workflows/claude.yml
vendored
3
.github/workflows/claude.yml
vendored
@@ -57,7 +57,8 @@ jobs:
|
||||
git reset --hard origin/${{ github.event.pull_request.head.ref }}
|
||||
- name: Run Claude Code
|
||||
id: claude
|
||||
uses: anthropics/claude-code-action@v1
|
||||
# TODO: switch this out once they merge their v1
|
||||
uses: km-anthropic/claude-code-action@v1-dev
|
||||
with:
|
||||
timeout_minutes: "180"
|
||||
claude_args: |
|
||||
|
||||
6
.github/workflows/labeled.yml
vendored
6
.github/workflows/labeled.yml
vendored
@@ -142,8 +142,8 @@ jobs:
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const closeAction = ${{ fromJson(steps.add-labels.outputs.close-action) }};
|
||||
|
||||
const closeAction = JSON.parse('${{ steps.add-labels.outputs.close-action }}');
|
||||
|
||||
// Comment with the reason
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
@@ -151,7 +151,7 @@ jobs:
|
||||
issue_number: context.issue.number,
|
||||
body: closeAction.comment
|
||||
});
|
||||
|
||||
|
||||
// Close the issue
|
||||
await github.rest.issues.update({
|
||||
owner: context.repo.owner,
|
||||
|
||||
19
CLAUDE.md
19
CLAUDE.md
@@ -23,15 +23,12 @@ Tip: Bun is already installed and in $PATH. The `bd` subcommand is a package.jso
|
||||
|
||||
### Test Organization
|
||||
|
||||
If a test is for a specific numbered GitHub Issue, it should be placed in `test/regression/issue/${issueNumber}.test.ts`. Ensure the issue number is **REAL** and not a placeholder!
|
||||
|
||||
If no valid issue number is provided, find the best existing file to modify instead, such as;
|
||||
|
||||
- `test/js/bun/` - Bun-specific API tests (http, crypto, ffi, shell, etc.)
|
||||
- `test/js/node/` - Node.js compatibility tests
|
||||
- `test/js/web/` - Web API tests (fetch, WebSocket, streams, etc.)
|
||||
- `test/cli/` - CLI command tests (install, run, test, etc.)
|
||||
- `test/bundler/` - Bundler and transpiler tests. Use `itBundled` helper.
|
||||
- `test/regression/issue/` - Regression tests (create one per bug fix)
|
||||
- `test/bundler/` - Bundler and transpiler tests
|
||||
- `test/integration/` - End-to-end integration tests
|
||||
- `test/napi/` - N-API compatibility tests
|
||||
- `test/v8/` - V8 C++ API compatibility tests
|
||||
@@ -64,21 +61,15 @@ test("my feature", async () => {
|
||||
proc.exited,
|
||||
]);
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
// Prefer snapshot tests over expect(stdout).toBe("hello\n");
|
||||
expect(normalizeBunSnapshot(stdout, dir)).toMatchInlineSnapshot(`"hello"`);
|
||||
|
||||
// Assert the exit code last. This gives you a more useful error message on test failure.
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
```
|
||||
|
||||
- Always use `port: 0`. Do not hardcode ports. Do not use your own random port number function.
|
||||
- Use `normalizeBunSnapshot` to normalize snapshot output of the test.
|
||||
- NEVER write tests that check for no "panic" or "uncaught exception" or similar in the test output. That is NOT a valid test.
|
||||
- Use `tempDir` from `"harness"` to create a temporary directory. **Do not** use `tmpdirSync` or `fs.mkdtempSync` to create temporary directories.
|
||||
- When spawning processes, tests should expect(stdout).toBe(...) BEFORE expect(exitCode).toBe(0). This gives you a more useful error message on test failure.
|
||||
- **CRITICAL**: Do not write flaky tests. Do not use `setTimeout` in tests. Instead, `await` the condition to be met. You are not testing the TIME PASSING, you are testing the CONDITION.
|
||||
- **CRITICAL**: Verify your test fails with `USE_SYSTEM_BUN=1 bun test <file>` and passes with `bun bd test <file>`. Your test is NOT VALID if it passes with `USE_SYSTEM_BUN=1`.
|
||||
|
||||
## Code Architecture
|
||||
|
||||
@@ -87,7 +78,7 @@ test("my feature", async () => {
|
||||
- **Zig code** (`src/*.zig`): Core runtime, JavaScript bindings, package manager
|
||||
- **C++ code** (`src/bun.js/bindings/*.cpp`): JavaScriptCore bindings, Web APIs
|
||||
- **TypeScript** (`src/js/`): Built-in JavaScript modules with special syntax (see JavaScript Modules section)
|
||||
- **Generated code**: Many files are auto-generated from `.classes.ts` and other sources. Bun will automatically rebuild these files when you make changes to them.
|
||||
- **Generated code**: Many files are auto-generated from `.classes.ts` and other sources
|
||||
|
||||
### Core Source Organization
|
||||
|
||||
@@ -187,5 +178,3 @@ Built-in JavaScript modules use special syntax and are organized as:
|
||||
10. **Debug builds** - Use `BUN_DEBUG_QUIET_LOGS=1` to disable debug logging, or `BUN_DEBUG_<scopeName>=1` to enable specific `Output.scoped(.${scopeName}, .visible)`s
|
||||
11. **Be humble & honest** - NEVER overstate what you got done or what actually works in commits, PRs or in messages to the user.
|
||||
12. **Branch names must start with `claude/`** - This is a requirement for the CI to work.
|
||||
|
||||
**ONLY** push up changes after running `bun bd test <file>` and ensuring your tests pass.
|
||||
|
||||
@@ -2,21 +2,7 @@ Configuring a development environment for Bun can take 10-30 minutes depending o
|
||||
|
||||
If you are using Windows, please refer to [this guide](https://bun.com/docs/project/building-windows)
|
||||
|
||||
## Using Nix (Alternative)
|
||||
|
||||
A Nix flake is provided as an alternative to manual dependency installation:
|
||||
|
||||
```bash
|
||||
nix develop
|
||||
# or explicitly use the pure shell
|
||||
# nix develop .#pure
|
||||
export CMAKE_SYSTEM_PROCESSOR=$(uname -m)
|
||||
bun bd
|
||||
```
|
||||
|
||||
This provides all dependencies in an isolated, reproducible environment without requiring sudo.
|
||||
|
||||
## Install Dependencies (Manual)
|
||||
## Install Dependencies
|
||||
|
||||
Using your system's package manager, install Bun's dependencies:
|
||||
|
||||
@@ -163,7 +149,7 @@ Bun generally takes about 2.5 minutes to compile a debug build when there are Zi
|
||||
- Batch up your changes
|
||||
- Ensure zls is running with incremental watching for LSP errors (if you use VSCode and install Zig and run `bun run build` once to download Zig, this should just work)
|
||||
- Prefer using the debugger ("CodeLLDB" in VSCode) to step through the code.
|
||||
- Use debug logs. `BUN_DEBUG_<scope>=1` will enable debug logging for the corresponding `Output.scoped(.<scope>, .hidden)` logs. You can also set `BUN_DEBUG_QUIET_LOGS=1` to disable all debug logging that isn't explicitly enabled. To dump debug lgos into a file, `BUN_DEBUG=<path-to-file>.log`. Debug logs are aggressively removed in release builds.
|
||||
- Use debug logs. `BUN_DEBUG_<scope>=1` will enable debug logging for the corresponding `Output.scoped(.<scope>, false)` logs. You can also set `BUN_DEBUG_QUIET_LOGS=1` to disable all debug logging that isn't explicitly enabled. To dump debug lgos into a file, `BUN_DEBUG=<path-to-file>.log`. Debug logs are aggressively removed in release builds.
|
||||
- src/js/\*\*.ts changes are pretty much instant to rebuild. C++ changes are a bit slower, but still much faster than the Zig code (Zig is one compilation unit, C++ is many).
|
||||
|
||||
## Code generation scripts
|
||||
|
||||
@@ -1,29 +1,40 @@
|
||||
# Create T3 App
|
||||
# `install` benchmark
|
||||
|
||||
This is a [T3 Stack](https://create.t3.gg/) project bootstrapped with `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_.
|
||||
|
||||
## What's next? How do I make an app with this?
|
||||
### With lockfile, online mode
|
||||
|
||||
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.
|
||||
To run the benchmark with the standard "install" command for each package manager:
|
||||
|
||||
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.
|
||||
```sh
|
||||
$ hyperfine --prepare 'rm -rf node_modules' --warmup 1 --runs 3 'bun install' 'pnpm install' 'yarn' 'npm install'
|
||||
```
|
||||
|
||||
- [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)
|
||||
### With lockfile, offline mode
|
||||
|
||||
## Learn More
|
||||
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:
|
||||
|
||||
To learn more about the [T3 Stack](https://create.t3.gg/), take a look at the following resources:
|
||||
```sh
|
||||
$ hyperfine --prepare 'rm -rf node_modules' --runs 1 'bun install' 'pnpm install --prefer-offline' 'yarn --offline' 'npm install --prefer-offline'
|
||||
```
|
||||
|
||||
- [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
|
||||
### Without lockfile, offline mode
|
||||
|
||||
You can check out the [create-t3-app GitHub repository](https://github.com/t3-oss/create-t3-app) — your feedback and contributions are welcome!
|
||||
To run the benchmark with offline mode but without lockfiles:
|
||||
|
||||
## How do I deploy this?
|
||||
```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'
|
||||
```
|
||||
|
||||
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.
|
||||
##
|
||||
|
||||
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).
|
||||
|
||||
18
bench/install/app/entry.client.tsx
Normal file
18
bench/install/app/entry.client.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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>,
|
||||
);
|
||||
});
|
||||
101
bench/install/app/entry.server.tsx
Normal file
101
bench/install/app/entry.server.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 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);
|
||||
});
|
||||
}
|
||||
20
bench/install/app/root.tsx
Normal file
20
bench/install/app/root.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
30
bench/install/app/routes/_index.tsx
Normal file
30
bench/install/app/routes/_index.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -1,488 +0,0 @@
|
||||
{
|
||||
"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
5
bench/install/next-env.d.ts
vendored
@@ -1,5 +0,0 @@
|
||||
/// <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.
|
||||
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
@@ -1,52 +1,31 @@
|
||||
{
|
||||
"name": "installbench",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"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"
|
||||
"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'"
|
||||
},
|
||||
"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"
|
||||
"@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"
|
||||
},
|
||||
"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"
|
||||
"@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"
|
||||
},
|
||||
"ct3aMetadata": {
|
||||
"initVersion": "7.39.3"
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
bench/install/public/favicon.ico
Normal file
BIN
bench/install/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
14
bench/install/remix.config.js
Normal file
14
bench/install/remix.config.js
Normal file
@@ -0,0 +1,14 @@
|
||||
/** @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,
|
||||
},
|
||||
};
|
||||
2
bench/install/remix.env.d.ts
vendored
Normal file
2
bench/install/remix.env.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/// <reference types="@remix-run/dev" />
|
||||
/// <reference types="@remix-run/node" />
|
||||
22
bench/install/tsconfig.json
Normal file
22
bench/install/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
}
|
||||
@@ -4,16 +4,20 @@
|
||||
"": {
|
||||
"name": "react-hello-world",
|
||||
"dependencies": {
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react": "next",
|
||||
"react-dom": "next",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
|
||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||
|
||||
"react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
|
||||
"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=="],
|
||||
|
||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||
"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=="],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,13 @@
|
||||
"description": "",
|
||||
"main": "react-hello-world.node.js",
|
||||
"scripts": {
|
||||
"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"
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Colin McDonnell",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0"
|
||||
"react": "next",
|
||||
"react-dom": "next"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
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
@@ -1,40 +0,0 @@
|
||||
// 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 });
|
||||
},
|
||||
};
|
||||
3
bun.lock
3
bun.lock
@@ -41,7 +41,6 @@
|
||||
},
|
||||
"overrides": {
|
||||
"@types/bun": "workspace:packages/@types/bun",
|
||||
"@types/node": "24.3.1",
|
||||
"bun-types": "workspace:packages/bun-types",
|
||||
},
|
||||
"packages": {
|
||||
@@ -161,7 +160,7 @@
|
||||
|
||||
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||
|
||||
"@types/node": ["@types/node@24.3.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g=="],
|
||||
"@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="],
|
||||
|
||||
"@types/react": ["@types/react@19.1.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="],
|
||||
|
||||
|
||||
@@ -86,20 +86,11 @@ elseif(APPLE)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
# Nix LLVM doesn't support zstd compression, use zlib instead
|
||||
if(DEFINED ENV{NIX_CC})
|
||||
register_compiler_flags(
|
||||
DESCRIPTION "Enable debug symbols (zlib-compressed for Nix)"
|
||||
-g3 -gz=zlib ${DEBUG}
|
||||
-g1 ${RELEASE}
|
||||
)
|
||||
else()
|
||||
register_compiler_flags(
|
||||
DESCRIPTION "Enable debug symbols (zstd-compressed)"
|
||||
-g3 -gz=zstd ${DEBUG}
|
||||
-g1 ${RELEASE}
|
||||
)
|
||||
endif()
|
||||
register_compiler_flags(
|
||||
DESCRIPTION "Enable debug symbols"
|
||||
-g3 -gz=zstd ${DEBUG}
|
||||
-g1 ${RELEASE}
|
||||
)
|
||||
|
||||
register_compiler_flags(
|
||||
DESCRIPTION "Optimize debug symbols for LLDB"
|
||||
@@ -215,6 +206,43 @@ if(ENABLE_ASSERTIONS)
|
||||
DESCRIPTION "Do not eliminate null-pointer checks"
|
||||
-fno-delete-null-pointer-checks
|
||||
)
|
||||
|
||||
register_compiler_definitions(
|
||||
DESCRIPTION "Enable libc++ assertions"
|
||||
_LIBCPP_ENABLE_ASSERTIONS=1
|
||||
_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE ${RELEASE}
|
||||
_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG ${DEBUG}
|
||||
)
|
||||
|
||||
register_compiler_definitions(
|
||||
DESCRIPTION "Enable fortified sources"
|
||||
_FORTIFY_SOURCE=3
|
||||
)
|
||||
|
||||
if(LINUX)
|
||||
register_compiler_definitions(
|
||||
DESCRIPTION "Enable glibc++ assertions"
|
||||
_GLIBCXX_ASSERTIONS=1
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
register_compiler_definitions(
|
||||
DESCRIPTION "Disable debug assertions"
|
||||
NDEBUG=1
|
||||
)
|
||||
|
||||
register_compiler_definitions(
|
||||
DESCRIPTION "Disable libc++ assertions"
|
||||
_LIBCPP_ENABLE_ASSERTIONS=0
|
||||
_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE
|
||||
)
|
||||
|
||||
if(LINUX)
|
||||
register_compiler_definitions(
|
||||
DESCRIPTION "Disable glibc++ assertions"
|
||||
_GLIBCXX_ASSERTIONS=0
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- Diagnostics ---
|
||||
@@ -265,6 +293,14 @@ 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.
|
||||
|
||||
@@ -136,6 +136,13 @@ 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)
|
||||
|
||||
@@ -910,6 +917,10 @@ function(register_compiler_flags)
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
function(register_compiler_definitions)
|
||||
|
||||
endfunction()
|
||||
|
||||
# register_linker_flags()
|
||||
# Description:
|
||||
# Registers a linker flag, similar to `add_link_options()`.
|
||||
|
||||
@@ -140,6 +140,11 @@ 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()
|
||||
|
||||
@@ -27,10 +27,6 @@
|
||||
"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"]
|
||||
|
||||
33
cmake/analysis/RunCppCheck.cmake
Normal file
33
cmake/analysis/RunCppCheck.cmake
Normal file
@@ -0,0 +1,33 @@
|
||||
# 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}
|
||||
)
|
||||
22
cmake/analysis/RunCppLint.cmake
Normal file
22
cmake/analysis/RunCppLint.cmake
Normal file
@@ -0,0 +1,22 @@
|
||||
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}
|
||||
)
|
||||
67
cmake/analysis/RunIWYU.cmake
Normal file
67
cmake/analysis/RunIWYU.cmake
Normal file
@@ -0,0 +1,67 @@
|
||||
# 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}
|
||||
)
|
||||
@@ -45,6 +45,12 @@ 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 ---
|
||||
|
||||
@@ -65,6 +71,9 @@ set(BUN_DEPENDENCIES
|
||||
)
|
||||
|
||||
include(CloneZstd)
|
||||
# foreach(dependency ${BUN_DEPENDENCIES})
|
||||
# include(Clone${dependency})
|
||||
# endforeach()
|
||||
|
||||
# --- Codegen ---
|
||||
|
||||
@@ -810,7 +819,7 @@ set_target_properties(${bun} PROPERTIES
|
||||
CXX_STANDARD_REQUIRED YES
|
||||
CXX_EXTENSIONS YES
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
C_STANDARD 17 # Cannot uprev to C23 because MSVC doesn't have support.
|
||||
C_STANDARD 17
|
||||
C_STANDARD_REQUIRED YES
|
||||
VISIBILITY_INLINES_HIDDEN YES
|
||||
)
|
||||
@@ -935,7 +944,7 @@ if(NOT WIN32)
|
||||
if (NOT ABI STREQUAL "musl")
|
||||
target_compile_options(${bun} PUBLIC
|
||||
-fsanitize=null
|
||||
-fno-sanitize-recover=all
|
||||
-fsanitize-recover=all
|
||||
-fsanitize=bounds
|
||||
-fsanitize=return
|
||||
-fsanitize=nullability-arg
|
||||
@@ -990,20 +999,6 @@ 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()
|
||||
@@ -1050,6 +1045,7 @@ if(APPLE)
|
||||
-Wl,-no_compact_unwind
|
||||
-Wl,-stack_size,0x1200000
|
||||
-fno-keep-static-consts
|
||||
-Wl,-map,${bun}.linker-map
|
||||
)
|
||||
|
||||
if(DEBUG)
|
||||
@@ -1069,7 +1065,6 @@ if(APPLE)
|
||||
target_link_options(${bun} PUBLIC
|
||||
-dead_strip
|
||||
-dead_strip_dylibs
|
||||
-Wl,-map,${bun}.linker-map
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
@@ -1103,17 +1098,6 @@ if(LINUX)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (ENABLE_LTO)
|
||||
# We are optimizing for size at a slight debug-ability cost
|
||||
target_link_options(${bun} PUBLIC
|
||||
-Wl,--no-eh-frame-hdr
|
||||
)
|
||||
else()
|
||||
target_link_options(${bun} PUBLIC
|
||||
-Wl,--eh-frame-hdr
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_options(${bun} PUBLIC
|
||||
--ld-path=${LLD_PROGRAM}
|
||||
-fno-pic
|
||||
@@ -1128,9 +1112,11 @@ if(LINUX)
|
||||
# make debug info faster to load
|
||||
-Wl,--gdb-index
|
||||
-Wl,-z,combreloc
|
||||
-Wl,--no-eh-frame-hdr
|
||||
-Wl,--sort-section=name
|
||||
-Wl,--hash-style=both
|
||||
-Wl,--build-id=sha1 # Better for debugging than default
|
||||
-Wl,-Map=${bun}.linker-map
|
||||
)
|
||||
|
||||
# don't strip in debug, this seems to be needed so that the Zig std library
|
||||
@@ -1145,7 +1131,6 @@ if(LINUX)
|
||||
if (NOT DEBUG AND NOT ENABLE_ASAN AND NOT ENABLE_VALGRIND)
|
||||
target_link_options(${bun} PUBLIC
|
||||
-Wl,-icf=safe
|
||||
-Wl,-Map=${bun}.linker-map
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -1252,9 +1237,15 @@ if(LINUX)
|
||||
target_link_libraries(${bun} PUBLIC libatomic.so)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicudata.a)
|
||||
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicui18n.a)
|
||||
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicuuc.a)
|
||||
if(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()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
@@ -1307,32 +1298,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
|
||||
@@ -1461,7 +1452,7 @@ if(NOT BUN_CPP_ONLY)
|
||||
list(APPEND bunFiles ${bun}.dSYM)
|
||||
endif()
|
||||
|
||||
if((APPLE OR LINUX) AND NOT ENABLE_ASAN)
|
||||
if(APPLE OR LINUX)
|
||||
list(APPEND bunFiles ${bun}.linker-map)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ register_repository(
|
||||
REPOSITORY
|
||||
google/highway
|
||||
COMMIT
|
||||
ac0d5d297b13ab1b89f48484fc7911082d76a93f
|
||||
12b325bc1793dee68ab2157995a690db859fe9e0
|
||||
)
|
||||
|
||||
set(HIGHWAY_CMAKE_ARGS
|
||||
|
||||
@@ -4,7 +4,7 @@ register_repository(
|
||||
REPOSITORY
|
||||
ebiggers/libdeflate
|
||||
COMMIT
|
||||
c8c56a20f8f621e6a966b716b31f1dedab6a41e3
|
||||
96836d7d9d10e3e0d53e6edb54eb908514e336c4
|
||||
)
|
||||
|
||||
register_cmake_command(
|
||||
|
||||
@@ -4,8 +4,8 @@ register_repository(
|
||||
REPOSITORY
|
||||
libuv/libuv
|
||||
COMMIT
|
||||
# Latest HEAD (includes recursion bug fix #4784)
|
||||
f3ce527ea940d926c40878ba5de219640c362811
|
||||
# Corresponds to v1.51.0
|
||||
5152db2cbfeb5582e9c27c5ea1dba2cd9e10759b
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.22 AS build
|
||||
FROM alpine:3.20 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.22
|
||||
FROM alpine:3.20
|
||||
|
||||
# Disable the runtime transpiler cache by default inside Docker containers.
|
||||
# On ephemeral containers, the cache is not useful
|
||||
|
||||
@@ -536,7 +536,7 @@ You can also access the `Server` object from the `fetch` handler. It's the secon
|
||||
const server = Bun.serve({
|
||||
fetch(req, server) {
|
||||
const ip = server.requestIP(req);
|
||||
return new Response(`Your IP is ${ip.address}`);
|
||||
return new Response(`Your IP is ${ip}`);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
@@ -42,7 +42,6 @@ await client.incr("counter");
|
||||
By default, the client reads connection information from the following environment variables (in order of precedence):
|
||||
|
||||
- `REDIS_URL`
|
||||
- `VALKEY_URL`
|
||||
- If not set, defaults to `"redis://localhost:6379"`
|
||||
|
||||
### Connection Lifecycle
|
||||
|
||||
@@ -107,8 +107,6 @@ Bun.serve({
|
||||
|
||||
Contextual `data` can be attached to a new WebSocket in the `.upgrade()` call. This data is made available on the `ws.data` property inside the WebSocket handlers.
|
||||
|
||||
To strongly type `ws.data`, add a `data` property to the `websocket` handler object. This types `ws.data` across all lifecycle hooks.
|
||||
|
||||
```ts
|
||||
type WebSocketData = {
|
||||
createdAt: number;
|
||||
@@ -150,10 +148,6 @@ Bun.serve({
|
||||
});
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Note:** Previously, you could specify the type of `ws.data` using a type parameter on `Bun.serve`, like `Bun.serve<MyData>({...})`. This pattern was removed due to [a limitation in TypeScript](https://github.com/microsoft/TypeScript/issues/26242) in favor of the `data` property shown above.
|
||||
{% /callout %}
|
||||
|
||||
To connect to this server from the browser, create a new `WebSocket`.
|
||||
|
||||
```ts#browser.js
|
||||
|
||||
@@ -586,41 +586,12 @@ Codesign support requires Bun v1.2.4 or newer.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
## Code splitting
|
||||
|
||||
Standalone executables support code splitting. Use `--compile` with `--splitting` to create an executable that loads code-split chunks at runtime.
|
||||
|
||||
```bash
|
||||
$ bun build --compile --splitting ./src/entry.ts --outdir ./build
|
||||
```
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#src/entry.ts
|
||||
console.log("Entrypoint loaded");
|
||||
const lazy = await import("./lazy.ts");
|
||||
lazy.hello();
|
||||
```
|
||||
|
||||
```ts#src/lazy.ts
|
||||
export function hello() {
|
||||
console.log("Lazy module loaded");
|
||||
}
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
```bash
|
||||
$ ./build/entry
|
||||
Entrypoint loaded
|
||||
Lazy module loaded
|
||||
```
|
||||
|
||||
## Unsupported CLI arguments
|
||||
|
||||
Currently, the `--compile` flag can only accept a single entrypoint at a time and does not support the following flags:
|
||||
|
||||
- `--outdir` — use `outfile` instead (except when using with `--splitting`).
|
||||
- `--outdir` — use `outfile` instead.
|
||||
- `--splitting`
|
||||
- `--public-path`
|
||||
- `--target=node` or `--target=browser`
|
||||
- `--no-bundle` - we always bundle everything into the executable.
|
||||
|
||||
@@ -1600,7 +1600,7 @@ interface BuildConfig {
|
||||
publicPath?: string;
|
||||
define?: Record<string, string>;
|
||||
loader?: { [k in string]: Loader };
|
||||
sourcemap?: "none" | "linked" | "inline" | "external" | boolean; // default: "none", true -> "inline"
|
||||
sourcemap?: "none" | "linked" | "inline" | "external" | "linked" | boolean; // default: "none", true -> "inline"
|
||||
/**
|
||||
* package.json `exports` conditions used when resolving imports
|
||||
*
|
||||
|
||||
@@ -2,29 +2,20 @@ Scaffold an empty Bun project with the interactive `bun init` command.
|
||||
|
||||
```bash
|
||||
$ bun init
|
||||
bun init helps you get started with a minimal project and tries to
|
||||
guess sensible defaults. Press ^C anytime to quit.
|
||||
|
||||
? Select a project template - Press return to submit.
|
||||
❯ Blank
|
||||
React
|
||||
Library
|
||||
package name (quickstart):
|
||||
entry point (index.ts):
|
||||
|
||||
✓ Select a project template: Blank
|
||||
|
||||
+ .gitignore
|
||||
+ index.ts
|
||||
+ tsconfig.json (for editor autocomplete)
|
||||
+ README.md
|
||||
Done! A package.json file was saved in the current directory.
|
||||
+ index.ts
|
||||
+ .gitignore
|
||||
+ tsconfig.json (for editor auto-complete)
|
||||
+ README.md
|
||||
|
||||
To get started, run:
|
||||
|
||||
bun run index.ts
|
||||
|
||||
bun install v$BUN_LATEST_VERSION
|
||||
|
||||
+ @types/bun@$BUN_LATEST_VERSION
|
||||
+ typescript@5.9.2
|
||||
|
||||
7 packages installed
|
||||
bun run index.ts
|
||||
```
|
||||
|
||||
Press `enter` to accept the default answer for each prompt, or pass the `-y` flag to auto-accept the defaults.
|
||||
|
||||
@@ -84,12 +84,14 @@ $ bun publish --dry-run
|
||||
|
||||
### `--tolerate-republish`
|
||||
|
||||
Exit with code 0 instead of 1 if the package version already exists. Useful in CI/CD where jobs may be re-run.
|
||||
The `--tolerate-republish` flag makes `bun publish` exit with code 0 instead of code 1 when attempting to republish over an existing version number. This is useful in automated workflows where republishing the same version might occur and should not be treated as an error.
|
||||
|
||||
```sh
|
||||
$ bun publish --tolerate-republish
|
||||
```
|
||||
|
||||
Without this flag, attempting to publish a version that already exists will result in an error and exit code 1. With this flag, the command will exit successfully even when trying to republish an existing version.
|
||||
|
||||
### `--gzip-level`
|
||||
|
||||
Specify the level of gzip compression to use when packing the package. Only applies to `bun publish` without a tarball path argument. Values range from `0` to `9` (default is `9`).
|
||||
|
||||
@@ -257,13 +257,12 @@ $ 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. |
|
||||
| `onTestFinished` | Runs after a test finishes, including after `afterEach`. |
|
||||
| Hook | Description |
|
||||
| ------------ | --------------------------- |
|
||||
| `beforeAll` | Runs once before all tests. |
|
||||
| `beforeEach` | Runs before each test. |
|
||||
| `afterEach` | Runs after each test. |
|
||||
| `afterAll` | Runs once after all tests. |
|
||||
|
||||
These hooks can be defined inside test files, or in a separate file that is preloaded with the `--preload` flag.
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ import { watch } from "fs";
|
||||
const watcher = watch(
|
||||
import.meta.dir,
|
||||
{ recursive: true },
|
||||
(event, relativePath) => {
|
||||
console.log(`Detected ${event} in ${relativePath}`);
|
||||
(event, filename) => {
|
||||
console.log(`Detected ${event} in ${filename}`);
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
@@ -89,12 +89,6 @@ $ bun install --linker isolated
|
||||
|
||||
Isolated installs create strict dependency isolation similar to pnpm, preventing phantom dependencies and ensuring more deterministic builds. For complete documentation, see [Isolated installs](https://bun.com/docs/install/isolated).
|
||||
|
||||
To protect against supply chain attacks, set a minimum age (in seconds) for package versions:
|
||||
|
||||
```bash
|
||||
$ bun install --minimum-release-age 259200 # 3 days
|
||||
```
|
||||
|
||||
{% details summary="Configuring behavior" %}
|
||||
The default behavior of `bun install` can be configured in `bunfig.toml`:
|
||||
|
||||
@@ -128,12 +122,6 @@ concurrentScripts = 16 # (cpu count or GOMAXPROCS) x2
|
||||
# installation strategy: "hoisted" or "isolated"
|
||||
# default: "hoisted"
|
||||
linker = "hoisted"
|
||||
|
||||
# minimum package age in seconds (protects against supply chain attacks)
|
||||
minimumReleaseAge = 259200 # 3 days
|
||||
|
||||
# exclude packages from age requirement
|
||||
minimumReleaseAgeExcludes = ["@types/node", "typescript"]
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
|
||||
@@ -36,10 +36,7 @@ linker = "isolated"
|
||||
|
||||
### Default behavior
|
||||
|
||||
- **Workspaces**: Bun uses **isolated** installs by default to prevent hoisting-related bugs
|
||||
- **Single projects**: Bun uses **hoisted** installs by default
|
||||
|
||||
To override the default, use `--linker hoisted` or `--linker isolated`, or set it in your configuration file.
|
||||
By default, Bun uses the **hoisted** installation strategy for all projects. To use isolated installs, you must explicitly specify the `--linker isolated` flag or set it in your configuration file.
|
||||
|
||||
## How isolated installs work
|
||||
|
||||
@@ -177,13 +174,14 @@ The main difference is that Bun uses symlinks in `node_modules` while pnpm uses
|
||||
|
||||
## When to use isolated installs
|
||||
|
||||
**Isolated installs are the default for workspaces.** You may want to explicitly enable them for single projects when:
|
||||
**Use isolated installs when:**
|
||||
|
||||
- Working in monorepos with multiple packages
|
||||
- Strict dependency management is required
|
||||
- Preventing phantom dependencies is important
|
||||
- Building libraries that need deterministic dependencies
|
||||
|
||||
**Switch to hoisted installs (including for workspaces) when:**
|
||||
**Use hoisted installs when:**
|
||||
|
||||
- Working with legacy code that assumes flat `node_modules`
|
||||
- Compatibility with existing build tools is required
|
||||
|
||||
@@ -38,21 +38,9 @@ In the root `package.json`, the `"workspaces"` key is used to indicate which sub
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Glob support** — Bun supports full glob syntax in `"workspaces"`, including negative patterns (e.g. `!**/excluded/**`). See [here](https://bun.com/docs/api/glob#supported-glob-patterns) for a comprehensive list of supported syntax.
|
||||
**Glob support** — Bun supports full glob syntax in `"workspaces"` (see [here](https://bun.com/docs/api/glob#supported-glob-patterns) for a comprehensive list of supported syntax), _except_ for exclusions (e.g. `!**/excluded/**`), which are not implemented yet.
|
||||
{% /callout %}
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-project",
|
||||
"version": "1.0.0",
|
||||
"workspaces": [
|
||||
"packages/**",
|
||||
"!packages/**/test/**",
|
||||
"!packages/**/template/**"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Each workspace has it's own `package.json`. When referencing other packages in the monorepo, semver or workspace protocols (e.g. `workspace:*`) can be used as the version field in your `package.json`.
|
||||
|
||||
```json
|
||||
|
||||
@@ -9,29 +9,20 @@ Run `bun init` to scaffold a new project. It's an interactive tool; for this tut
|
||||
|
||||
```bash
|
||||
$ bun init
|
||||
bun init helps you get started with a minimal project and tries to
|
||||
guess sensible defaults. Press ^C anytime to quit.
|
||||
|
||||
? Select a project template - Press return to submit.
|
||||
❯ Blank
|
||||
React
|
||||
Library
|
||||
package name (quickstart):
|
||||
entry point (index.ts):
|
||||
|
||||
✓ Select a project template: Blank
|
||||
|
||||
+ .gitignore
|
||||
+ index.ts
|
||||
+ tsconfig.json (for editor autocomplete)
|
||||
+ README.md
|
||||
Done! A package.json file was saved in the current directory.
|
||||
+ index.ts
|
||||
+ .gitignore
|
||||
+ tsconfig.json (for editor auto-complete)
|
||||
+ README.md
|
||||
|
||||
To get started, run:
|
||||
|
||||
bun run index.ts
|
||||
|
||||
bun install v$BUN_LATEST_VERSION
|
||||
|
||||
+ @types/bun@$BUN_LATEST_VERSION
|
||||
+ typescript@5.9.2
|
||||
|
||||
7 packages installed
|
||||
bun run index.ts
|
||||
```
|
||||
|
||||
Since our entry point is a `*.ts` file, Bun generates a `tsconfig.json` for you. If you're using plain JavaScript, it will generate a [`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig) instead.
|
||||
@@ -97,15 +88,11 @@ Bun can also execute `"scripts"` from your `package.json`. Add the following scr
|
||||
"name": "quickstart",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
+ "scripts": {
|
||||
+ "start": "bun run index.ts"
|
||||
+ },
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -249,81 +249,6 @@ 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`.
|
||||
|
||||
```toml
|
||||
[test]
|
||||
randomize = true
|
||||
```
|
||||
|
||||
This helps catch bugs related to test interdependencies by running tests in a different order each time. When combined with `seed`, the random order becomes reproducible.
|
||||
|
||||
The `--randomize` CLI flag will override this setting when specified.
|
||||
|
||||
### `test.seed`
|
||||
|
||||
Set the random seed for test randomization. This option requires `randomize` to be `true`.
|
||||
|
||||
```toml
|
||||
[test]
|
||||
randomize = true
|
||||
seed = 2444615283
|
||||
```
|
||||
|
||||
Using a seed makes the randomized test order reproducible across runs, which is useful for debugging flaky tests. When you encounter a test failure with randomization enabled, you can use the same seed to reproduce the exact test order.
|
||||
|
||||
The `--seed` CLI flag will override this setting when specified.
|
||||
|
||||
### `test.rerunEach`
|
||||
|
||||
Re-run each test file a specified number of times. Default `0` (run once).
|
||||
|
||||
```toml
|
||||
[test]
|
||||
rerunEach = 3
|
||||
```
|
||||
|
||||
This is useful for catching flaky tests or non-deterministic behavior. Each test file will be executed the specified number of times.
|
||||
|
||||
The `--rerun-each` CLI flag will override this setting when specified.
|
||||
|
||||
## Package manager
|
||||
|
||||
Package management is a complex issue; to support a range of use cases, the behavior of `bun install` can be configured under the `[install]` section.
|
||||
@@ -686,7 +611,7 @@ editor = "code"
|
||||
|
||||
The `bun run` command can be configured under the `[run]` section. These apply to the `bun run` command and the `bun` command when running a file or executable or script.
|
||||
|
||||
Currently, `bunfig.toml` is only automatically loaded for `bun run` in a local project (it doesn't check for a global `.bunfig.toml`).
|
||||
Currently, `bunfig.toml` isn't always automatically loaded for `bun run` in a local project (it does check for a global `bunfig.toml`), so you might still need to pass `-c` or `-c=bunfig.toml` to use these settings.
|
||||
|
||||
### `run.shell` - use the system shell or Bun's shell
|
||||
|
||||
|
||||
@@ -174,29 +174,6 @@ import { stuff } from "foo";
|
||||
|
||||
The full specification of this algorithm are officially documented in the [Node.js documentation](https://nodejs.org/api/modules.html); we won't rehash it here. Briefly: if you import `from "foo"`, Bun scans up the file system for a `node_modules` directory containing the package `foo`.
|
||||
|
||||
### NODE_PATH
|
||||
|
||||
Bun supports `NODE_PATH` for additional module resolution directories:
|
||||
|
||||
```bash
|
||||
NODE_PATH=./packages bun run src/index.js
|
||||
```
|
||||
|
||||
```ts
|
||||
// packages/foo/index.js
|
||||
export const hello = "world";
|
||||
|
||||
// src/index.js
|
||||
import { hello } from "foo";
|
||||
```
|
||||
|
||||
Multiple paths use the platform's delimiter (`:` on Unix, `;` on Windows):
|
||||
|
||||
```bash
|
||||
NODE_PATH=./packages:./lib bun run src/index.js # Unix/macOS
|
||||
NODE_PATH=./packages;./lib bun run src/index.js # Windows
|
||||
```
|
||||
|
||||
Once it finds the `foo` package, Bun reads the `package.json` to determine how the package should be imported. To determine the package's entrypoint, Bun first reads the `exports` field and checks for the following conditions.
|
||||
|
||||
```jsonc#package.json
|
||||
|
||||
@@ -65,34 +65,6 @@ Test files matching this pattern will behave as if the `--concurrent` flag was p
|
||||
|
||||
The `--concurrent` CLI flag will override this setting when specified, forcing all tests to run concurrently regardless of the glob pattern.
|
||||
|
||||
#### randomize
|
||||
|
||||
Run tests in random order to identify tests with hidden dependencies:
|
||||
|
||||
```toml
|
||||
[test]
|
||||
randomize = true
|
||||
```
|
||||
|
||||
#### seed
|
||||
|
||||
Specify a seed for reproducible random test order. Requires `randomize = true`:
|
||||
|
||||
```toml
|
||||
[test]
|
||||
randomize = true
|
||||
seed = 2444615283
|
||||
```
|
||||
|
||||
#### rerunEach
|
||||
|
||||
Re-run each test file multiple times to identify flaky tests:
|
||||
|
||||
```toml
|
||||
[test]
|
||||
rerunEach = 3
|
||||
```
|
||||
|
||||
### Coverage options
|
||||
|
||||
In addition to the options documented in the [coverage documentation](./coverage.md), the following options are available:
|
||||
|
||||
@@ -34,15 +34,6 @@ test/package-json-lint.test.ts:
|
||||
Ran 4 tests across 1 files. [0.66ms]
|
||||
```
|
||||
|
||||
### Dots Reporter
|
||||
|
||||
The dots reporter shows `.` for passing tests and `F` for failures—useful for large test suites.
|
||||
|
||||
```sh
|
||||
$ bun test --dots
|
||||
$ bun test --reporter=dots
|
||||
```
|
||||
|
||||
### JUnit XML Reporter
|
||||
|
||||
For CI/CD environments, Bun supports generating JUnit XML reports. JUnit XML is a widely-adopted format for test results that can be parsed by many CI/CD systems, including GitLab, Jenkins, and others.
|
||||
|
||||
61
flake.lock
generated
61
flake.lock
generated
@@ -1,61 +0,0 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1759831965,
|
||||
"narHash": "sha256-vgPm2xjOmKdZ0xKA6yLXPJpjOtQPHfaZDRtH+47XEBo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c9b6fb798541223bbb396d287d16f43520250518",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
175
flake.nix
175
flake.nix
@@ -1,175 +0,0 @@
|
||||
{
|
||||
description = "Bun - A fast all-in-one JavaScript runtime";
|
||||
|
||||
# Uncomment this when you set up Cachix to enable automatic binary cache
|
||||
# nixConfig = {
|
||||
# extra-substituters = [
|
||||
# "https://bun-dev.cachix.org"
|
||||
# ];
|
||||
# extra-trusted-public-keys = [
|
||||
# "bun-dev.cachix.org-1:REPLACE_WITH_YOUR_PUBLIC_KEY"
|
||||
# ];
|
||||
# };
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
config = {
|
||||
allowUnfree = true;
|
||||
};
|
||||
};
|
||||
|
||||
# LLVM 19 - matching the bootstrap script (targets 19.1.7, actual version from nixpkgs-unstable)
|
||||
llvm = pkgs.llvm_19;
|
||||
clang = pkgs.clang_19;
|
||||
lld = pkgs.lld_19;
|
||||
|
||||
# Node.js 24 - matching the bootstrap script (targets 24.3.0, actual version from nixpkgs-unstable)
|
||||
nodejs = pkgs.nodejs_24;
|
||||
|
||||
# Build tools and dependencies
|
||||
packages = [
|
||||
# Core build tools
|
||||
pkgs.cmake # Expected: 3.30+ on nixos-unstable as of 2025-10
|
||||
pkgs.ninja
|
||||
pkgs.pkg-config
|
||||
pkgs.ccache
|
||||
|
||||
# Compilers and toolchain - version pinned to LLVM 19
|
||||
clang
|
||||
llvm
|
||||
lld
|
||||
pkgs.gcc
|
||||
pkgs.rustc
|
||||
pkgs.cargo
|
||||
pkgs.go
|
||||
|
||||
# Bun itself (for running build scripts via `bun bd`)
|
||||
pkgs.bun
|
||||
|
||||
# Node.js - version pinned to 24
|
||||
nodejs
|
||||
|
||||
# Python for build scripts
|
||||
pkgs.python3
|
||||
|
||||
# Other build dependencies from bootstrap.sh
|
||||
pkgs.libtool
|
||||
pkgs.ruby
|
||||
pkgs.perl
|
||||
|
||||
# Libraries
|
||||
pkgs.openssl
|
||||
pkgs.zlib
|
||||
pkgs.libxml2
|
||||
pkgs.libiconv
|
||||
|
||||
# Development tools
|
||||
pkgs.git
|
||||
pkgs.curl
|
||||
pkgs.wget
|
||||
pkgs.unzip
|
||||
pkgs.xz
|
||||
|
||||
# Additional dependencies for Linux
|
||||
] ++ pkgs.lib.optionals pkgs.stdenv.isLinux [
|
||||
pkgs.gdb # for debugging core dumps (from bootstrap.sh line 1535)
|
||||
|
||||
# Chromium dependencies for Puppeteer testing (from bootstrap.sh lines 1397-1483)
|
||||
# X11 and graphics libraries
|
||||
pkgs.xorg.libX11
|
||||
pkgs.xorg.libxcb
|
||||
pkgs.xorg.libXcomposite
|
||||
pkgs.xorg.libXcursor
|
||||
pkgs.xorg.libXdamage
|
||||
pkgs.xorg.libXext
|
||||
pkgs.xorg.libXfixes
|
||||
pkgs.xorg.libXi
|
||||
pkgs.xorg.libXrandr
|
||||
pkgs.xorg.libXrender
|
||||
pkgs.xorg.libXScrnSaver
|
||||
pkgs.xorg.libXtst
|
||||
pkgs.libxkbcommon
|
||||
pkgs.mesa
|
||||
pkgs.nspr
|
||||
pkgs.nss
|
||||
pkgs.cups
|
||||
pkgs.dbus
|
||||
pkgs.expat
|
||||
pkgs.fontconfig
|
||||
pkgs.freetype
|
||||
pkgs.glib
|
||||
pkgs.gtk3
|
||||
pkgs.pango
|
||||
pkgs.cairo
|
||||
pkgs.alsa-lib
|
||||
pkgs.at-spi2-atk
|
||||
pkgs.at-spi2-core
|
||||
pkgs.libgbm # for hardware acceleration
|
||||
pkgs.liberation_ttf # fonts-liberation
|
||||
pkgs.atk
|
||||
pkgs.libdrm
|
||||
pkgs.xorg.libxshmfence
|
||||
pkgs.gdk-pixbuf
|
||||
] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [
|
||||
# macOS specific dependencies
|
||||
pkgs.darwin.apple_sdk.frameworks.CoreFoundation
|
||||
pkgs.darwin.apple_sdk.frameworks.CoreServices
|
||||
pkgs.darwin.apple_sdk.frameworks.Security
|
||||
];
|
||||
|
||||
in
|
||||
{
|
||||
devShells.default = (pkgs.mkShell.override {
|
||||
stdenv = pkgs.clangStdenv;
|
||||
}) {
|
||||
inherit packages;
|
||||
|
||||
shellHook = ''
|
||||
# Set up build environment
|
||||
export CC="${pkgs.lib.getExe clang}"
|
||||
export CXX="${pkgs.lib.getExe' clang "clang++"}"
|
||||
export AR="${llvm}/bin/llvm-ar"
|
||||
export RANLIB="${llvm}/bin/llvm-ranlib"
|
||||
export CMAKE_C_COMPILER="$CC"
|
||||
export CMAKE_CXX_COMPILER="$CXX"
|
||||
export CMAKE_AR="$AR"
|
||||
export CMAKE_RANLIB="$RANLIB"
|
||||
export CMAKE_SYSTEM_PROCESSOR="$(uname -m)"
|
||||
export TMPDIR="''${TMPDIR:-/tmp}"
|
||||
'' + pkgs.lib.optionalString pkgs.stdenv.isLinux ''
|
||||
export LD="${pkgs.lib.getExe' lld "ld.lld"}"
|
||||
export NIX_CFLAGS_LINK="''${NIX_CFLAGS_LINK:+$NIX_CFLAGS_LINK }-fuse-ld=lld"
|
||||
export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath packages}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
'' + ''
|
||||
|
||||
# Print welcome message
|
||||
echo "====================================="
|
||||
echo "Bun Development Environment"
|
||||
echo "====================================="
|
||||
echo "Node.js: $(node --version 2>/dev/null || echo 'not found')"
|
||||
echo "Bun: $(bun --version 2>/dev/null || echo 'not found')"
|
||||
echo "Clang: $(clang --version 2>/dev/null | head -n1 || echo 'not found')"
|
||||
echo "CMake: $(cmake --version 2>/dev/null | head -n1 || echo 'not found')"
|
||||
echo "LLVM: ${llvm.version}"
|
||||
echo ""
|
||||
echo "Quick start:"
|
||||
echo " bun bd # Build debug binary"
|
||||
echo " bun bd test <test-file> # Run tests"
|
||||
echo "====================================="
|
||||
'';
|
||||
|
||||
# Additional environment variables
|
||||
CMAKE_BUILD_TYPE = "Debug";
|
||||
ENABLE_CCACHE = "1";
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
1
invalid.css
Normal file
1
invalid.css
Normal file
@@ -0,0 +1 @@
|
||||
.test{color:}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "bun",
|
||||
"version": "1.3.2",
|
||||
"version": "1.2.24",
|
||||
"workspaces": [
|
||||
"./packages/bun-types",
|
||||
"./packages/@types/bun"
|
||||
@@ -23,8 +23,7 @@
|
||||
},
|
||||
"resolutions": {
|
||||
"bun-types": "workspace:packages/bun-types",
|
||||
"@types/bun": "workspace:packages/@types/bun",
|
||||
"@types/node": "24.3.1"
|
||||
"@types/bun": "workspace:packages/@types/bun"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "bun --silent run build:debug",
|
||||
@@ -87,10 +86,9 @@
|
||||
"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.22",
|
||||
"machine:linux:alpine": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=linux --distro=alpine --release=3.21",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
1
packages/bun-framework-react/.gitignore
vendored
1
packages/bun-framework-react/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
bun-framework-react*.tgz
|
||||
@@ -1,10 +0,0 @@
|
||||
<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) 🎉
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"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=="],
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
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);
|
||||
});
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
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;
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
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);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import { Router } from "./router.ts";
|
||||
|
||||
export const router: Router = new Router();
|
||||
@@ -1,355 +0,0 @@
|
||||
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();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export function isThenable<T>(payload: PromiseLike<T> | unknown): payload is PromiseLike<T> {
|
||||
return payload !== null && typeof payload === "object" && "then" in payload;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
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;
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
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,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
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);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
"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);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
*
|
||||
@@ -1,21 +0,0 @@
|
||||
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.
|
||||
@@ -1,5 +0,0 @@
|
||||
# react-server-dom-bun
|
||||
|
||||
Experimental React Flight bindings for DOM using Bun.
|
||||
|
||||
**Use it at your own risk.**
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
export function createFromReadableStream<T>(readable: ReadableStream<T>): Promise<T>;
|
||||
@@ -1,7 +0,0 @@
|
||||
'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');
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = require('./client.browser');
|
||||
@@ -1,7 +0,0 @@
|
||||
'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');
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user