Compare commits

..

1 Commits

Author SHA1 Message Date
Ciro Spaciari
e783515cd0 fix agent port being rewritten 2025-07-24 11:43:09 -07:00
1326 changed files with 104520 additions and 256105 deletions

78
.agent/agent.mjs Normal file
View File

@@ -0,0 +1,78 @@
import { spawnSync } from "node:child_process";
import { readFileSync, existsSync } from "node:fs";
import { parseArgs } from "node:util";
const { positionals, values } = parseArgs({
allowPositionals: true,
options: {
help: {
type: "boolean",
short: "h",
default: false,
},
interactive: {
type: "boolean",
short: "i",
default: false,
},
},
});
if (values.help || positionals.length === 0) {
console.log("Usage: node agent.mjs <prompt_name> [extra_args...]");
console.log("Example: node agent.mjs triage fix bug in authentication");
console.log("Options:");
console.log(" -h, --help Show this help message");
console.log(" -i, --interactive Run in interactive mode");
process.exit(0);
}
const promptName = positionals[0].toUpperCase();
const promptFile = `.agent/${promptName}.md`;
const extraArgs = positionals.slice(1);
if (!existsSync(promptFile)) {
console.error(`Error: Prompt file "${promptFile}" not found`);
console.error(`Available prompts should be named like: .agent/triage.md, .agent/debug.md, etc.`);
process.exit(1);
}
try {
let prompt = readFileSync(promptFile, "utf-8");
const githubEnvs = Object.entries(process.env)
.filter(([key]) => key.startsWith("GITHUB_"))
.sort(([a], [b]) => a.localeCompare(b));
if (githubEnvs.length > 0) {
const githubContext = `## GitHub Environment\n\n${githubEnvs
.map(([key, value]) => `**${key}**: \`${value}\``)
.join("\n")}\n\n---\n\n`;
prompt = githubContext + prompt;
}
if (extraArgs.length > 0) {
const extraArgsContext = `\n\n## Additional Arguments\n\n${extraArgs.join(" ")}\n\n---\n\n`;
prompt = prompt + extraArgsContext;
}
const claudeArgs = [prompt, "--allowedTools=Edit,Write,Replace,Search", "--output-format=json"];
if (!values.interactive) {
claudeArgs.unshift("--print");
}
const { status, error } = spawnSync("claude", claudeArgs, {
stdio: "inherit",
encoding: "utf-8",
});
if (error) {
console.error("Error running claude:", error);
process.exit(1);
}
process.exit(status || 0);
} catch (error) {
console.error(`Error reading prompt file "${promptFile}":`, error);
process.exit(1);
}

View File

@@ -303,34 +303,9 @@ function getCppAgent(platform, options) {
}
return getEc2Agent(platform, options, {
instanceType: arch === "aarch64" ? "c8g.4xlarge" : "c7i.4xlarge",
});
}
/**
* @param {Platform} platform
* @param {PipelineOptions} options
* @returns {string}
*/
function getLinkBunAgent(platform, options) {
const { os, arch, distro } = platform;
if (os === "darwin") {
return {
queue: `build-${os}`,
os,
arch,
};
}
if (os === "windows") {
return getEc2Agent(platform, options, {
instanceType: arch === "aarch64" ? "r8g.large" : "r7i.large",
});
}
return getEc2Agent(platform, options, {
instanceType: arch === "aarch64" ? "r8g.xlarge" : "r7i.xlarge",
instanceType: arch === "aarch64" ? "c8g.16xlarge" : "c7i.16xlarge",
cpuCount: 32,
threadsPerCore: 1,
});
}
@@ -381,7 +356,7 @@ function getTestAgent(platform, options) {
};
}
// TODO: delete this block when we upgrade to mimalloc v3
// TODO: `dev-server-ssr-110.test.ts` and `next-build.test.ts` run out of memory at 8GB of memory, so use 16GB instead.
if (os === "windows") {
return getEc2Agent(platform, options, {
instanceType: "c7i.2xlarge",
@@ -434,17 +409,11 @@ function getBuildEnv(target, options) {
* @param {PipelineOptions} options
* @returns {string}
*/
function getBuildCommand(target, options, label) {
function getBuildCommand(target, options) {
const { profile } = target;
const buildProfile = profile || "release";
if (target.os === "windows" && label === "build-bun") {
// Only sign release builds, not canary builds (DigiCert charges per signature)
const enableSigning = !options.canary ? " -DENABLE_WINDOWS_CODESIGNING=ON" : "";
return `bun run build:${buildProfile}${enableSigning}`;
}
return `bun run build:${buildProfile}`;
const label = profile || "release";
return `bun run build:${label}`;
}
/**
@@ -533,14 +502,14 @@ function getLinkBunStep(platform, options) {
key: `${getTargetKey(platform)}-build-bun`,
label: `${getTargetLabel(platform)} - build-bun`,
depends_on: [`${getTargetKey(platform)}-build-cpp`, `${getTargetKey(platform)}-build-zig`],
agents: getLinkBunAgent(platform, options),
agents: getCppAgent(platform, options),
retry: getRetry(),
cancel_on_build_failing: isMergeQueue(),
env: {
BUN_LINK_ONLY: "ON",
...getBuildEnv(platform, options),
},
command: `${getBuildCommand(platform, options, "build-bun")} --target bun`,
command: `${getBuildCommand(platform, options)} --target bun`,
};
}

View File

@@ -1,464 +0,0 @@
# Windows Code Signing Script for Bun
# Uses DigiCert KeyLocker for Authenticode signing
# Native PowerShell implementation - no path translation issues
param(
[Parameter(Mandatory=$true)]
[string]$BunProfileExe,
[Parameter(Mandatory=$true)]
[string]$BunExe
)
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
# Logging functions
function Log-Info {
param([string]$Message)
Write-Host "[INFO] $Message" -ForegroundColor Cyan
}
function Log-Success {
param([string]$Message)
Write-Host "[SUCCESS] $Message" -ForegroundColor Green
}
function Log-Error {
param([string]$Message)
Write-Host "[ERROR] $Message" -ForegroundColor Red
}
function Log-Debug {
param([string]$Message)
if ($env:DEBUG -eq "true" -or $env:DEBUG -eq "1") {
Write-Host "[DEBUG] $Message" -ForegroundColor Gray
}
}
# Load Visual Studio environment if not already loaded
function Ensure-VSEnvironment {
if ($null -eq $env:VSINSTALLDIR) {
Log-Info "Loading Visual Studio environment..."
$vswhere = "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"
if (!(Test-Path $vswhere)) {
throw "Command not found: vswhere (did you install Visual Studio?)"
}
$vsDir = & $vswhere -prerelease -latest -property installationPath
if ($null -eq $vsDir) {
$vsDir = Get-ChildItem -Path "C:\Program Files\Microsoft Visual Studio\2022" -Directory -ErrorAction SilentlyContinue
if ($null -eq $vsDir) {
throw "Visual Studio directory not found."
}
$vsDir = $vsDir.FullName
}
Push-Location $vsDir
try {
$vsShell = Join-Path -Path $vsDir -ChildPath "Common7\Tools\Launch-VsDevShell.ps1"
. $vsShell -Arch amd64 -HostArch amd64
} finally {
Pop-Location
}
Log-Success "Visual Studio environment loaded"
}
if ($env:VSCMD_ARG_TGT_ARCH -eq "x86") {
throw "Visual Studio environment is targeting 32 bit, but only 64 bit is supported."
}
}
# Check for required environment variables
function Check-Environment {
Log-Info "Checking environment variables..."
$required = @{
"SM_API_KEY" = $env:SM_API_KEY
"SM_CLIENT_CERT_PASSWORD" = $env:SM_CLIENT_CERT_PASSWORD
"SM_KEYPAIR_ALIAS" = $env:SM_KEYPAIR_ALIAS
"SM_HOST" = $env:SM_HOST
"SM_CLIENT_CERT_FILE" = $env:SM_CLIENT_CERT_FILE
}
$missing = @()
foreach ($key in $required.Keys) {
if ([string]::IsNullOrEmpty($required[$key])) {
$missing += $key
} else {
Log-Debug "$key is set (length: $($required[$key].Length))"
}
}
if ($missing.Count -gt 0) {
throw "Missing required environment variables: $($missing -join ', ')"
}
Log-Success "All required environment variables are present"
}
# Setup certificate file
function Setup-Certificate {
Log-Info "Setting up certificate..."
# Always try to decode as base64 first
# If it fails, then treat as file path
try {
Log-Info "Attempting to decode certificate as base64..."
Log-Debug "Input string length: $($env:SM_CLIENT_CERT_FILE.Length) characters"
$tempCertPath = Join-Path $env:TEMP "digicert_cert_$(Get-Random).p12"
# Try to decode as base64
$certBytes = [System.Convert]::FromBase64String($env:SM_CLIENT_CERT_FILE)
[System.IO.File]::WriteAllBytes($tempCertPath, $certBytes)
# Validate the decoded certificate size
$fileSize = (Get-Item $tempCertPath).Length
if ($fileSize -lt 100) {
throw "Decoded certificate too small: $fileSize bytes (expected >100 bytes)"
}
# Update environment to point to file
$env:SM_CLIENT_CERT_FILE = $tempCertPath
Log-Success "Certificate decoded and written to: $tempCertPath"
Log-Debug "Decoded certificate file size: $fileSize bytes"
# Register cleanup
$global:TEMP_CERT_PATH = $tempCertPath
} catch {
# If base64 decode fails, check if it's a file path
Log-Info "Base64 decode failed, checking if it's a file path..."
Log-Debug "Decode error: $_"
if (Test-Path $env:SM_CLIENT_CERT_FILE) {
$fileSize = (Get-Item $env:SM_CLIENT_CERT_FILE).Length
# Validate file size
if ($fileSize -lt 100) {
throw "Certificate file too small: $fileSize bytes at $env:SM_CLIENT_CERT_FILE (possibly corrupted)"
}
Log-Info "Using certificate file: $env:SM_CLIENT_CERT_FILE"
Log-Debug "Certificate file size: $fileSize bytes"
} else {
throw "SM_CLIENT_CERT_FILE is neither valid base64 nor an existing file: $env:SM_CLIENT_CERT_FILE"
}
}
}
# Install DigiCert KeyLocker tools
function Install-KeyLocker {
Log-Info "Setting up DigiCert KeyLocker tools..."
# Define our controlled installation directory
$installDir = "C:\BuildTools\DigiCert"
$smctlPath = Join-Path $installDir "smctl.exe"
# Check if already installed in our controlled location
if (Test-Path $smctlPath) {
Log-Success "KeyLocker tools already installed at: $smctlPath"
# Add to PATH if not already there
if ($env:PATH -notlike "*$installDir*") {
$env:PATH = "$installDir;$env:PATH"
Log-Info "Added to PATH: $installDir"
}
return $smctlPath
}
Log-Info "Installing KeyLocker tools to: $installDir"
# Create the installation directory if it doesn't exist
if (!(Test-Path $installDir)) {
Log-Info "Creating installation directory: $installDir"
try {
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
Log-Success "Created directory: $installDir"
} catch {
throw "Failed to create directory $installDir : $_"
}
}
# Download MSI installer
$msiUrl = "https://bun-ci-assets.bun.sh/Keylockertools-windows-x64.msi"
$msiPath = Join-Path $env:TEMP "Keylockertools-windows-x64.msi"
Log-Info "Downloading MSI from: $msiUrl"
Log-Info "Downloading to: $msiPath"
try {
# Remove existing MSI if present
if (Test-Path $msiPath) {
Remove-Item $msiPath -Force
Log-Debug "Removed existing MSI file"
}
# Download with progress tracking
$webClient = New-Object System.Net.WebClient
$webClient.DownloadFile($msiUrl, $msiPath)
if (!(Test-Path $msiPath)) {
throw "MSI download failed - file not found"
}
$fileSize = (Get-Item $msiPath).Length
Log-Success "MSI downloaded successfully (size: $fileSize bytes)"
} catch {
throw "Failed to download MSI: $_"
}
# Install MSI
Log-Info "Installing MSI..."
Log-Debug "MSI path: $msiPath"
Log-Debug "File exists: $(Test-Path $msiPath)"
Log-Debug "File size: $((Get-Item $msiPath).Length) bytes"
# Check if running as administrator
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
Log-Info "Running as administrator: $isAdmin"
# Install MSI silently to our controlled directory
$arguments = @(
"/i", "`"$msiPath`"",
"/quiet",
"/norestart",
"TARGETDIR=`"$installDir`"",
"INSTALLDIR=`"$installDir`"",
"ACCEPT_EULA=1",
"ADDLOCAL=ALL"
)
Log-Debug "Running: msiexec.exe $($arguments -join ' ')"
Log-Info "Installing to: $installDir"
$process = Start-Process -FilePath "msiexec.exe" -ArgumentList $arguments -Wait -PassThru -NoNewWindow
if ($process.ExitCode -ne 0) {
Log-Error "MSI installation failed with exit code: $($process.ExitCode)"
# Try to get error details from event log
try {
$events = Get-WinEvent -LogName "Application" -MaxEvents 10 |
Where-Object { $_.ProviderName -eq "MsiInstaller" -and $_.TimeCreated -gt (Get-Date).AddMinutes(-1) }
foreach ($event in $events) {
Log-Debug "MSI Event: $($event.Message)"
}
} catch {
Log-Debug "Could not retrieve MSI installation events"
}
throw "MSI installation failed with exit code: $($process.ExitCode)"
}
Log-Success "MSI installation completed"
# Wait for installation to complete
Start-Sleep -Seconds 2
# Verify smctl.exe exists in our controlled location
if (Test-Path $smctlPath) {
Log-Success "KeyLocker tools installed successfully at: $smctlPath"
# Add to PATH
$env:PATH = "$installDir;$env:PATH"
Log-Info "Added to PATH: $installDir"
return $smctlPath
}
# If not in our expected location, check if it installed somewhere in the directory
$found = Get-ChildItem -Path $installDir -Filter "smctl.exe" -Recurse -ErrorAction SilentlyContinue |
Select-Object -First 1
if ($found) {
Log-Success "Found smctl.exe at: $($found.FullName)"
$smctlDir = $found.DirectoryName
$env:PATH = "$smctlDir;$env:PATH"
return $found.FullName
}
throw "KeyLocker tools installation succeeded but smctl.exe not found in $installDir"
}
# Configure KeyLocker
function Configure-KeyLocker {
param([string]$SmctlPath)
Log-Info "Configuring KeyLocker..."
# Verify smctl is accessible
try {
$version = & $SmctlPath --version 2>&1
Log-Debug "smctl version: $version"
} catch {
throw "Failed to run smctl: $_"
}
# Configure KeyLocker credentials and environment
Log-Info "Configuring KeyLocker credentials..."
try {
# Save credentials (API key and password)
Log-Info "Saving credentials to OS store..."
$saveOutput = & $SmctlPath credentials save $env:SM_API_KEY $env:SM_CLIENT_CERT_PASSWORD 2>&1 | Out-String
Log-Debug "Credentials save output: $saveOutput"
if ($saveOutput -like "*Credentials saved*") {
Log-Success "Credentials saved successfully"
}
# Set environment variables for smctl
Log-Info "Setting KeyLocker environment variables..."
$env:SM_HOST = $env:SM_HOST # Already set, but ensure it's available
$env:SM_API_KEY = $env:SM_API_KEY # Already set
$env:SM_CLIENT_CERT_FILE = $env:SM_CLIENT_CERT_FILE # Path to decoded cert file
Log-Debug "SM_HOST: $env:SM_HOST"
Log-Debug "SM_CLIENT_CERT_FILE: $env:SM_CLIENT_CERT_FILE"
# Run health check
Log-Info "Running KeyLocker health check..."
$healthOutput = & $SmctlPath healthcheck 2>&1 | Out-String
Log-Debug "Health check output: $healthOutput"
if ($healthOutput -like "*Healthy*" -or $healthOutput -like "*SUCCESS*" -or $LASTEXITCODE -eq 0) {
Log-Success "KeyLocker health check passed"
} else {
Log-Error "Health check failed: $healthOutput"
# Don't throw here, sometimes healthcheck is flaky but signing still works
}
# Sync certificates to Windows certificate store
Log-Info "Syncing certificates to Windows store..."
$syncOutput = & $SmctlPath windows certsync 2>&1 | Out-String
Log-Debug "Certificate sync output: $syncOutput"
if ($syncOutput -like "*success*" -or $syncOutput -like "*synced*" -or $LASTEXITCODE -eq 0) {
Log-Success "Certificates synced to Windows store"
} else {
Log-Info "Certificate sync output: $syncOutput"
}
} catch {
throw "Failed to configure KeyLocker: $_"
}
}
# Sign an executable
function Sign-Executable {
param(
[string]$ExePath,
[string]$SmctlPath
)
if (!(Test-Path $ExePath)) {
throw "Executable not found: $ExePath"
}
$fileName = Split-Path $ExePath -Leaf
Log-Info "Signing $fileName..."
Log-Debug "Full path: $ExePath"
Log-Debug "File size: $((Get-Item $ExePath).Length) bytes"
# Check if already signed
$existingSig = Get-AuthenticodeSignature $ExePath
if ($existingSig.Status -eq "Valid") {
Log-Info "$fileName is already signed by: $($existingSig.SignerCertificate.Subject)"
Log-Info "Skipping re-signing"
return
}
# Sign the executable using smctl
try {
# smctl sign command with keypair-alias
$signArgs = @(
"sign",
"--keypair-alias", $env:SM_KEYPAIR_ALIAS,
"--input", $ExePath,
"--verbose"
)
Log-Debug "Running: $SmctlPath $($signArgs -join ' ')"
$signOutput = & $SmctlPath $signArgs 2>&1 | Out-String
if ($LASTEXITCODE -ne 0) {
Log-Error "Signing output: $signOutput"
throw "Signing failed with exit code: $LASTEXITCODE"
}
Log-Debug "Signing output: $signOutput"
Log-Success "Signing command completed"
} catch {
throw "Failed to sign $fileName : $_"
}
# Verify signature
$newSig = Get-AuthenticodeSignature $ExePath
if ($newSig.Status -eq "Valid") {
Log-Success "$fileName signed successfully"
Log-Info "Signed by: $($newSig.SignerCertificate.Subject)"
Log-Info "Thumbprint: $($newSig.SignerCertificate.Thumbprint)"
Log-Info "Valid from: $($newSig.SignerCertificate.NotBefore) to $($newSig.SignerCertificate.NotAfter)"
} else {
throw "$fileName signature verification failed: $($newSig.Status) - $($newSig.StatusMessage)"
}
}
# Cleanup function
function Cleanup {
if ($global:TEMP_CERT_PATH -and (Test-Path $global:TEMP_CERT_PATH)) {
try {
Remove-Item $global:TEMP_CERT_PATH -Force
Log-Info "Cleaned up temporary certificate"
} catch {
Log-Error "Failed to cleanup temporary certificate: $_"
}
}
}
# Main execution
try {
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " Windows Code Signing for Bun" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
# Ensure we're in a VS environment
Ensure-VSEnvironment
# Check environment variables
Check-Environment
# Setup certificate
Setup-Certificate
# Install and configure KeyLocker
$smctlPath = Install-KeyLocker
Configure-KeyLocker -SmctlPath $smctlPath
# Sign both executables
Sign-Executable -ExePath $BunProfileExe -SmctlPath $smctlPath
Sign-Executable -ExePath $BunExe -SmctlPath $smctlPath
Write-Host "========================================" -ForegroundColor Green
Write-Host " Code signing completed successfully!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
exit 0
} catch {
Log-Error "Code signing failed: $_"
exit 1
} finally {
Cleanup
}

View File

@@ -1,3 +1,50 @@
### What does this PR do?
<!-- **Please explain what your changes do**, example: -->
<!--
This adds a new flag --bail to bun test. When set, it will stop running tests after the first failure. This is useful for CI environments where you want to fail fast.
-->
- [ ] Documentation or TypeScript types (it's okay to leave the rest blank in this case)
- [ ] Code changes
### How did you verify your code works?
<!-- **For code changes, please include automated tests**. Feel free to uncomment the line below -->
<!-- I wrote automated tests -->
<!-- If JavaScript/TypeScript modules or builtins changed:
- [ ] I included a test for the new code, or existing tests cover it
- [ ] I ran my tests locally and they pass (`bun-debug test test-file-name.test`)
-->
<!-- If Zig files changed:
- [ ] I checked the lifetime of memory allocated to verify it's (1) freed and (2) only freed when it should be
- [ ] I included a test for the new code, or an existing test covers it
- [ ] JSValue used outside of the stack is either wrapped in a JSC.Strong or is JSValueProtect'ed
- [ ] I wrote TypeScript/JavaScript tests and they pass locally (`bun-debug test test-file-name.test`)
-->
<!-- If new methods, getters, or setters were added to a publicly exposed class:
- [ ] I added TypeScript types for the new methods, getters, or setters
-->
<!-- If dependencies in tests changed:
- [ ] I made sure that specific versions of dependencies are used instead of ranged or tagged versions
-->
<!-- If a new builtin ESM/CJS module was added:
- [ ] I updated Aliases in `module_loader.zig` to include the new module
- [ ] I added a test that imports the module
- [ ] I added a test that require() the module
-->

View File

@@ -1,103 +0,0 @@
# GitHub Actions Workflow Maintenance Guide
This document provides guidance for maintaining the GitHub Actions workflows in this repository.
## format.yml Workflow
### Overview
The `format.yml` workflow runs code formatters (Prettier, clang-format, and Zig fmt) on pull requests and pushes to main. It's optimized for speed by running all formatters in parallel.
### Key Components
#### 1. Clang-format Script (`scripts/run-clang-format.sh`)
- **Purpose**: Formats C++ source and header files
- **What it does**:
- Reads C++ files from `cmake/sources/CxxSources.txt`
- Finds all header files in `src/` and `packages/`
- Excludes third-party directories (libuv, napi, deps, vendor, sqlite, etc.)
- Requires specific clang-format version (no fallbacks)
**Important exclusions**:
- `src/napi/` - Node API headers (third-party)
- `src/bun.js/bindings/libuv/` - libuv headers (third-party)
- `src/bun.js/bindings/sqlite/` - SQLite headers (third-party)
- `src/bun.js/api/ffi-*.h` - FFI headers (generated/third-party)
- `src/deps/` - Dependencies (third-party)
- Files in `vendor/`, `third_party/`, `generated/` directories
#### 2. Parallel Execution
The workflow runs all three formatters simultaneously:
- Each formatter outputs with a prefix (`[prettier]`, `[clang-format]`, `[zig]`)
- Output is streamed in real-time without blocking
- Uses GitHub Actions groups (`::group::`) for collapsible sections
#### 3. Tool Installation
##### Clang-format-19
- Installs ONLY `clang-format-19` package (not the entire LLVM toolchain)
- Uses `--no-install-recommends --no-install-suggests` to skip unnecessary packages
- Quiet installation with `-qq` and `-o=Dpkg::Use-Pty=0`
##### Zig
- Downloads from `oven-sh/zig` releases (musl build for static linking)
- URL: `https://github.com/oven-sh/zig/releases/download/autobuild-{COMMIT}/bootstrap-x86_64-linux-musl.zip`
- Extracts to temp directory to avoid polluting the repository
- Directory structure: `bootstrap-x86_64-linux-musl/zig`
### Updating the Workflow
#### To update Zig version:
1. Find the new commit hash from https://github.com/oven-sh/zig/releases
2. Replace the hash in the wget URL (line 65 of format.yml)
3. Test that the URL is valid and the binary works
#### To update clang-format version:
1. Update `LLVM_VERSION_MAJOR` environment variable at the top of format.yml
2. Update the version check in `scripts/run-clang-format.sh`
#### To add/remove file exclusions:
1. Edit the exclusion patterns in `scripts/run-clang-format.sh` (lines 34-39)
2. Test locally to ensure the right files are being formatted
### Performance Optimizations
1. **Parallel execution**: All formatters run simultaneously
2. **Minimal installations**: Only required packages, no extras
3. **Temp directories**: Tools downloaded to temp dirs, cleaned up after use
4. **Streaming output**: Real-time feedback without buffering
5. **Early start**: Formatting begins immediately after each tool is ready
### Troubleshooting
**If formatters appear to run sequentially:**
- Check if output is being buffered (should use `sed` for line prefixing)
- Ensure background processes use `&` and proper wait commands
**If third-party files are being formatted:**
- Review exclusion patterns in `scripts/run-clang-format.sh`
- Check if new third-party directories were added that need exclusion
**If clang-format installation is slow:**
- Ensure using minimal package installation flags
- Check if apt cache needs updating
- Consider caching the clang-format binary between runs
### Testing Changes Locally
```bash
# Test the clang-format script
export LLVM_VERSION_MAJOR=19
./scripts/run-clang-format.sh format
# Test with check mode (no modifications)
./scripts/run-clang-format.sh check
# Test specific file exclusions
./scripts/run-clang-format.sh format 2>&1 | grep -E "(libuv|napi|deps)"
# Should return nothing if exclusions work correctly
```
### Important Notes
- The script defaults to **format** mode (modifies files)
- Always test locally before pushing workflow changes
- The musl Zig build works on glibc systems due to static linking
- Keep the exclusion list updated as new third-party code is added

View File

@@ -1,24 +0,0 @@
name: Auto-label Claude PRs
on:
pull_request:
types: [opened]
jobs:
auto-label:
if: github.event.pull_request.user.login == 'robobun' || contains(github.event.pull_request.body, '🤖 Generated with')
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Add claude label to PRs from robobun
uses: actions/github-script@v7
with:
script: |
github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['claude']
});

View File

@@ -13,55 +13,23 @@ on:
jobs:
claude:
if: |
github.repository == 'oven-sh/bun' &&
(
(github.event_name == 'issue_comment' && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'COLLABORATOR')) ||
(github.event_name == 'pull_request_review_comment' && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'COLLABORATOR')) ||
(github.event_name == 'pull_request_review' && (github.event.review.author_association == 'MEMBER' || github.event.review.author_association == 'OWNER' || github.event.review.author_association == 'COLLABORATOR')) ||
(github.event_name == 'issues' && (github.event.issue.author_association == 'MEMBER' || github.event.issue.author_association == 'OWNER' || github.event.issue.author_association == 'COLLABORATOR'))
) &&
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: claude
env:
IS_SANDBOX: 1
container:
image: localhost:5000/claude-bun:latest
options: --privileged --user 1000:1000
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Checkout repository
working-directory: /workspace/bun
run: |
git config --global user.email "claude-bot@bun.sh" && \
git config --global user.name "Claude Bot" && \
git config --global url."git@github.com:".insteadOf "https://github.com/" && \
git config --global url."git@github.com:".insteadOf "http://github.com/" && \
git config --global --add safe.directory /workspace/bun && \
git config --global push.default current && \
git config --global pull.rebase true && \
git config --global init.defaultBranch main && \
git config --global core.editor "vim" && \
git config --global color.ui auto && \
git config --global fetch.prune true && \
git config --global diff.colorMoved zebra && \
git config --global merge.conflictStyle diff3 && \
git config --global rerere.enabled true && \
git config --global core.autocrlf input
git fetch origin ${{ github.event.pull_request.head.sha }}
git checkout ${{ github.event.pull_request.head.ref }}
git reset --hard origin/${{ github.event.pull_request.head.ref }}
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Run Claude Code
id: claude
# TODO: switch this out once they merge their v1
uses: km-anthropic/claude-code-action@v1-dev
uses: anthropics/claude-code-action@beta
with:
timeout_minutes: "180"
claude_args: |
--dangerously-skip-permissions
--system-prompt "You are working on the Bun codebase"
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

View File

@@ -6,8 +6,6 @@ on:
- "docs/**"
- "packages/bun-types/**.d.ts"
- "CONTRIBUTING.md"
- "src/cli/install.sh"
- "src/cli/install.ps1"
branches:
- main

View File

@@ -37,73 +37,22 @@ jobs:
- name: Setup Dependencies
run: |
bun install
- name: Format Code
- name: Install LLVM
run: |
# Start prettier in background with prefixed output
echo "::group::Prettier"
(bun run prettier 2>&1 | sed 's/^/[prettier] /' || echo "[prettier] Failed with exit code $?") &
PRETTIER_PID=$!
# Start clang-format installation and formatting in background with prefixed output
echo "::group::Clang-format"
(
echo "[clang-format] Installing clang-format-${{ env.LLVM_VERSION_MAJOR }}..."
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc > /dev/null
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-${{ env.LLVM_VERSION_MAJOR }} main" | sudo tee /etc/apt/sources.list.d/llvm.list > /dev/null
sudo apt-get update -qq
sudo apt-get install -y -qq --no-install-recommends --no-install-suggests -o=Dpkg::Use-Pty=0 clang-format-${{ env.LLVM_VERSION_MAJOR }}
echo "[clang-format] Running clang-format..."
LLVM_VERSION_MAJOR=${{ env.LLVM_VERSION_MAJOR }} ./scripts/run-clang-format.sh format 2>&1 | sed 's/^/[clang-format] /'
) &
CLANG_PID=$!
# Setup Zig in temp directory and run zig fmt in background with prefixed output
echo "::group::Zig fmt"
(
ZIG_TEMP=$(mktemp -d)
echo "[zig] Downloading Zig (musl build)..."
wget -q -O "$ZIG_TEMP/zig.zip" https://github.com/oven-sh/zig/releases/download/autobuild-d1a4e0b0ddc75f37c6a090b97eef0cbb6335556e/bootstrap-x86_64-linux-musl.zip
unzip -q -d "$ZIG_TEMP" "$ZIG_TEMP/zig.zip"
export PATH="$ZIG_TEMP/bootstrap-x86_64-linux-musl:$PATH"
echo "[zig] Running zig fmt..."
zig fmt src 2>&1 | sed 's/^/[zig] /'
./scripts/sort-imports.ts src 2>&1 | sed 's/^/[zig] /'
zig fmt src 2>&1 | sed 's/^/[zig] /'
rm -rf "$ZIG_TEMP"
) &
ZIG_PID=$!
# Wait for all formatting tasks to complete
echo ""
echo "Running formatters in parallel..."
FAILED=0
if ! wait $PRETTIER_PID; then
echo "::error::Prettier failed"
FAILED=1
fi
echo "::endgroup::"
if ! wait $CLANG_PID; then
echo "::error::Clang-format failed"
FAILED=1
fi
echo "::endgroup::"
if ! wait $ZIG_PID; then
echo "::error::Zig fmt failed"
FAILED=1
fi
echo "::endgroup::"
# Exit with error if any formatter failed
if [ $FAILED -eq 1 ]; then
echo "::error::One or more formatters failed"
exit 1
fi
echo "✅ All formatters completed successfully"
- name: Ban Words
curl -fsSL https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.LLVM_VERSION_MAJOR }} all
- name: Setup Zig
uses: mlugg/setup-zig@v1
with:
version: 0.14.0
- name: Zig Format
run: |
bun ./test/internal/ban-words.test.ts
zig fmt src
./scripts/sort-imports.ts src
zig fmt src
- name: Prettier Format
run: |
bun run prettier
- name: Clang Format
run: |
bun run clang-format
- uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27

View File

@@ -55,13 +55,10 @@ jobs:
echo "Error: Could not fetch SHA for tag $LATEST_TAG"
exit 1
fi
# Try to get commit SHA from tag object (for annotated tags)
# If it fails, assume it's a lightweight tag pointing directly to commit
LATEST_SHA=$(curl -sL "https://api.github.com/repos/HdrHistogram/HdrHistogram_c/git/tags/$LATEST_TAG_SHA" 2>/dev/null | jq -r '.object.sha // empty')
if [ -z "$LATEST_SHA" ]; then
# Lightweight tag - SHA points directly to commit
LATEST_SHA="$LATEST_TAG_SHA"
LATEST_SHA=$(curl -sL "https://api.github.com/repos/HdrHistogram/HdrHistogram_c/git/tags/$LATEST_TAG_SHA" | jq -r '.object.sha')
if [ -z "$LATEST_SHA" ] || [ "$LATEST_SHA" = "null" ]; then
echo "Error: Could not fetch SHA for tag $LATEST_TAG @ $LATEST_TAG_SHA"
exit 1
fi
if ! [[ $LATEST_SHA =~ ^[0-9a-f]{40}$ ]]; then
@@ -91,7 +88,7 @@ jobs:
commit-message: "deps: update hdrhistogram to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
title: "deps: update hdrhistogram to ${{ steps.check-version.outputs.tag }}"
delete-branch: true
branch: deps/update-hdrhistogram-${{ github.run_number }}
branch: deps/update-cares-${{ github.run_number }}
body: |
## What does this PR do?
@@ -99,4 +96,4 @@ jobs:
Compare: https://github.com/HdrHistogram/HdrHistogram_c/compare/${{ steps.check-version.outputs.current }}...${{ steps.check-version.outputs.latest }}
Auto-updated by [this workflow](https://github.com/oven-sh/bun/actions/workflows/update-hdrhistogram.yml)
Auto-updated by [this workflow](https://github.com/oven-sh/bun/actions/workflows/update-cares.yml)

View File

@@ -50,33 +50,14 @@ jobs:
exit 1
fi
TAG_REF=$(curl -sL "https://api.github.com/repos/google/highway/git/refs/tags/$LATEST_TAG")
if [ -z "$TAG_REF" ]; then
echo "Error: Could not fetch tag reference for $LATEST_TAG"
exit 1
fi
TAG_OBJECT_SHA=$(echo "$TAG_REF" | jq -r '.object.sha')
TAG_OBJECT_TYPE=$(echo "$TAG_REF" | jq -r '.object.type')
if [ -z "$TAG_OBJECT_SHA" ] || [ "$TAG_OBJECT_SHA" = "null" ]; then
LATEST_TAG_SHA=$(curl -sL "https://api.github.com/repos/google/highway/git/refs/tags/$LATEST_TAG" | jq -r '.object.sha')
if [ -z "$LATEST_TAG_SHA" ] || [ "$LATEST_TAG_SHA" = "null" ]; then
echo "Error: Could not fetch SHA for tag $LATEST_TAG"
exit 1
fi
# Handle both lightweight tags (type: commit) and annotated tags (type: tag)
if [ "$TAG_OBJECT_TYPE" = "commit" ]; then
# Lightweight tag - object.sha is already the commit SHA
LATEST_SHA="$TAG_OBJECT_SHA"
elif [ "$TAG_OBJECT_TYPE" = "tag" ]; then
# Annotated tag - need to fetch the tag object to get the commit SHA
LATEST_SHA=$(curl -sL "https://api.github.com/repos/google/highway/git/tags/$TAG_OBJECT_SHA" | jq -r '.object.sha')
if [ -z "$LATEST_SHA" ] || [ "$LATEST_SHA" = "null" ]; then
echo "Error: Could not fetch commit SHA for annotated tag $LATEST_TAG @ $TAG_OBJECT_SHA"
exit 1
fi
else
echo "Error: Unexpected tag object type: $TAG_OBJECT_TYPE"
LATEST_SHA=$(curl -sL "https://api.github.com/repos/google/highway/git/tags/$LATEST_TAG_SHA" | jq -r '.object.sha')
if [ -z "$LATEST_SHA" ] || [ "$LATEST_SHA" = "null" ]; then
echo "Error: Could not fetch SHA for tag $LATEST_TAG @ $LATEST_TAG_SHA"
exit 1
fi
@@ -107,7 +88,7 @@ jobs:
commit-message: "deps: update highway to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
title: "deps: update highway to ${{ steps.check-version.outputs.tag }}"
delete-branch: true
branch: deps/update-highway-${{ github.run_number }}
branch: deps/update-cares-${{ github.run_number }}
body: |
## What does this PR do?
@@ -115,4 +96,4 @@ jobs:
Compare: https://github.com/google/highway/compare/${{ steps.check-version.outputs.current }}...${{ steps.check-version.outputs.latest }}
Auto-updated by [this workflow](https://github.com/oven-sh/bun/actions/workflows/update-highway.yml)
Auto-updated by [this workflow](https://github.com/oven-sh/bun/actions/workflows/update-cares.yml)

View File

@@ -50,27 +50,15 @@ jobs:
exit 1
fi
# Get the commit SHA that the tag points to
# This handles both lightweight tags (direct commit refs) and annotated tags (tag objects)
TAG_REF_RESPONSE=$(curl -sL "https://api.github.com/repos/cloudflare/lol-html/git/refs/tags/$LATEST_TAG")
LATEST_TAG_SHA=$(echo "$TAG_REF_RESPONSE" | jq -r '.object.sha')
TAG_OBJECT_TYPE=$(echo "$TAG_REF_RESPONSE" | jq -r '.object.type')
LATEST_TAG_SHA=$(curl -sL "https://api.github.com/repos/cloudflare/lol-html/git/refs/tags/$LATEST_TAG" | jq -r '.object.sha')
if [ -z "$LATEST_TAG_SHA" ] || [ "$LATEST_TAG_SHA" = "null" ]; then
echo "Error: Could not fetch SHA for tag $LATEST_TAG"
exit 1
fi
if [ "$TAG_OBJECT_TYPE" = "tag" ]; then
# This is an annotated tag, we need to get the commit it points to
LATEST_SHA=$(curl -sL "https://api.github.com/repos/cloudflare/lol-html/git/tags/$LATEST_TAG_SHA" | jq -r '.object.sha')
if [ -z "$LATEST_SHA" ] || [ "$LATEST_SHA" = "null" ]; then
echo "Error: Could not fetch commit SHA for annotated tag $LATEST_TAG @ $LATEST_TAG_SHA"
exit 1
fi
else
# This is a lightweight tag pointing directly to a commit
LATEST_SHA="$LATEST_TAG_SHA"
LATEST_SHA=$(curl -sL "https://api.github.com/repos/cloudflare/lol-html/git/tags/$LATEST_TAG_SHA" | jq -r '.object.sha')
if [ -z "$LATEST_SHA" ] || [ "$LATEST_SHA" = "null" ]; then
echo "Error: Could not fetch SHA for tag $LATEST_TAG @ $LATEST_TAG_SHA"
exit 1
fi
if ! [[ $LATEST_SHA =~ ^[0-9a-f]{40}$ ]]; then

View File

@@ -50,32 +50,15 @@ jobs:
exit 1
fi
# Get the tag reference, which contains both SHA and type
TAG_REF=$(curl -sL "https://api.github.com/repos/litespeedtech/ls-hpack/git/refs/tags/$LATEST_TAG")
if [ -z "$TAG_REF" ]; then
echo "Error: Could not fetch tag reference for $LATEST_TAG"
exit 1
fi
LATEST_TAG_SHA=$(echo "$TAG_REF" | jq -r '.object.sha')
TAG_TYPE=$(echo "$TAG_REF" | jq -r '.object.type')
LATEST_TAG_SHA=$(curl -sL "https://api.github.com/repos/litespeedtech/ls-hpack/git/refs/tags/$LATEST_TAG" | jq -r '.object.sha')
if [ -z "$LATEST_TAG_SHA" ] || [ "$LATEST_TAG_SHA" = "null" ]; then
echo "Error: Could not fetch SHA for tag $LATEST_TAG"
exit 1
fi
# If it's an annotated tag, we need to dereference it to get the commit SHA
# If it's a lightweight tag, the SHA already points to the commit
if [ "$TAG_TYPE" = "tag" ]; then
LATEST_SHA=$(curl -sL "https://api.github.com/repos/litespeedtech/ls-hpack/git/tags/$LATEST_TAG_SHA" | jq -r '.object.sha')
if [ -z "$LATEST_SHA" ] || [ "$LATEST_SHA" = "null" ]; then
echo "Error: Could not fetch commit SHA for annotated tag $LATEST_TAG"
exit 1
fi
else
# For lightweight tags, the SHA is already the commit SHA
LATEST_SHA="$LATEST_TAG_SHA"
LATEST_SHA=$(curl -sL "https://api.github.com/repos/litespeedtech/ls-hpack/git/tags/$LATEST_TAG_SHA" | jq -r '.object.sha')
if [ -z "$LATEST_SHA" ] || [ "$LATEST_SHA" = "null" ]; then
echo "Error: Could not fetch SHA for tag $LATEST_TAG @ $LATEST_TAG_SHA"
exit 1
fi
if ! [[ $LATEST_SHA =~ ^[0-9a-f]{40}$ ]]; then

4
.gitignore vendored
View File

@@ -184,6 +184,4 @@ codegen-for-zig-team.tar.gz
*.sock
scratch*.{js,ts,tsx,cjs,mjs}
*.bun-build
scripts/lldb-inline
*.bun-build

3
.vscode/launch.json generated vendored
View File

@@ -22,9 +22,6 @@
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_DEBUG_jest": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "1",
// "BUN_JSC_validateExceptionChecks": "1",
// "BUN_JSC_dumpSimulatedThrows": "1",
// "BUN_JSC_unexpectedExceptionStackTraceLimit": "20",
},
"console": "internalConsole",
"sourceMap": {

View File

@@ -168,5 +168,5 @@
"WebKit/WebInspectorUI": true,
},
"git.detectSubmodules": false,
"bun.test.customScript": "./build/debug/bun-debug test",
// "bun.test.customScript": "./build/debug/bun-debug test"
}

View File

@@ -6,7 +6,7 @@ This is the Bun repository - an all-in-one JavaScript runtime & toolkit designed
- **Build debug version**: `bun bd`
- Creates a debug build at `./build/debug/bun-debug`
- **CRITICAL**: DO NOT set a build timeout. Compilation takes ~5 minutes. Be patient.
- Compilation takes ~5 minutes. Don't timeout, be patient.
- **Run tests with your debug build**: `bun bd test <test-file>`
- **CRITICAL**: Never use `bun test` directly - it won't include your changes
- **Run any command with debug build**: `bun bd <command>`
@@ -43,12 +43,7 @@ Tests use Bun's Jest-compatible test runner with proper test fixtures:
```typescript
import { test, expect } from "bun:test";
import {
bunEnv,
bunExe,
normalizeBunSnapshot,
tempDirWithFiles,
} from "harness";
import { bunEnv, bunExe, tempDirWithFiles } from "harness";
test("my feature", async () => {
// Create temp directory with test files
@@ -61,25 +56,19 @@ test("my feature", async () => {
cmd: [bunExe(), "index.js"],
env: bunEnv,
cwd: dir,
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([
proc.stdout.text(),
proc.stderr.text(),
new Response(proc.stdout).text(),
new Response(proc.stderr).text(),
proc.exited,
]);
expect(exitCode).toBe(0);
// Prefer snapshot tests over expect(stdout).toBe("hello\n");
expect(normalizeBunSnapshot(stdout, dir)).toMatchInlineSnapshot(`"hello"`);
expect(stdout).toBe("hello\n");
});
```
- 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.
## Code Architecture
### Language Structure
@@ -144,6 +133,7 @@ test("my feature", async () => {
When implementing JavaScript classes in C++:
1. Create three classes if there's a public constructor:
- `class Foo : public JSC::JSDestructibleObject` (if has C++ fields)
- `class FooPrototype : public JSC::JSNonFinalObject`
- `class FooConstructor : public JSC::InternalFunction`
@@ -203,6 +193,7 @@ Built-in JavaScript modules use special syntax and are organized as:
```
3. **Debug helpers**:
- `$debug()` - Like console.log but stripped in release builds
- `$assert()` - Assertions stripped in release builds
- `if($debug) {}` - Check if debug env var is set
@@ -230,17 +221,15 @@ bun ci
## Important Development Notes
1. **Never use `bun test` or `bun <file>` directly** - always use `bun bd test` or `bun bd <command>`. `bun bd` compiles & runs the debug build.
2. **All changes must be tested** - if you're not testing your changes, you're not done.
3. **Get your tests to pass**. If you didn't run the tests, your code does not work.
4. **Follow existing code style** - check neighboring files for patterns
5. **Create tests in the right folder** in `test/` and the test must end in `.test.ts` or `.test.tsx`
6. **Use absolute paths** - Always use absolute paths in file operations
7. **Avoid shell commands** - Don't use `find` or `grep` in tests; use Bun's Glob and built-in tools
8. **Memory management** - In Zig code, be careful with allocators and use defer for cleanup
9. **Cross-platform** - Run `bun run zig:check-all` to compile the Zig code on all platforms when making platform-specific changes
10. **Debug builds** - Use `BUN_DEBUG_QUIET_LOGS=1` to disable debug logging, or `BUN_DEBUG_<scope>=1` to enable specific scopes
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.
2. **Use `await using`** for proper resource cleanup with Bun APIs (Bun.spawn, Bun.serve, Bun.connect, etc.)
3. **Follow existing code style** - check neighboring files for patterns
4. **Create regression tests** in `test/regression/issue/` when fixing bugs
5. **Use absolute paths** - Always use absolute paths in file operations
6. **Avoid shell commands** - Don't use `find` or `grep` in tests; use Bun's Glob and built-in tools
7. **Memory management** - In Zig code, be careful with allocators and use defer for cleanup
8. **Cross-platform** - Test on macOS, Linux, and Windows when making platform-specific changes
9. **Debug builds** - Use `BUN_DEBUG_QUIET_LOGS=1` to disable debug logging, or `BUN_DEBUG_<scope>=1` to enable specific scopes
10. **Transpiled source** - Find transpiled files in `/tmp/bun-debug-src/` for debugging
## Key APIs and Features

2
LATEST
View File

@@ -1 +1 @@
1.2.21
1.2.19

2046
Makefile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -15,13 +15,11 @@
"eventemitter3": "^5.0.0",
"execa": "^8.0.1",
"fast-glob": "3.3.1",
"fastify": "^5.0.0",
"fdir": "^6.1.0",
"mitata": "^1.0.25",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"string-width": "7.1.0",
"strip-ansi": "^7.1.0",
"tinycolor2": "^1.6.0",
"zx": "^7.2.3",
},
@@ -95,18 +93,6 @@
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.14.54", "", { "os": "linux", "cpu": "none" }, "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw=="],
"@fastify/ajv-compiler": ["@fastify/ajv-compiler@4.0.2", "", { "dependencies": { "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "fast-uri": "^3.0.0" } }, "sha512-Rkiu/8wIjpsf46Rr+Fitd3HRP+VsxUFDDeag0hs9L0ksfnwx2g7SPQQTFL0E8Qv+rfXzQOxBJnjUB9ITUDjfWQ=="],
"@fastify/error": ["@fastify/error@4.2.0", "", {}, "sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ=="],
"@fastify/fast-json-stringify-compiler": ["@fastify/fast-json-stringify-compiler@5.0.3", "", { "dependencies": { "fast-json-stringify": "^6.0.0" } }, "sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ=="],
"@fastify/forwarded": ["@fastify/forwarded@3.0.0", "", {}, "sha512-kJExsp4JCms7ipzg7SJ3y8DwmePaELHxKYtg+tZow+k0znUTf3cb+npgyqm8+ATZOdmfgfydIebPDWM172wfyA=="],
"@fastify/merge-json-schemas": ["@fastify/merge-json-schemas@0.2.1", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A=="],
"@fastify/proxy-addr": ["@fastify/proxy-addr@5.0.0", "", { "dependencies": { "@fastify/forwarded": "^3.0.0", "ipaddr.js": "^2.1.0" } }, "sha512-37qVVA1qZ5sgH7KpHkkC4z9SK6StIsIcOmpjvMPXNb3vx2GQxhZocogVYbr2PbbeLCQxYIPDok307xEvRZOzGA=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.1.1", "", { "dependencies": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w=="],
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.0", "", {}, "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w=="],
@@ -157,20 +143,10 @@
"@types/which": ["@types/which@3.0.3", "", {}, "sha512-2C1+XoY0huExTbs8MQv1DuS5FS86+SEjdM9F/+GS61gg5Hqbtj8ZiDSx8MfWcyei907fIPbfPGCOrNUTnVHY1g=="],
"abstract-logging": ["abstract-logging@2.0.1", "", {}, "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="],
"ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
"ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
"ansi-regex": ["ansi-regex@6.0.1", "", {}, "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA=="],
"ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
"atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="],
"avvio": ["avvio@9.1.0", "", { "dependencies": { "@fastify/error": "^4.0.0", "fastq": "^1.17.1" } }, "sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw=="],
"benchmark": ["benchmark@2.1.4", "", { "dependencies": { "lodash": "^4.17.4", "platform": "^1.3.3" } }, "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ=="],
"braces": ["braces@3.0.2", "", { "dependencies": { "fill-range": "^7.0.1" } }, "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A=="],
@@ -191,16 +167,12 @@
"convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="],
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
"cross-spawn": ["cross-spawn@7.0.3", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w=="],
"data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
"debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="],
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
"dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="],
"duplexer": ["duplexer@0.1.2", "", {}, "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg=="],
@@ -261,22 +233,10 @@
"execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="],
"fast-json-stringify": ["fast-json-stringify@6.0.1", "", { "dependencies": { "@fastify/merge-json-schemas": "^0.2.0", "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "fast-uri": "^3.0.0", "json-schema-ref-resolver": "^2.0.0", "rfdc": "^1.2.0" } }, "sha512-s7SJE83QKBZwg54dIbD5rCtzOBVD43V1ReWXXYqBgwCwHLYAAT0RQc/FmrQglXqWPpz6omtryJQOau5jI4Nrvg=="],
"fast-querystring": ["fast-querystring@1.1.2", "", { "dependencies": { "fast-decode-uri-component": "^1.0.1" } }, "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg=="],
"fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="],
"fast-uri": ["fast-uri@3.0.6", "", {}, "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="],
"fastify": ["fastify@5.5.0", "", { "dependencies": { "@fastify/ajv-compiler": "^4.0.0", "@fastify/error": "^4.0.0", "@fastify/fast-json-stringify-compiler": "^5.0.0", "@fastify/proxy-addr": "^5.0.0", "abstract-logging": "^2.0.1", "avvio": "^9.0.0", "fast-json-stringify": "^6.0.0", "find-my-way": "^9.0.0", "light-my-request": "^6.0.0", "pino": "^9.0.0", "process-warning": "^5.0.0", "rfdc": "^1.3.1", "secure-json-parse": "^4.0.0", "semver": "^7.6.0", "toad-cache": "^3.7.0" } }, "sha512-ZWSWlzj3K/DcULCnCjEiC2zn2FBPdlZsSA/pnPa/dbUfLvxkD/Nqmb0XXMXLrWkeM4uQPUvjdJpwtXmTfriXqw=="],
"fastq": ["fastq@1.15.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw=="],
"fdir": ["fdir@6.1.0", "", { "peerDependencies": { "picomatch": "2.x" } }, "sha512-274qhz5PxNnA/fybOu6apTCUnM0GnO3QazB6VH+oag/7DQskdYq8lm07ZSm90kEQuWYH5GvjAxGruuHrEr0bcg=="],
@@ -285,8 +245,6 @@
"fill-range": ["fill-range@7.0.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ=="],
"find-my-way": ["find-my-way@9.3.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", "safe-regex2": "^5.0.0" } }, "sha512-eRoFWQw+Yv2tuYlK2pjFS2jGXSxSppAs3hSQjfxVKxM5amECzIgYYc1FEI8ZmhSh/Ig+FrKEz43NLRKJjYCZVg=="],
"formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
"from": ["from@0.1.7", "", {}, "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g=="],
@@ -315,8 +273,6 @@
"ignore": ["ignore@5.3.0", "", {}, "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg=="],
"ipaddr.js": ["ipaddr.js@2.2.0", "", {}, "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA=="],
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
@@ -333,16 +289,10 @@
"jsesc": ["jsesc@2.5.2", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="],
"json-schema-ref-resolver": ["json-schema-ref-resolver@2.0.1", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-HG0SIB9X4J8bwbxCbnd5FfPEbcXAJYTi1pBJeP/QPON+w8ovSME8iRG+ElHNxZNX2Qh6eYn1GdzJFS4cDFfx0Q=="],
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
"jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="],
"light-my-request": ["light-my-request@6.6.0", "", { "dependencies": { "cookie": "^1.0.1", "process-warning": "^4.0.0", "set-cookie-parser": "^2.6.0" } }, "sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A=="],
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
@@ -373,8 +323,6 @@
"npm-run-path": ["npm-run-path@5.2.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg=="],
"on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="],
"onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
@@ -387,50 +335,24 @@
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"pino": ["pino@9.9.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-zxsRIQG9HzG+jEljmvmZupOMDUQ0Jpj0yAgE28jQvvrdYTlEaiGwelJpdndMl/MBuRr70heIj83QyqJUWaU8mQ=="],
"pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="],
"pino-std-serializers": ["pino-std-serializers@7.0.0", "", {}, "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA=="],
"platform": ["platform@1.3.6", "", {}, "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg=="],
"process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="],
"ps-tree": ["ps-tree@1.2.0", "", { "dependencies": { "event-stream": "=3.3.4" }, "bin": { "ps-tree": "./bin/ps-tree.js" } }, "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="],
"react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],
"react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="],
"real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="],
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
"ret": ["ret@0.5.0", "", {}, "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw=="],
"reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="],
"rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="],
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
"safe-regex2": ["safe-regex2@5.0.0", "", { "dependencies": { "ret": "~0.5.0" } }, "sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw=="],
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
"scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
"secure-json-parse": ["secure-json-parse@4.0.0", "", {}, "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA=="],
"semver": ["semver@6.3.0", "", { "bin": { "semver": "./bin/semver.js" } }, "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="],
"set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
@@ -441,12 +363,8 @@
"slash": ["slash@4.0.0", "", {}, "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew=="],
"sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="],
"split": ["split@0.3.3", "", { "dependencies": { "through": "2" } }, "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA=="],
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
"stream-combiner": ["stream-combiner@0.0.4", "", { "dependencies": { "duplexer": "~0.1.1" } }, "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw=="],
"string-width": ["string-width@7.1.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw=="],
@@ -457,8 +375,6 @@
"supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
"thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="],
"through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="],
"tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="],
@@ -467,8 +383,6 @@
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
"toad-cache": ["toad-cache@3.7.0", "", {}, "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw=="],
"undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
@@ -493,14 +407,8 @@
"ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
"avvio/fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
"cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"fastify/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"light-my-request/process-warning": ["process-warning@4.0.1", "", {}, "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q=="],
"npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
"ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],

View File

@@ -18,7 +18,6 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"string-width": "7.1.0",
"strip-ansi": "^7.1.0",
"tinycolor2": "^1.6.0",
"zx": "^7.2.3"
},

View File

@@ -1,77 +0,0 @@
// Benchmark for string fast path optimization in postMessage with Workers
import { bench, run } from "mitata";
import { Worker, isMainThread, parentPort } from "node:worker_threads";
// Test strings of different sizes
const strings = {
small: "Hello world",
medium: Buffer.alloc("Hello World!!!".length * 1024, "Hello World!!!").toString(),
large: Buffer.alloc("Hello World!!!".length * 1024 * 256, "Hello World!!!").toString(),
};
let worker;
let receivedCount = new Int32Array(new SharedArrayBuffer(4));
let sentCount = 0;
function createWorker() {
const workerCode = `
import { parentPort, workerData } from "node:worker_threads";
let int = workerData;
parentPort?.on("message", data => {
Atomics.add(int, 0, 1);
});
`;
worker = new Worker(workerCode, { eval: true, workerData: receivedCount });
worker.on("message", confirmationId => {});
worker.on("error", error => {
console.error("Worker error:", error);
});
}
// Initialize worker before running benchmarks
createWorker();
function fmt(int) {
if (int < 1000) {
return `${int} chars`;
}
if (int < 100000) {
return `${(int / 1024) | 0} KB`;
}
return `${(int / 1024 / 1024) | 0} MB`;
}
// Benchmark postMessage with pure strings (uses fast path)
bench("postMessage(" + fmt(strings.small.length) + " string)", async () => {
sentCount++;
worker.postMessage(strings.small);
});
bench("postMessage(" + fmt(strings.medium.length) + " string)", async () => {
sentCount++;
worker.postMessage(strings.medium);
});
bench("postMessage(" + fmt(strings.large.length) + " string)", async () => {
sentCount++;
worker.postMessage(strings.large);
});
await run();
await new Promise(resolve => setTimeout(resolve, 5000));
if (receivedCount[0] !== sentCount) {
throw new Error("Expected " + receivedCount[0] + " to equal " + sentCount);
}
// Cleanup worker
worker?.terminate();

View File

@@ -1,56 +0,0 @@
// Benchmark for string fast path optimization in postMessage and structuredClone
import { bench, run } from "mitata";
// Test strings of different sizes
const strings = {
small: "Hello world",
medium: "Hello World!!!".repeat(1024).split("").join(""),
large: "Hello World!!!".repeat(1024).repeat(1024).split("").join(""),
};
console.log("String fast path benchmark");
console.log("Comparing pure strings (fast path) vs objects containing strings (traditional)");
console.log("For structuredClone, pure strings should have constant time regardless of size.");
console.log("");
// Benchmark structuredClone with pure strings (uses fast path)
bench("structuredClone small string (fast path)", () => {
structuredClone(strings.small);
});
bench("structuredClone medium string (fast path)", () => {
structuredClone(strings.medium);
});
bench("structuredClone large string (fast path)", () => {
structuredClone(strings.large);
});
// Benchmark structuredClone with objects containing strings (traditional path)
bench("structuredClone object with small string", () => {
structuredClone({ str: strings.small });
});
bench("structuredClone object with medium string", () => {
structuredClone({ str: strings.medium });
});
bench("structuredClone object with large string", () => {
structuredClone({ str: strings.large });
});
// Multiple string cloning benchmark
bench("structuredClone 100 small strings", () => {
for (let i = 0; i < 100; i++) {
structuredClone(strings.small);
}
});
bench("structuredClone 100 small objects", () => {
for (let i = 0; i < 100; i++) {
structuredClone({ str: strings.small });
}
});
await run();

View File

@@ -28,4 +28,10 @@ bench("brotli compress stream", async () => {
await pipeline(source, compress);
});
bench("brotli decompress stream", async () => {
const source = Readable.from([compressed]);
const decompress = createBrotliDecompress();
await pipeline(source, decompress);
});
await run();

View File

@@ -1,37 +0,0 @@
import npmStripAnsi from "strip-ansi";
import { bench, run } from "../runner.mjs";
let bunStripANSI = null;
if (!process.env.FORCE_NPM) {
bunStripANSI = globalThis?.Bun?.stripANSI;
}
const stripANSI = bunStripANSI || npmStripAnsi;
const formatter = new Intl.NumberFormat();
const format = n => {
return formatter.format(n);
};
const inputs = [
["hello world", "no-ansi"],
["\x1b[31mred\x1b[39m", "ansi"],
["a".repeat(1024 * 16), "long-no-ansi"],
["\x1b[31mred\x1b[39m".repeat(1024 * 16), "long-ansi"],
];
const maxInputLength = Math.max(...inputs.map(([input]) => input.length));
for (const [input, textLabel] of inputs) {
const label = bunStripANSI ? "Bun.stripANSI" : "npm/strip-ansi";
const name = `${label} ${format(input.length).padStart(format(maxInputLength).length, " ")} chars ${textLabel}`;
bench(name, () => {
stripANSI(input);
});
if (bunStripANSI && bunStripANSI(input) !== npmStripAnsi(input)) {
throw new Error("strip-ansi mismatch");
}
}
await run();

View File

@@ -1,19 +0,0 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "yaml-benchmark",
"dependencies": {
"js-yaml": "^4.1.0",
"yaml": "^2.8.1",
},
},
},
"packages": {
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
"yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="],
}
}

View File

@@ -1,8 +0,0 @@
{
"name": "yaml-benchmark",
"version": "1.0.0",
"dependencies": {
"js-yaml": "^4.1.0",
"yaml": "^2.8.1"
}
}

View File

@@ -1,368 +0,0 @@
import { bench, group, run } from "../runner.mjs";
import jsYaml from "js-yaml";
import yaml from "yaml";
// Small YAML document
const smallYaml = `
name: John Doe
age: 30
email: john@example.com
active: true
`;
// Medium YAML document with nested structures
const mediumYaml = `
company: Acme Corp
employees:
- name: John Doe
age: 30
position: Developer
skills:
- JavaScript
- TypeScript
- Node.js
- name: Jane Smith
age: 28
position: Designer
skills:
- Figma
- Photoshop
- Illustrator
- name: Bob Johnson
age: 35
position: Manager
skills:
- Leadership
- Communication
- Planning
settings:
database:
host: localhost
port: 5432
name: mydb
cache:
enabled: true
ttl: 3600
`;
// Large YAML document with complex structures
const largeYaml = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
env:
- name: ENV_VAR_1
value: "value1"
- name: ENV_VAR_2
value: "value2"
volumeMounts:
- name: config
mountPath: /etc/nginx
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "0.5"
memory: "512Mi"
volumes:
- name: config
configMap:
name: nginx-config
items:
- key: nginx.conf
path: nginx.conf
- key: mime.types
path: mime.types
nodeSelector:
disktype: ssd
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
- key: "key2"
operator: "Exists"
effect: "NoExecute"
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/e2e-az-name
operator: In
values:
- e2e-az1
- e2e-az2
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web-store
topologyKey: kubernetes.io/hostname
`;
// YAML with anchors and references
const yamlWithAnchors = `
defaults: &defaults
adapter: postgresql
host: localhost
port: 5432
development:
<<: *defaults
database: dev_db
test:
<<: *defaults
database: test_db
production:
<<: *defaults
database: prod_db
host: prod.example.com
`;
// Array of items
const arrayYaml = `
- id: 1
name: Item 1
price: 10.99
tags: [electronics, gadgets]
- id: 2
name: Item 2
price: 25.50
tags: [books, education]
- id: 3
name: Item 3
price: 5.00
tags: [food, snacks]
- id: 4
name: Item 4
price: 100.00
tags: [electronics, computers]
- id: 5
name: Item 5
price: 15.75
tags: [clothing, accessories]
`;
// Multiline strings
const multilineYaml = `
description: |
This is a multiline string
that preserves line breaks
and indentation.
It can contain multiple paragraphs
and special characters: !@#$%^&*()
folded: >
This is a folded string
where line breaks are converted
to spaces unless there are
empty lines like above.
plain: This is a plain string
quoted: "This is a quoted string with \\"escapes\\""
literal: 'This is a literal string with ''quotes'''
`;
// Numbers and special values
const numbersYaml = `
integer: 42
negative: -17
float: 3.14159
scientific: 1.23e-4
infinity: .inf
negativeInfinity: -.inf
notANumber: .nan
octal: 0o755
hex: 0xFF
binary: 0b1010
`;
// Dates and timestamps
const datesYaml = `
date: 2024-01-15
datetime: 2024-01-15T10:30:00Z
timestamp: 2024-01-15 10:30:00.123456789 -05:00
canonical: 2024-01-15T10:30:00.123456789Z
`;
// Parse benchmarks
group("parse small YAML", () => {
if (typeof Bun !== "undefined" && Bun.YAML) {
bench("Bun.YAML.parse", () => {
globalThis.result = Bun.YAML.parse(smallYaml);
});
}
bench("js-yaml.load", () => {
globalThis.result = jsYaml.load(smallYaml);
});
bench("yaml.parse", () => {
globalThis.result = yaml.parse(smallYaml);
});
});
group("parse medium YAML", () => {
if (typeof Bun !== "undefined" && Bun.YAML) {
bench("Bun.YAML.parse", () => {
globalThis.result = Bun.YAML.parse(mediumYaml);
});
}
bench("js-yaml.load", () => {
globalThis.result = jsYaml.load(mediumYaml);
});
bench("yaml.parse", () => {
globalThis.result = yaml.parse(mediumYaml);
});
});
group("parse large YAML", () => {
if (typeof Bun !== "undefined" && Bun.YAML) {
bench("Bun.YAML.parse", () => {
globalThis.result = Bun.YAML.parse(largeYaml);
});
}
bench("js-yaml.load", () => {
globalThis.result = jsYaml.load(largeYaml);
});
bench("yaml.parse", () => {
globalThis.result = yaml.parse(largeYaml);
});
});
group("parse YAML with anchors", () => {
if (typeof Bun !== "undefined" && Bun.YAML) {
bench("Bun.YAML.parse", () => {
globalThis.result = Bun.YAML.parse(yamlWithAnchors);
});
}
bench("js-yaml.load", () => {
globalThis.result = jsYaml.load(yamlWithAnchors);
});
bench("yaml.parse", () => {
globalThis.result = yaml.parse(yamlWithAnchors);
});
});
group("parse YAML array", () => {
if (typeof Bun !== "undefined" && Bun.YAML) {
bench("Bun.YAML.parse", () => {
globalThis.result = Bun.YAML.parse(arrayYaml);
});
}
bench("js-yaml.load", () => {
globalThis.result = jsYaml.load(arrayYaml);
});
bench("yaml.parse", () => {
globalThis.result = yaml.parse(arrayYaml);
});
});
group("parse YAML with multiline strings", () => {
if (typeof Bun !== "undefined" && Bun.YAML) {
bench("Bun.YAML.parse", () => {
globalThis.result = Bun.YAML.parse(multilineYaml);
});
}
bench("js-yaml.load", () => {
globalThis.result = jsYaml.load(multilineYaml);
});
bench("yaml.parse", () => {
globalThis.result = yaml.parse(multilineYaml);
});
});
group("parse YAML with numbers", () => {
if (typeof Bun !== "undefined" && Bun.YAML) {
bench("Bun.YAML.parse", () => {
globalThis.result = Bun.YAML.parse(numbersYaml);
});
}
bench("js-yaml.load", () => {
globalThis.result = jsYaml.load(numbersYaml);
});
bench("yaml.parse", () => {
globalThis.result = yaml.parse(numbersYaml);
});
});
group("parse YAML with dates", () => {
if (typeof Bun !== "undefined" && Bun.YAML) {
bench("Bun.YAML.parse", () => {
globalThis.result = Bun.YAML.parse(datesYaml);
});
}
bench("js-yaml.load", () => {
globalThis.result = jsYaml.load(datesYaml);
});
bench("yaml.parse", () => {
globalThis.result = yaml.parse(datesYaml);
});
});
// // Stringify benchmarks
// const smallObjJs = jsYaml.load(smallYaml);
// const mediumObjJs = jsYaml.load(mediumYaml);
// const largeObjJs = jsYaml.load(largeYaml);
// group("stringify small object", () => {
// bench("js-yaml.dump", () => {
// globalThis.result = jsYaml.dump(smallObjJs);
// });
// });
// group("stringify medium object", () => {
// bench("js-yaml.dump", () => {
// globalThis.result = jsYaml.dump(mediumObjJs);
// });
// });
// group("stringify large object", () => {
// bench("js-yaml.dump", () => {
// globalThis.result = jsYaml.dump(largeObjJs);
// });
// });
await run();

213
bun.lock
View File

@@ -6,8 +6,6 @@
"devDependencies": {
"@lezer/common": "^1.2.3",
"@lezer/cpp": "^1.1.3",
"@types/bun": "workspace:*",
"bun-tracestrings": "github:oven-sh/bun.report#912ca63e26c51429d3e6799aa2a6ab079b188fd8",
"esbuild": "^0.21.4",
"mitata": "^0.1.11",
"peechy": "0.4.34",
@@ -16,7 +14,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"source-map-js": "^1.2.0",
"typescript": "5.9.2",
"typescript": "^5.7.2",
},
},
"packages/@types/bun": {
@@ -33,6 +31,7 @@
},
"devDependencies": {
"@types/react": "^19",
"typescript": "^5.0.2",
},
"peerDependencies": {
"@types/react": "^19",
@@ -40,8 +39,8 @@
},
},
"overrides": {
"bun-types": "workspace:packages/bun-types",
"@types/bun": "workspace:packages/@types/bun",
"bun-types": "workspace:packages/bun-types",
},
"packages": {
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
@@ -98,183 +97,41 @@
"@lezer/lr": ["@lezer/lr@1.4.2", "", { "dependencies": { "@lezer/common": "^1.0.0" } }, "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA=="],
"@octokit/app": ["@octokit/app@14.1.0", "", { "dependencies": { "@octokit/auth-app": "^6.0.0", "@octokit/auth-unauthenticated": "^5.0.0", "@octokit/core": "^5.0.0", "@octokit/oauth-app": "^6.0.0", "@octokit/plugin-paginate-rest": "^9.0.0", "@octokit/types": "^12.0.0", "@octokit/webhooks": "^12.0.4" } }, "sha512-g3uEsGOQCBl1+W1rgfwoRFUIR6PtvB2T1E4RpygeUU5LrLvlOqcxrt5lfykIeRpUPpupreGJUYl70fqMDXdTpw=="],
"@octokit/auth-app": ["@octokit/auth-app@6.1.4", "", { "dependencies": { "@octokit/auth-oauth-app": "^7.1.0", "@octokit/auth-oauth-user": "^4.1.0", "@octokit/request": "^8.3.1", "@octokit/request-error": "^5.1.0", "@octokit/types": "^13.1.0", "deprecation": "^2.3.1", "lru-cache": "npm:@wolfy1339/lru-cache@^11.0.2-patch.1", "universal-github-app-jwt": "^1.1.2", "universal-user-agent": "^6.0.0" } }, "sha512-QkXkSOHZK4dA5oUqY5Dk3S+5pN2s1igPjEASNQV8/vgJgW034fQWR16u7VsNOK/EljA00eyjYF5mWNxWKWhHRQ=="],
"@octokit/auth-oauth-app": ["@octokit/auth-oauth-app@7.1.0", "", { "dependencies": { "@octokit/auth-oauth-device": "^6.1.0", "@octokit/auth-oauth-user": "^4.1.0", "@octokit/request": "^8.3.1", "@octokit/types": "^13.0.0", "@types/btoa-lite": "^1.0.0", "btoa-lite": "^1.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-w+SyJN/b0l/HEb4EOPRudo7uUOSW51jcK1jwLa+4r7PA8FPFpoxEnHBHMITqCsc/3Vo2qqFjgQfz/xUUvsSQnA=="],
"@octokit/auth-oauth-device": ["@octokit/auth-oauth-device@6.1.0", "", { "dependencies": { "@octokit/oauth-methods": "^4.1.0", "@octokit/request": "^8.3.1", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-FNQ7cb8kASufd6Ej4gnJ3f1QB5vJitkoV1O0/g6e6lUsQ7+VsSNRHRmFScN2tV4IgKA12frrr/cegUs0t+0/Lw=="],
"@octokit/auth-oauth-user": ["@octokit/auth-oauth-user@4.1.0", "", { "dependencies": { "@octokit/auth-oauth-device": "^6.1.0", "@octokit/oauth-methods": "^4.1.0", "@octokit/request": "^8.3.1", "@octokit/types": "^13.0.0", "btoa-lite": "^1.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-FrEp8mtFuS/BrJyjpur+4GARteUCrPeR/tZJzD8YourzoVhRics7u7we/aDcKv+yywRNwNi/P4fRi631rG/OyQ=="],
"@octokit/auth-token": ["@octokit/auth-token@4.0.0", "", {}, "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="],
"@octokit/auth-unauthenticated": ["@octokit/auth-unauthenticated@5.0.1", "", { "dependencies": { "@octokit/request-error": "^5.0.0", "@octokit/types": "^12.0.0" } }, "sha512-oxeWzmBFxWd+XolxKTc4zr+h3mt+yofn4r7OfoIkR/Cj/o70eEGmPsFbueyJE2iBAGpjgTnEOKM3pnuEGVmiqg=="],
"@octokit/core": ["@octokit/core@5.2.2", "", { "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" } }, "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg=="],
"@octokit/endpoint": ["@octokit/endpoint@9.0.6", "", { "dependencies": { "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw=="],
"@octokit/graphql": ["@octokit/graphql@7.1.1", "", { "dependencies": { "@octokit/request": "^8.4.1", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g=="],
"@octokit/oauth-app": ["@octokit/oauth-app@6.1.0", "", { "dependencies": { "@octokit/auth-oauth-app": "^7.0.0", "@octokit/auth-oauth-user": "^4.0.0", "@octokit/auth-unauthenticated": "^5.0.0", "@octokit/core": "^5.0.0", "@octokit/oauth-authorization-url": "^6.0.2", "@octokit/oauth-methods": "^4.0.0", "@types/aws-lambda": "^8.10.83", "universal-user-agent": "^6.0.0" } }, "sha512-nIn/8eUJ/BKUVzxUXd5vpzl1rwaVxMyYbQkNZjHrF7Vk/yu98/YDF/N2KeWO7uZ0g3b5EyiFXFkZI8rJ+DH1/g=="],
"@octokit/oauth-authorization-url": ["@octokit/oauth-authorization-url@6.0.2", "", {}, "sha512-CdoJukjXXxqLNK4y/VOiVzQVjibqoj/xHgInekviUJV73y/BSIcwvJ/4aNHPBPKcPWFnd4/lO9uqRV65jXhcLA=="],
"@octokit/oauth-methods": ["@octokit/oauth-methods@4.1.0", "", { "dependencies": { "@octokit/oauth-authorization-url": "^6.0.2", "@octokit/request": "^8.3.1", "@octokit/request-error": "^5.1.0", "@octokit/types": "^13.0.0", "btoa-lite": "^1.0.0" } }, "sha512-4tuKnCRecJ6CG6gr0XcEXdZtkTDbfbnD5oaHBmLERTjTMZNi2CbfEHZxPU41xXLDG4DfKf+sonu00zvKI9NSbw=="],
"@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
"@octokit/plugin-paginate-graphql": ["@octokit/plugin-paginate-graphql@4.0.1", "", { "peerDependencies": { "@octokit/core": ">=5" } }, "sha512-R8ZQNmrIKKpHWC6V2gum4x9LG2qF1RxRjo27gjQcG3j+vf2tLsEfE7I/wRWEPzYMaenr1M+qDAtNcwZve1ce1A=="],
"@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@11.4.4-cjs.2", "", { "dependencies": { "@octokit/types": "^13.7.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw=="],
"@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1", "", { "dependencies": { "@octokit/types": "^13.8.0" }, "peerDependencies": { "@octokit/core": "^5" } }, "sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ=="],
"@octokit/plugin-retry": ["@octokit/plugin-retry@6.1.0", "", { "dependencies": { "@octokit/request-error": "^5.0.0", "@octokit/types": "^13.0.0", "bottleneck": "^2.15.3" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-WrO3bvq4E1Xh1r2mT9w6SDFg01gFmP81nIG77+p/MqW1JeXXgL++6umim3t6x0Zj5pZm3rXAN+0HEjmmdhIRig=="],
"@octokit/plugin-throttling": ["@octokit/plugin-throttling@8.2.0", "", { "dependencies": { "@octokit/types": "^12.2.0", "bottleneck": "^2.15.3" }, "peerDependencies": { "@octokit/core": "^5.0.0" } }, "sha512-nOpWtLayKFpgqmgD0y3GqXafMFuKcA4tRPZIfu7BArd2lEZeb1988nhWhwx4aZWmjDmUfdgVf7W+Tt4AmvRmMQ=="],
"@octokit/request": ["@octokit/request@8.4.1", "", { "dependencies": { "@octokit/endpoint": "^9.0.6", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw=="],
"@octokit/request-error": ["@octokit/request-error@5.1.1", "", { "dependencies": { "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g=="],
"@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
"@octokit/webhooks": ["@octokit/webhooks@12.3.2", "", { "dependencies": { "@octokit/request-error": "^5.0.0", "@octokit/webhooks-methods": "^4.1.0", "@octokit/webhooks-types": "7.6.1", "aggregate-error": "^3.1.0" } }, "sha512-exj1MzVXoP7xnAcAB3jZ97pTvVPkQF9y6GA/dvYC47HV7vLv+24XRS6b/v/XnyikpEuvMhugEXdGtAlU086WkQ=="],
"@octokit/webhooks-methods": ["@octokit/webhooks-methods@5.1.1", "", {}, "sha512-NGlEHZDseJTCj8TMMFehzwa9g7On4KJMPVHDSrHxCQumL6uSQR8wIkP/qesv52fXqV1BPf4pTxwtS31ldAt9Xg=="],
"@octokit/webhooks-types": ["@octokit/webhooks-types@7.6.1", "", {}, "sha512-S8u2cJzklBC0FgTwWVLaM8tMrDuDMVE4xiTK4EYXM9GntyvrdbSoxqDQa+Fh57CCNApyIpyeqPhhFEmHPfrXgw=="],
"@sentry/types": ["@sentry/types@7.120.4", "", {}, "sha512-cUq2hSSe6/qrU6oZsEP4InMI5VVdD86aypE+ENrQ6eZEVLTCYm1w6XhW1NvIu3UuWh7gZec4a9J7AFpYxki88Q=="],
"@types/aws-lambda": ["@types/aws-lambda@8.10.152", "", {}, "sha512-soT/c2gYBnT5ygwiHPmd9a1bftj462NWVk2tKCc1PYHSIacB2UwbTS2zYG4jzag1mRDuzg/OjtxQjQ2NKRB6Rw=="],
"@types/btoa-lite": ["@types/btoa-lite@1.0.2", "", {}, "sha512-ZYbcE2x7yrvNFJiU7xJGrpF/ihpkM7zKgw8bha3LNJSesvTtUNxbpzaT7WXBIryf6jovisrxTBvymxMeLLj1Mg=="],
"@types/bun": ["@types/bun@workspace:packages/@types/bun"],
"@types/jsonwebtoken": ["@types/jsonwebtoken@9.0.10", "", { "dependencies": { "@types/ms": "*", "@types/node": "*" } }, "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA=="],
"@types/node": ["@types/node@22.15.18", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg=="],
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
"@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="],
"@types/react": ["@types/react@19.1.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="],
"aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="],
"before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="],
"bottleneck": ["bottleneck@2.19.5", "", {}, "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="],
"btoa-lite": ["btoa-lite@1.0.0", "", {}, "sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA=="],
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
"bun-tracestrings": ["bun-tracestrings@github:oven-sh/bun.report#912ca63", { "dependencies": { "@octokit/webhooks-methods": "^5.1.0", "@sentry/types": "^7.112.2", "@types/bun": "^1.2.6", "html-minifier": "^4.0.0", "lightningcss": "^1.24.1", "marked": "^12.0.1", "octokit": "^3.2.0", "prettier": "^3.2.5", "typescript": "^5.0.0" }, "bin": { "ci-remap-server": "./bin/ci-remap-server.ts" } }, "oven-sh-bun.report-912ca63"],
"@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
"bun-types": ["bun-types@workspace:packages/bun-types"],
"camel-case": ["camel-case@3.0.0", "", { "dependencies": { "no-case": "^2.2.0", "upper-case": "^1.1.1" } }, "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w=="],
"camel-case": ["camel-case@4.1.2", "", { "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" } }, "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw=="],
"capital-case": ["capital-case@1.0.4", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", "upper-case-first": "^2.0.2" } }, "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A=="],
"change-case": ["change-case@4.1.2", "", { "dependencies": { "camel-case": "^4.1.2", "capital-case": "^1.0.4", "constant-case": "^3.0.4", "dot-case": "^3.0.4", "header-case": "^2.0.4", "no-case": "^3.0.4", "param-case": "^3.0.4", "pascal-case": "^3.1.2", "path-case": "^3.0.4", "sentence-case": "^3.0.4", "snake-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A=="],
"clean-css": ["clean-css@4.2.4", "", { "dependencies": { "source-map": "~0.6.0" } }, "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A=="],
"clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="],
"commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
"constant-case": ["constant-case@3.0.4", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", "upper-case": "^2.0.2" } }, "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="],
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
"dot-case": ["dot-case@3.0.4", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w=="],
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
"esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
"he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="],
"header-case": ["header-case@2.0.4", "", { "dependencies": { "capital-case": "^1.0.4", "tslib": "^2.0.3" } }, "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q=="],
"html-minifier": ["html-minifier@4.0.0", "", { "dependencies": { "camel-case": "^3.0.0", "clean-css": "^4.2.1", "commander": "^2.19.0", "he": "^1.2.0", "param-case": "^2.1.1", "relateurl": "^0.2.7", "uglify-js": "^3.5.1" }, "bin": { "html-minifier": "./cli.js" } }, "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig=="],
"indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="],
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"jsonwebtoken": ["jsonwebtoken@9.0.2", "", { "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ=="],
"jwa": ["jwa@1.4.2", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw=="],
"jws": ["jws@3.2.2", "", { "dependencies": { "jwa": "^1.4.1", "safe-buffer": "^5.0.1" } }, "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA=="],
"lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.1", "", { "os": "linux", "cpu": "arm" }, "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="],
"lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="],
"lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="],
"lodash.isinteger": ["lodash.isinteger@4.0.4", "", {}, "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="],
"lodash.isnumber": ["lodash.isnumber@3.0.3", "", {}, "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="],
"lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="],
"lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="],
"lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="],
"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=="],
"lower-case": ["lower-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="],
"lru-cache": ["@wolfy1339/lru-cache@11.0.2-patch.1", "", {}, "sha512-BgYZfL2ADCXKOw2wJtkM3slhHotawWkgIRRxq4wEybnZQPjvAp71SPX35xepMykTw8gXlzWcWPTY31hlbnRsDA=="],
"marked": ["marked@12.0.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q=="],
"mitata": ["mitata@0.1.14", "", {}, "sha512-8kRs0l636eT4jj68PFXOR2D5xl4m56T478g16SzUPOYgkzQU+xaw62guAQxzBPm+SXb15GQi1cCpDxJfkr4CSA=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"no-case": ["no-case@3.0.4", "", { "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg=="],
"octokit": ["octokit@3.2.2", "", { "dependencies": { "@octokit/app": "^14.0.2", "@octokit/core": "^5.0.0", "@octokit/oauth-app": "^6.0.0", "@octokit/plugin-paginate-graphql": "^4.0.0", "@octokit/plugin-paginate-rest": "11.4.4-cjs.2", "@octokit/plugin-rest-endpoint-methods": "13.3.2-cjs.1", "@octokit/plugin-retry": "^6.0.0", "@octokit/plugin-throttling": "^8.0.0", "@octokit/request-error": "^5.0.0", "@octokit/types": "^13.0.0", "@octokit/webhooks": "^12.3.1" } }, "sha512-7Abo3nADdja8l/aglU6Y3lpnHSfv0tw7gFPiqzry/yCU+2gTAX7R1roJ8hJrxIK+S1j+7iqRJXtmuHJ/UDsBhQ=="],
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
"param-case": ["param-case@2.1.1", "", { "dependencies": { "no-case": "^2.2.0" } }, "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w=="],
"param-case": ["param-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A=="],
"pascal-case": ["pascal-case@3.1.2", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g=="],
@@ -282,76 +139,30 @@
"peechy": ["peechy@0.4.34", "", { "dependencies": { "change-case": "^4.1.2" }, "bin": { "peechy": "cli.js" } }, "sha512-Cpke/cCqqZHhkyxz7mdqS8ZAGJFUi5icu3ZGqxm9GC7g2VrhH0tmjPhZoWHAN5ghw1m1wq5+2YvfbDSqgC4+Zg=="],
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
"prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="],
"prettier-plugin-organize-imports": ["prettier-plugin-organize-imports@4.2.0", "", { "peerDependencies": { "prettier": ">=2.0", "typescript": ">=2.9", "vue-tsc": "^2.1.0 || 3" }, "optionalPeers": ["vue-tsc"] }, "sha512-Zdy27UhlmyvATZi67BTnLcKTo8fm6Oik59Sz6H64PgZJVs6NJpPD1mT240mmJn62c98/QaL+r3kx9Q3gRpDajg=="],
"prettier-plugin-organize-imports": ["prettier-plugin-organize-imports@4.1.0", "", { "peerDependencies": { "prettier": ">=2.0", "typescript": ">=2.9", "vue-tsc": "^2.1.0" }, "optionalPeers": ["vue-tsc"] }, "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A=="],
"react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],
"react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="],
"relateurl": ["relateurl@0.2.7", "", {}, "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog=="],
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"sentence-case": ["sentence-case@3.0.4", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", "upper-case-first": "^2.0.2" } }, "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg=="],
"snake-case": ["snake-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg=="],
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="],
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
"undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="],
"universal-github-app-jwt": ["universal-github-app-jwt@1.2.0", "", { "dependencies": { "@types/jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.2" } }, "sha512-dncpMpnsKBk0eetwfN8D8OUHGfiDhhJ+mtsbMl+7PfW7mYjiH8LIcqRmYMtzYLgSh47HjfdBtrBwIQ/gizKR3g=="],
"universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="],
"upper-case": ["upper-case@1.1.3", "", {}, "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA=="],
"upper-case": ["upper-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg=="],
"upper-case-first": ["upper-case-first@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg=="],
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
"@octokit/app/@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@9.2.2", "", { "dependencies": { "@octokit/types": "^12.6.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ=="],
"@octokit/app/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
"@octokit/auth-unauthenticated/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
"@octokit/plugin-throttling/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
"@octokit/webhooks/@octokit/webhooks-methods": ["@octokit/webhooks-methods@4.1.0", "", {}, "sha512-zoQyKw8h9STNPqtm28UGOYFE7O6D4Il8VJwhAtMHFt2C4L0VQT1qGKLeefUOqHNs1mNRYSadVv7x0z8U2yyeWQ=="],
"camel-case/no-case": ["no-case@2.3.2", "", { "dependencies": { "lower-case": "^1.1.1" } }, "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ=="],
"change-case/camel-case": ["camel-case@4.1.2", "", { "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" } }, "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw=="],
"change-case/param-case": ["param-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A=="],
"constant-case/upper-case": ["upper-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg=="],
"param-case/no-case": ["no-case@2.3.2", "", { "dependencies": { "lower-case": "^1.1.1" } }, "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ=="],
"@octokit/app/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="],
"@octokit/auth-unauthenticated/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="],
"@octokit/plugin-throttling/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="],
"camel-case/no-case/lower-case": ["lower-case@1.1.4", "", {}, "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA=="],
"param-case/no-case/lower-case": ["lower-case@1.1.4", "", {}, "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA=="],
}
}

View File

@@ -57,23 +57,6 @@ else()
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}")
endif()
# Windows Code Signing Option
if(WIN32)
optionx(ENABLE_WINDOWS_CODESIGNING BOOL "Enable Windows code signing with DigiCert KeyLocker" DEFAULT OFF)
if(ENABLE_WINDOWS_CODESIGNING)
message(STATUS "Windows code signing: ENABLED")
# Check for required environment variables
if(NOT DEFINED ENV{SM_API_KEY})
message(WARNING "SM_API_KEY not set - code signing may fail")
endif()
if(NOT DEFINED ENV{SM_CLIENT_CERT_FILE})
message(WARNING "SM_CLIENT_CERT_FILE not set - code signing may fail")
endif()
endif()
endif()
if(LINUX)
if(EXISTS "/etc/alpine-release")
set(DEFAULT_ABI "musl")
@@ -119,11 +102,6 @@ else()
endif()
optionx(ENABLE_ASAN BOOL "If ASAN support should be enabled" DEFAULT ${DEFAULT_ASAN})
optionx(ENABLE_ZIG_ASAN BOOL "If Zig ASAN support should be enabled" DEFAULT ${ENABLE_ASAN})
if (NOT ENABLE_ASAN)
set(ENABLE_ZIG_ASAN OFF)
endif()
if(RELEASE AND LINUX AND CI AND NOT ENABLE_ASSERTIONS AND NOT ENABLE_ASAN)
set(DEFAULT_LTO ON)

View File

@@ -42,7 +42,6 @@ src/bun.js/bindings/DOMURL.cpp
src/bun.js/bindings/DOMWrapperWorld.cpp
src/bun.js/bindings/DoubleFormatter.cpp
src/bun.js/bindings/EncodeURIComponent.cpp
src/bun.js/bindings/EncodingTables.cpp
src/bun.js/bindings/ErrorCode.cpp
src/bun.js/bindings/ErrorStackFrame.cpp
src/bun.js/bindings/ErrorStackTrace.cpp
@@ -87,7 +86,6 @@ src/bun.js/bindings/JSNodePerformanceHooksHistogramConstructor.cpp
src/bun.js/bindings/JSNodePerformanceHooksHistogramPrototype.cpp
src/bun.js/bindings/JSPropertyIterator.cpp
src/bun.js/bindings/JSS3File.cpp
src/bun.js/bindings/JSSecrets.cpp
src/bun.js/bindings/JSSocketAddressDTO.cpp
src/bun.js/bindings/JSStringDecoder.cpp
src/bun.js/bindings/JSWrappingFunction.cpp
@@ -95,7 +93,6 @@ src/bun.js/bindings/JSX509Certificate.cpp
src/bun.js/bindings/JSX509CertificateConstructor.cpp
src/bun.js/bindings/JSX509CertificatePrototype.cpp
src/bun.js/bindings/linux_perf_tracing.cpp
src/bun.js/bindings/MarkedArgumentBufferBinding.cpp
src/bun.js/bindings/MarkingConstraint.cpp
src/bun.js/bindings/ModuleLoader.cpp
src/bun.js/bindings/napi_external.cpp
@@ -190,24 +187,12 @@ src/bun.js/bindings/ProcessIdentifier.cpp
src/bun.js/bindings/RegularExpression.cpp
src/bun.js/bindings/S3Error.cpp
src/bun.js/bindings/ScriptExecutionContext.cpp
src/bun.js/bindings/SecretsDarwin.cpp
src/bun.js/bindings/SecretsLinux.cpp
src/bun.js/bindings/SecretsWindows.cpp
src/bun.js/bindings/Serialization.cpp
src/bun.js/bindings/ServerRouteList.cpp
src/bun.js/bindings/spawn.cpp
src/bun.js/bindings/SQLClient.cpp
src/bun.js/bindings/sqlite/JSSQLStatement.cpp
src/bun.js/bindings/stripANSI.cpp
src/bun.js/bindings/Strong.cpp
src/bun.js/bindings/TextCodec.cpp
src/bun.js/bindings/TextCodecCJK.cpp
src/bun.js/bindings/TextCodecReplacement.cpp
src/bun.js/bindings/TextCodecSingleByte.cpp
src/bun.js/bindings/TextCodecUserDefined.cpp
src/bun.js/bindings/TextCodecWrapper.cpp
src/bun.js/bindings/TextEncoding.cpp
src/bun.js/bindings/TextEncodingRegistry.cpp
src/bun.js/bindings/Uint8Array.cpp
src/bun.js/bindings/Undici.cpp
src/bun.js/bindings/URLDecomposition.cpp
@@ -365,7 +350,6 @@ src/bun.js/bindings/webcore/JSTextEncoderStream.cpp
src/bun.js/bindings/webcore/JSTransformStream.cpp
src/bun.js/bindings/webcore/JSTransformStreamDefaultController.cpp
src/bun.js/bindings/webcore/JSURLSearchParams.cpp
src/bun.js/bindings/webcore/JSWasmStreamingCompiler.cpp
src/bun.js/bindings/webcore/JSWebSocket.cpp
src/bun.js/bindings/webcore/JSWorker.cpp
src/bun.js/bindings/webcore/JSWorkerOptions.cpp

View File

@@ -29,7 +29,6 @@ src/js/builtins/TransformStream.ts
src/js/builtins/TransformStreamDefaultController.ts
src/js/builtins/TransformStreamInternals.ts
src/js/builtins/UtilInspect.ts
src/js/builtins/WasmStreaming.ts
src/js/builtins/WritableStreamDefaultController.ts
src/js/builtins/WritableStreamDefaultWriter.ts
src/js/builtins/WritableStreamInternals.ts
@@ -65,12 +64,6 @@ src/js/internal/linkedlist.ts
src/js/internal/primordials.js
src/js/internal/promisify.ts
src/js/internal/shared.ts
src/js/internal/sql/errors.ts
src/js/internal/sql/mysql.ts
src/js/internal/sql/postgres.ts
src/js/internal/sql/query.ts
src/js/internal/sql/shared.ts
src/js/internal/sql/sqlite.ts
src/js/internal/stream.promises.ts
src/js/internal/stream.ts
src/js/internal/streams/add-abort-signal.ts

View File

@@ -6,6 +6,7 @@ src/bun.js/api/Glob.classes.ts
src/bun.js/api/h2.classes.ts
src/bun.js/api/html_rewriter.classes.ts
src/bun.js/api/JSBundler.classes.ts
src/bun.js/api/postgres.classes.ts
src/bun.js/api/ResumableSink.classes.ts
src/bun.js/api/S3Client.classes.ts
src/bun.js/api/S3Stat.classes.ts
@@ -14,7 +15,6 @@ src/bun.js/api/Shell.classes.ts
src/bun.js/api/ShellArgs.classes.ts
src/bun.js/api/sockets.classes.ts
src/bun.js/api/sourcemap.classes.ts
src/bun.js/api/sql.classes.ts
src/bun.js/api/streams.classes.ts
src/bun.js/api/valkey.classes.ts
src/bun.js/api/zlib.classes.ts

View File

@@ -1,8 +1,6 @@
src/allocators.zig
src/allocators/AllocationScope.zig
src/allocators/basic.zig
src/allocators/fallback.zig
src/allocators/fallback/z.zig
src/allocators/LinuxMemFdAllocator.zig
src/allocators/MaxHeapAllocator.zig
src/allocators/MemoryReportingAllocator.zig
@@ -12,7 +10,6 @@ src/allocators/NullableAllocator.zig
src/analytics.zig
src/analytics/schema.zig
src/api/schema.zig
src/asan.zig
src/ast.zig
src/ast/Ast.zig
src/ast/ASTMemoryAllocator.zig
@@ -21,50 +18,25 @@ src/ast/base.zig
src/ast/Binding.zig
src/ast/BundledAst.zig
src/ast/CharFreq.zig
src/ast/ConvertESMExportsForHmr.zig
src/ast/E.zig
src/ast/Expr.zig
src/ast/foldStringAddition.zig
src/ast/G.zig
src/ast/ImportScanner.zig
src/ast/KnownGlobal.zig
src/ast/Macro.zig
src/ast/maybe.zig
src/ast/NewStore.zig
src/ast/Op.zig
src/ast/P.zig
src/ast/parse.zig
src/ast/parseFn.zig
src/ast/parseImportExport.zig
src/ast/parseJSXElement.zig
src/ast/parsePrefix.zig
src/ast/parseProperty.zig
src/ast/Parser.zig
src/ast/parseStmt.zig
src/ast/parseSuffix.zig
src/ast/parseTypescript.zig
src/ast/S.zig
src/ast/Scope.zig
src/ast/ServerComponentBoundary.zig
src/ast/SideEffects.zig
src/ast/skipTypescript.zig
src/ast/Stmt.zig
src/ast/Symbol.zig
src/ast/symbols.zig
src/ast/TS.zig
src/ast/TypeScript.zig
src/ast/UseDirective.zig
src/ast/visit.zig
src/ast/visitBinaryExpression.zig
src/ast/visitExpr.zig
src/ast/visitStmt.zig
src/async/posix_event_loop.zig
src/async/stub_event_loop.zig
src/async/windows_event_loop.zig
src/bake.zig
src/bake/DevServer.zig
src/bake/DevServer/Assets.zig
src/bake/DevServer/DevAllocator.zig
src/bake/DevServer/DirectoryWatchStore.zig
src/bake/DevServer/ErrorReportRequest.zig
src/bake/DevServer/HmrSocket.zig
@@ -99,11 +71,6 @@ src/bun.js/api/bun/spawn.zig
src/bun.js/api/bun/spawn/stdio.zig
src/bun.js/api/bun/ssl_wrapper.zig
src/bun.js/api/bun/subprocess.zig
src/bun.js/api/bun/subprocess/Readable.zig
src/bun.js/api/bun/subprocess/ResourceUsage.zig
src/bun.js/api/bun/subprocess/StaticPipeWriter.zig
src/bun.js/api/bun/subprocess/SubprocessPipeReader.zig
src/bun.js/api/bun/subprocess/Writable.zig
src/bun.js/api/bun/udp_socket.zig
src/bun.js/api/bun/x509.zig
src/bun.js/api/BunObject.zig
@@ -136,7 +103,6 @@ src/bun.js/api/server/StaticRoute.zig
src/bun.js/api/server/WebSocketServerContext.zig
src/bun.js/api/streams.classes.zig
src/bun.js/api/Timer.zig
src/bun.js/api/Timer/DateHeaderTimer.zig
src/bun.js/api/Timer/EventLoopTimer.zig
src/bun.js/api/Timer/ImmediateObject.zig
src/bun.js/api/Timer/TimeoutObject.zig
@@ -144,7 +110,6 @@ src/bun.js/api/Timer/TimerObjectInternals.zig
src/bun.js/api/Timer/WTFTimer.zig
src/bun.js/api/TOMLObject.zig
src/bun.js/api/UnsafeObject.zig
src/bun.js/api/YAMLObject.zig
src/bun.js/bindgen_test.zig
src/bun.js/bindings/AbortSignal.zig
src/bun.js/bindings/AnyPromise.zig
@@ -186,12 +151,10 @@ src/bun.js/bindings/JSPromiseRejectionOperation.zig
src/bun.js/bindings/JSPropertyIterator.zig
src/bun.js/bindings/JSRef.zig
src/bun.js/bindings/JSRuntimeType.zig
src/bun.js/bindings/JSSecrets.zig
src/bun.js/bindings/JSString.zig
src/bun.js/bindings/JSType.zig
src/bun.js/bindings/JSUint8Array.zig
src/bun.js/bindings/JSValue.zig
src/bun.js/bindings/MarkedArgumentBuffer.zig
src/bun.js/bindings/NodeModuleModule.zig
src/bun.js/bindings/RegularExpression.zig
src/bun.js/bindings/ResolvedSource.zig
@@ -201,7 +164,6 @@ src/bun.js/bindings/SourceProvider.zig
src/bun.js/bindings/SourceType.zig
src/bun.js/bindings/static_export.zig
src/bun.js/bindings/SystemError.zig
src/bun.js/bindings/TextCodec.zig
src/bun.js/bindings/URL.zig
src/bun.js/bindings/URLSearchParams.zig
src/bun.js/bindings/VM.zig
@@ -287,84 +249,7 @@ src/bun.js/RuntimeTranspilerCache.zig
src/bun.js/SavedSourceMap.zig
src/bun.js/Strong.zig
src/bun.js/test/diff_format.zig
src/bun.js/test/diff/diff_match_patch.zig
src/bun.js/test/diff/printDiff.zig
src/bun.js/test/expect.zig
src/bun.js/test/expect/toBe.zig
src/bun.js/test/expect/toBeArray.zig
src/bun.js/test/expect/toBeArrayOfSize.zig
src/bun.js/test/expect/toBeBoolean.zig
src/bun.js/test/expect/toBeCloseTo.zig
src/bun.js/test/expect/toBeDate.zig
src/bun.js/test/expect/toBeDefined.zig
src/bun.js/test/expect/toBeEmpty.zig
src/bun.js/test/expect/toBeEmptyObject.zig
src/bun.js/test/expect/toBeEven.zig
src/bun.js/test/expect/toBeFalse.zig
src/bun.js/test/expect/toBeFalsy.zig
src/bun.js/test/expect/toBeFinite.zig
src/bun.js/test/expect/toBeFunction.zig
src/bun.js/test/expect/toBeGreaterThan.zig
src/bun.js/test/expect/toBeGreaterThanOrEqual.zig
src/bun.js/test/expect/toBeInstanceOf.zig
src/bun.js/test/expect/toBeInteger.zig
src/bun.js/test/expect/toBeLessThan.zig
src/bun.js/test/expect/toBeLessThanOrEqual.zig
src/bun.js/test/expect/toBeNaN.zig
src/bun.js/test/expect/toBeNegative.zig
src/bun.js/test/expect/toBeNil.zig
src/bun.js/test/expect/toBeNull.zig
src/bun.js/test/expect/toBeNumber.zig
src/bun.js/test/expect/toBeObject.zig
src/bun.js/test/expect/toBeOdd.zig
src/bun.js/test/expect/toBeOneOf.zig
src/bun.js/test/expect/toBePositive.zig
src/bun.js/test/expect/toBeString.zig
src/bun.js/test/expect/toBeSymbol.zig
src/bun.js/test/expect/toBeTrue.zig
src/bun.js/test/expect/toBeTruthy.zig
src/bun.js/test/expect/toBeTypeOf.zig
src/bun.js/test/expect/toBeUndefined.zig
src/bun.js/test/expect/toBeValidDate.zig
src/bun.js/test/expect/toBeWithin.zig
src/bun.js/test/expect/toContain.zig
src/bun.js/test/expect/toContainAllKeys.zig
src/bun.js/test/expect/toContainAllValues.zig
src/bun.js/test/expect/toContainAnyKeys.zig
src/bun.js/test/expect/toContainAnyValues.zig
src/bun.js/test/expect/toContainEqual.zig
src/bun.js/test/expect/toContainKey.zig
src/bun.js/test/expect/toContainKeys.zig
src/bun.js/test/expect/toContainValue.zig
src/bun.js/test/expect/toContainValues.zig
src/bun.js/test/expect/toEndWith.zig
src/bun.js/test/expect/toEqual.zig
src/bun.js/test/expect/toEqualIgnoringWhitespace.zig
src/bun.js/test/expect/toHaveBeenCalled.zig
src/bun.js/test/expect/toHaveBeenCalledOnce.zig
src/bun.js/test/expect/toHaveBeenCalledTimes.zig
src/bun.js/test/expect/toHaveBeenCalledWith.zig
src/bun.js/test/expect/toHaveBeenLastCalledWith.zig
src/bun.js/test/expect/toHaveBeenNthCalledWith.zig
src/bun.js/test/expect/toHaveLastReturnedWith.zig
src/bun.js/test/expect/toHaveLength.zig
src/bun.js/test/expect/toHaveNthReturnedWith.zig
src/bun.js/test/expect/toHaveProperty.zig
src/bun.js/test/expect/toHaveReturned.zig
src/bun.js/test/expect/toHaveReturnedTimes.zig
src/bun.js/test/expect/toHaveReturnedWith.zig
src/bun.js/test/expect/toInclude.zig
src/bun.js/test/expect/toIncludeRepeated.zig
src/bun.js/test/expect/toMatch.zig
src/bun.js/test/expect/toMatchInlineSnapshot.zig
src/bun.js/test/expect/toMatchObject.zig
src/bun.js/test/expect/toMatchSnapshot.zig
src/bun.js/test/expect/toSatisfy.zig
src/bun.js/test/expect/toStartWith.zig
src/bun.js/test/expect/toStrictEqual.zig
src/bun.js/test/expect/toThrow.zig
src/bun.js/test/expect/toThrowErrorMatchingInlineSnapshot.zig
src/bun.js/test/expect/toThrowErrorMatchingSnapshot.zig
src/bun.js/test/jest.zig
src/bun.js/test/pretty_format.zig
src/bun.js/test/snapshot.zig
@@ -414,7 +299,6 @@ src/bundler/BundleThread.zig
src/bundler/Chunk.zig
src/bundler/DeferredBatchTask.zig
src/bundler/entry_points.zig
src/bundler/graph_visualizer.zig
src/bundler/Graph.zig
src/bundler/HTMLImportManifest.zig
src/bundler/linker_context/computeChunks.zig
@@ -499,6 +383,7 @@ src/copy_file.zig
src/crash_handler.zig
src/create/SourceFileProjectGenerator.zig
src/csrf.zig
src/css_scanner.zig
src/css/compat.zig
src/css/context.zig
src/css/css_internals.zig
@@ -601,6 +486,7 @@ src/defines.zig
src/deps/boringssl.translated.zig
src/deps/brotli_c.zig
src/deps/c_ares.zig
src/deps/diffz/DiffMatchPatch.zig
src/deps/libdeflate.zig
src/deps/libuv.zig
src/deps/lol-html.zig
@@ -650,7 +536,6 @@ src/glob.zig
src/glob/GlobWalker.zig
src/glob/match.zig
src/Global.zig
src/handle_oom.zig
src/heap_breakdown.zig
src/highway.zig
src/hmac.zig
@@ -660,7 +545,6 @@ src/http/AsyncHTTP.zig
src/http/CertificateInfo.zig
src/http/Decompressor.zig
src/http/Encoding.zig
src/http/ETag.zig
src/http/FetchRedirect.zig
src/http/HeaderBuilder.zig
src/http/Headers.zig
@@ -735,7 +619,6 @@ src/install/PackageManager/patchPackage.zig
src/install/PackageManager/processDependencyList.zig
src/install/PackageManager/ProgressStrings.zig
src/install/PackageManager/runTasks.zig
src/install/PackageManager/security_scanner.zig
src/install/PackageManager/updatePackageJSONAndInstall.zig
src/install/PackageManager/UpdateRequest.zig
src/install/PackageManager/WorkspacePackageJSONCache.zig
@@ -749,12 +632,10 @@ src/install/resolvers/folder_resolver.zig
src/install/versioned_url.zig
src/install/windows-shim/BinLinkingShim.zig
src/install/windows-shim/bun_shim_impl.zig
src/install/yarn.zig
src/interchange.zig
src/interchange/json.zig
src/interchange/toml.zig
src/interchange/toml/lexer.zig
src/interchange/yaml.zig
src/io/heap.zig
src/io/io.zig
src/io/MaxBuf.zig
@@ -798,12 +679,7 @@ src/Progress.zig
src/ptr.zig
src/ptr/Cow.zig
src/ptr/CowSlice.zig
src/ptr/meta.zig
src/ptr/owned.zig
src/ptr/owned/maybe.zig
src/ptr/owned/scoped.zig
src/ptr/ref_count.zig
src/ptr/shared.zig
src/ptr/tagged_pointer.zig
src/ptr/weak_ptr.zig
src/renamer.zig
@@ -826,11 +702,6 @@ src/s3/multipart_options.zig
src/s3/multipart.zig
src/s3/simple_request.zig
src/s3/storage_class.zig
src/safety.zig
src/safety/alloc.zig
src/safety/CriticalSection.zig
src/safety/thread_id.zig
src/safety/ThreadLock.zig
src/semver.zig
src/semver/ExternalString.zig
src/semver/SemverObject.zig
@@ -891,63 +762,30 @@ src/sourcemap/JSSourceMap.zig
src/sourcemap/LineOffsetTable.zig
src/sourcemap/sourcemap.zig
src/sourcemap/VLQ.zig
src/sql/mysql.zig
src/sql/mysql/AuthMethod.zig
src/sql/mysql/Capabilities.zig
src/sql/mysql/ConnectionState.zig
src/sql/mysql/MySQLConnection.zig
src/sql/mysql/MySQLContext.zig
src/sql/mysql/MySQLQuery.zig
src/sql/mysql/MySQLRequest.zig
src/sql/mysql/MySQLStatement.zig
src/sql/mysql/MySQLTypes.zig
src/sql/mysql/protocol/AnyMySQLError.zig
src/sql/mysql/protocol/Auth.zig
src/sql/mysql/protocol/AuthSwitchRequest.zig
src/sql/mysql/protocol/AuthSwitchResponse.zig
src/sql/mysql/protocol/CharacterSet.zig
src/sql/mysql/protocol/ColumnDefinition41.zig
src/sql/mysql/protocol/CommandType.zig
src/sql/mysql/protocol/DecodeBinaryValue.zig
src/sql/mysql/protocol/EncodeInt.zig
src/sql/mysql/protocol/EOFPacket.zig
src/sql/mysql/protocol/ErrorPacket.zig
src/sql/mysql/protocol/HandshakeResponse41.zig
src/sql/mysql/protocol/HandshakeV10.zig
src/sql/mysql/protocol/LocalInfileRequest.zig
src/sql/mysql/protocol/NewReader.zig
src/sql/mysql/protocol/NewWriter.zig
src/sql/mysql/protocol/OKPacket.zig
src/sql/mysql/protocol/PacketHeader.zig
src/sql/mysql/protocol/PacketType.zig
src/sql/mysql/protocol/PreparedStatement.zig
src/sql/mysql/protocol/Query.zig
src/sql/mysql/protocol/ResultSet.zig
src/sql/mysql/protocol/ResultSetHeader.zig
src/sql/mysql/protocol/Signature.zig
src/sql/mysql/protocol/StackReader.zig
src/sql/mysql/protocol/StmtPrepareOKPacket.zig
src/sql/mysql/SSLMode.zig
src/sql/mysql/StatusFlags.zig
src/sql/mysql/TLSStatus.zig
src/sql/postgres.zig
src/sql/postgres/AnyPostgresError.zig
src/sql/postgres/AuthenticationState.zig
src/sql/postgres/CommandTag.zig
src/sql/postgres/ConnectionFlags.zig
src/sql/postgres/Data.zig
src/sql/postgres/DataCell.zig
src/sql/postgres/DebugSocketMonitorReader.zig
src/sql/postgres/DebugSocketMonitorWriter.zig
src/sql/postgres/ObjectIterator.zig
src/sql/postgres/PostgresCachedStructure.zig
src/sql/postgres/PostgresProtocol.zig
src/sql/postgres/PostgresRequest.zig
src/sql/postgres/PostgresSQLConnection.zig
src/sql/postgres/PostgresSQLContext.zig
src/sql/postgres/PostgresSQLQuery.zig
src/sql/postgres/PostgresSQLQueryResultMode.zig
src/sql/postgres/PostgresSQLStatement.zig
src/sql/postgres/PostgresTypes.zig
src/sql/postgres/protocol/ArrayList.zig
src/sql/postgres/protocol/Authentication.zig
src/sql/postgres/protocol/BackendKeyData.zig
src/sql/postgres/protocol/Close.zig
src/sql/postgres/protocol/ColumnIdentifier.zig
src/sql/postgres/protocol/CommandComplete.zig
src/sql/postgres/protocol/CopyData.zig
src/sql/postgres/protocol/CopyFail.zig
@@ -980,6 +818,7 @@ src/sql/postgres/protocol/StartupMessage.zig
src/sql/postgres/protocol/TransactionStatusIndicator.zig
src/sql/postgres/protocol/WriteWrap.zig
src/sql/postgres/protocol/zHelpers.zig
src/sql/postgres/QueryBindingIterator.zig
src/sql/postgres/SASL.zig
src/sql/postgres/Signature.zig
src/sql/postgres/SocketMonitor.zig
@@ -994,14 +833,6 @@ src/sql/postgres/types/json.zig
src/sql/postgres/types/numeric.zig
src/sql/postgres/types/PostgresString.zig
src/sql/postgres/types/Tag.zig
src/sql/shared/CachedStructure.zig
src/sql/shared/ColumnIdentifier.zig
src/sql/shared/ConnectionFlags.zig
src/sql/shared/Data.zig
src/sql/shared/ObjectIterator.zig
src/sql/shared/QueryBindingIterator.zig
src/sql/shared/SQLDataCell.zig
src/sql/shared/SQLQueryResultMode.zig
src/StandaloneModuleGraph.zig
src/StaticHashMap.zig
src/string.zig
@@ -1021,10 +852,6 @@ src/string/StringJoiner.zig
src/string/WTFStringImpl.zig
src/sys_uv.zig
src/sys.zig
src/sys/coreutils_error_map.zig
src/sys/Error.zig
src/sys/File.zig
src/sys/libuv_error_map.zig
src/system_timer.zig
src/test/fixtures.zig
src/test/recover.zig

View File

@@ -618,7 +618,7 @@ register_command(
-Doptimize=${ZIG_OPTIMIZE}
-Dcpu=${ZIG_CPU}
-Denable_logs=$<IF:$<BOOL:${ENABLE_LOGS}>,true,false>
-Denable_asan=$<IF:$<BOOL:${ENABLE_ZIG_ASAN}>,true,false>
-Denable_asan=$<IF:$<BOOL:${ENABLE_ASAN}>,true,false>
-Dversion=${VERSION}
-Dreported_nodejs_version=${NODEJS_VERSION}
-Dcanary=${CANARY_REVISION}
@@ -1034,6 +1034,7 @@ if(LINUX)
--ld-path=${LLD_PROGRAM}
-fno-pic
-Wl,-no-pie
-Wl,-icf=safe
-Wl,--as-needed
-Wl,-z,stack-size=12800000
-Wl,--compress-debug-sections=zlib
@@ -1059,13 +1060,6 @@ if(LINUX)
-Wl,--gc-sections
)
endif()
if (NOT DEBUG AND NOT ENABLE_ASAN)
target_link_options(${bun} PUBLIC
-Wl,-icf=safe
)
endif()
endif()
# --- Symbols list ---
@@ -1205,7 +1199,6 @@ if(NOT BUN_CPP_ONLY)
endif()
if(bunStrip)
# First, strip bun-profile.exe to create bun.exe
register_command(
TARGET
${bun}
@@ -1226,48 +1219,6 @@ 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
NAMES pwsh.exe powershell.exe
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
${bun}
TARGET_PHASE
POST_BUILD
COMMENT
"Code signing bun-profile.exe and bun.exe with DigiCert KeyLocker"
COMMAND
"${POWERSHELL_EXECUTABLE}" "-NoProfile" "-ExecutionPolicy" "Bypass" "-File" "${SIGN_SCRIPT}" "-BunProfileExe" "${BUILD_PATH}/${bunExe}" "-BunExe" "${BUILD_PATH}/${bunStripExe}"
CWD
${CMAKE_SOURCE_DIR}
SOURCES
${BUILD_PATH}/${bunStripExe}
)
endif()
endif()
# somehow on some Linux systems we need to disable ASLR for ASAN-instrumented binaries to run

View File

@@ -4,7 +4,7 @@ register_repository(
REPOSITORY
HdrHistogram/HdrHistogram_c
COMMIT
8dcce8f68512fca460b171bccc3a5afce0048779
652d51bcc36744fd1a6debfeb1a8a5f58b14022c
)
register_cmake_command(

View File

@@ -4,7 +4,7 @@ register_repository(
REPOSITORY
libarchive/libarchive
COMMIT
9525f90ca4bd14c7b335e2f8c84a4607b0af6bdf
7118f97c26bf0b2f426728b482f86508efc81d02
)
register_cmake_command(

View File

@@ -13,52 +13,14 @@ set(MIMALLOC_CMAKE_ARGS
-DMI_BUILD_SHARED=OFF
-DMI_BUILD_TESTS=OFF
-DMI_USE_CXX=ON
-DMI_OVERRIDE=OFF
-DMI_OSX_ZONE=OFF
-DMI_OSX_INTERPOSE=OFF
-DMI_SKIP_COLLECT_ON_EXIT=ON
# ```
# mimalloc_allow_large_os_pages=0 BUN_PORT=3004 mem bun http-hello.js
# Started development server: http://localhost:3004
#
# Peak memory usage: 52 MB
#
# mimalloc_allow_large_os_pages=1 BUN_PORT=3004 mem bun http-hello.js
# Started development server: http://localhost:3004
#
# Peak memory usage: 74 MB
# ```
#
# ```
# mimalloc_allow_large_os_pages=1 mem bun --eval 1
#
# Peak memory usage: 52 MB
#
# mimalloc_allow_large_os_pages=0 mem bun --eval 1
#
# Peak memory usage: 30 MB
# ```
-DMI_NO_THP=1
)
if (ABI STREQUAL "musl")
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_LIBC_MUSL=ON)
endif()
if(ENABLE_ASAN)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_TRACK_ASAN=ON)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OVERRIDE=OFF)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OSX_ZONE=OFF)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OSX_INTERPOSE=OFF)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_DEBUG_UBSAN=ON)
elseif(APPLE OR LINUX)
if(APPLE)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OVERRIDE=OFF)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OSX_ZONE=OFF)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OSX_INTERPOSE=OFF)
else()
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OVERRIDE=ON)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OSX_ZONE=OFF)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OSX_INTERPOSE=OFF)
endif()
endif()
if(DEBUG)
@@ -69,12 +31,6 @@ if(ENABLE_VALGRIND)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_VALGRIND=ON)
endif()
# Enable SIMD optimizations when not building for baseline (older CPUs)
if(NOT ENABLE_BASELINE)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OPT_ARCH=ON)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OPT_SIMD=ON)
endif()
if(WIN32)
if(DEBUG)
set(MIMALLOC_LIBRARY mimalloc-static-debug)
@@ -97,7 +53,6 @@ if(APPLE OR (LINUX AND NOT DEBUG))
set(MIMALLOC_LIBRARY CMakeFiles/mimalloc-obj.dir/src/static.c.o)
endif()
register_cmake_command(
TARGET
mimalloc

View File

@@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use")
option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading")
if(NOT WEBKIT_VERSION)
set(WEBKIT_VERSION 9dba2893ab70f873d8bb6950ee1bccb6b20c10b9)
set(WEBKIT_VERSION 1098cc50652ab1eab171f58f7669e19ca6c276ae)
endif()
string(SUBSTRING ${WEBKIT_VERSION} 0 16 WEBKIT_VERSION_PREFIX)

File diff suppressed because it is too large Load Diff

View File

@@ -320,6 +320,7 @@ Bun automatically sets the `Content-Type` header for request bodies when not exp
- For `Blob` objects, uses the blob's `type`
- For `FormData`, sets appropriate multipart boundary
- For JSON objects, sets `application/json`
## Debugging

View File

@@ -164,70 +164,6 @@ Static responses do not allocate additional memory after initialization. You can
Static route responses are cached for the lifetime of the server object. To reload static routes, call `server.reload(options)`.
### File Responses vs Static Responses
When serving files in routes, there are two distinct behaviors depending on whether you buffer the file content or serve it directly:
```ts
Bun.serve({
routes: {
// Static route - content is buffered in memory at startup
"/logo.png": new Response(await Bun.file("./logo.png").bytes()),
// File route - content is read from filesystem on each request
"/download.zip": new Response(Bun.file("./download.zip")),
},
});
```
**Static routes** (`new Response(await file.bytes())`) buffer content in memory at startup:
- **Zero filesystem I/O** during requests - content served entirely from memory
- **ETag support** - Automatically generates and validates ETags for caching
- **If-None-Match** - Returns `304 Not Modified` when client ETag matches
- **No 404 handling** - Missing files cause startup errors, not runtime 404s
- **Memory usage** - Full file content stored in RAM
- **Best for**: Small static assets, API responses, frequently accessed files
**File routes** (`new Response(Bun.file(path))`) read from filesystem per request:
- **Filesystem reads** on each request - checks file existence and reads content
- **Built-in 404 handling** - Returns `404 Not Found` if file doesn't exist or becomes inaccessible
- **Last-Modified support** - Uses file modification time for `If-Modified-Since` headers
- **If-Modified-Since** - Returns `304 Not Modified` when file hasn't changed since client's cached version
- **Range request support** - Automatically handles partial content requests with `Content-Range` headers
- **Streaming transfers** - Uses buffered reader with backpressure handling for efficient memory usage
- **Memory efficient** - Only buffers small chunks during transfer, not entire file
- **Best for**: Large files, dynamic content, user uploads, files that change frequently
### HTTP Caching Behavior
Both route types implement HTTP caching standards but with different strategies:
#### Static Routes Caching
- **ETag generation**: Automatically computes ETag hash from content at startup
- **If-None-Match**: Validates client ETag against server ETag
- **304 responses**: Returns `304 Not Modified` with empty body when ETags match
- **Cache headers**: Inherits any `Cache-Control` headers you provide in the Response
- **Consistency**: ETag remains constant until server restart or route reload
#### File Routes Caching
- **Last-Modified**: Uses file's `mtime` for `Last-Modified` header
- **If-Modified-Since**: Compares client date with file modification time
- **304 responses**: Returns `304 Not Modified` when file unchanged since client's cached version
- **Content-Length**: Automatically set based on current file size
- **Dynamic validation**: Checks file modification time on each request
#### Status Code Handling
Both route types automatically adjust status codes:
- **200 → 204**: Empty files (0 bytes) return `204 No Content` instead of `200 OK`
- **200 → 304**: Successful cache validation returns `304 Not Modified`
- **File routes only**: Missing or inaccessible files return `404 Not Found`
```ts
const server = Bun.serve({
static: {

View File

@@ -1,319 +0,0 @@
Store and retrieve sensitive credentials securely using the operating system's native credential storage APIs.
**Experimental:** This API is new and experimental. It may change in the future.
```typescript
import { secrets } from "bun";
const githubToken = await secrets.get({
service: "my-cli-tool",
name: "github-token",
});
if (!githubToken) {
const response = await fetch("https://api.github.com/name", {
headers: { "Authorization": `token ${githubToken}` },
});
console.log("Please enter your GitHub token");
} else {
await secrets.set({
service: "my-cli-tool",
name: "github-token",
value: prompt("Please enter your GitHub token"),
});
console.log("GitHub token stored");
}
```
## Overview
`Bun.secrets` provides a cross-platform API for managing sensitive credentials that CLI tools and development applications typically store in plaintext files like `~/.npmrc`, `~/.aws/credentials`, or `.env` files. It uses:
- **macOS**: Keychain Services
- **Linux**: libsecret (GNOME Keyring, KWallet, etc.)
- **Windows**: Windows Credential Manager
All operations are asynchronous and non-blocking, running on Bun's threadpool.
Note: in the future, we may add an additional `provider` option to make this better for production deployment secrets, but today this API is mostly useful for local development tools.
## API
### `Bun.secrets.get(options)`
Retrieve a stored credential.
```typescript
import { secrets } from "bun";
const password = await Bun.secrets.get({
service: "my-app",
name: "alice@example.com",
});
// Returns: string | null
// Or if you prefer without an object
const password = await Bun.secrets.get("my-app", "alice@example.com");
```
**Parameters:**
- `options.service` (string, required) - The service or application name
- `options.name` (string, required) - The username or account identifier
**Returns:**
- `Promise<string | null>` - The stored password, or `null` if not found
### `Bun.secrets.set(options, value)`
Store or update a credential.
```typescript
import { secrets } from "bun";
await secrets.set({
service: "my-app",
name: "alice@example.com",
value: "super-secret-password",
});
```
**Parameters:**
- `options.service` (string, required) - The service or application name
- `options.name` (string, required) - The username or account identifier
- `value` (string, required) - The password or secret to store
**Notes:**
- If a credential already exists for the given service/name combination, it will be replaced
- The stored value is encrypted by the operating system
### `Bun.secrets.delete(options)`
Delete a stored credential.
```typescript
const deleted = await Bun.secrets.delete({
service: "my-app",
name: "alice@example.com",
value: "super-secret-password",
});
// Returns: boolean
```
**Parameters:**
- `options.service` (string, required) - The service or application name
- `options.name` (string, required) - The username or account identifier
**Returns:**
- `Promise<boolean>` - `true` if a credential was deleted, `false` if not found
## Examples
### Storing CLI Tool Credentials
```javascript
// Store GitHub CLI token (instead of ~/.config/gh/hosts.yml)
await Bun.secrets.set({
service: "my-app.com",
name: "github-token",
value: "ghp_xxxxxxxxxxxxxxxxxxxx",
});
// Or if you prefer without an object
await Bun.secrets.set("my-app.com", "github-token", "ghp_xxxxxxxxxxxxxxxxxxxx");
// Store npm registry token (instead of ~/.npmrc)
await Bun.secrets.set({
service: "npm-registry",
name: "https://registry.npmjs.org",
value: "npm_xxxxxxxxxxxxxxxxxxxx",
});
// Retrieve for API calls
const token = await Bun.secrets.get({
service: "gh-cli",
name: "github.com",
});
if (token) {
const response = await fetch("https://api.github.com/name", {
headers: {
"Authorization": `token ${token}`,
},
});
}
```
### Migrating from Plaintext Config Files
```javascript
// Instead of storing in ~/.aws/credentials
await Bun.secrets.set({
service: "aws-cli",
name: "AWS_SECRET_ACCESS_KEY",
value: process.env.AWS_SECRET_ACCESS_KEY,
});
// Instead of .env files with sensitive data
await Bun.secrets.set({
service: "my-app",
name: "api-key",
value: "sk_live_xxxxxxxxxxxxxxxxxxxx",
});
// Load at runtime
const apiKey =
(await Bun.secrets.get({
service: "my-app",
name: "api-key",
})) || process.env.API_KEY; // Fallback for CI/production
```
### Error Handling
```javascript
try {
await Bun.secrets.set({
service: "my-app",
name: "alice",
value: "password123",
});
} catch (error) {
console.error("Failed to store credential:", error.message);
}
// Check if a credential exists
const password = await Bun.secrets.get({
service: "my-app",
name: "alice",
});
if (password === null) {
console.log("No credential found");
}
```
### Updating Credentials
```javascript
// Initial password
await Bun.secrets.set({
service: "email-server",
name: "admin@example.com",
value: "old-password",
});
// Update to new password
await Bun.secrets.set({
service: "email-server",
name: "admin@example.com",
value: "new-password",
});
// The old password is replaced
```
## Platform Behavior
### macOS (Keychain)
- Credentials are stored in the name's login keychain
- The keychain may prompt for access permission on first use
- Credentials persist across system restarts
- Accessible by the name who stored them
### Linux (libsecret)
- Requires a secret service daemon (GNOME Keyring, KWallet, etc.)
- Credentials are stored in the default collection
- May prompt for unlock if the keyring is locked
- The secret service must be running
### Windows (Credential Manager)
- Credentials are stored in Windows Credential Manager
- Visible in Control Panel → Credential Manager → Windows Credentials
- Persist with `CRED_PERSIST_ENTERPRISE` flag so it's scoped per user
- Encrypted using Windows Data Protection API
## Security Considerations
1. **Encryption**: Credentials are encrypted by the operating system's credential manager
2. **Access Control**: Only the name who stored the credential can retrieve it
3. **No Plain Text**: Passwords are never stored in plain text
4. **Memory Safety**: Bun zeros out password memory after use
5. **Process Isolation**: Credentials are isolated per name account
## Limitations
- Maximum password length varies by platform (typically 2048-4096 bytes)
- Service and name names should be reasonable lengths (< 256 characters)
- Some special characters may need escaping depending on the platform
- Requires appropriate system services:
- Linux: Secret service daemon must be running
- macOS: Keychain Access must be available
- Windows: Credential Manager service must be enabled
## Comparison with Environment Variables
Unlike environment variables, `Bun.secrets`:
- ✅ Encrypts credentials at rest (thanks to the operating system)
- ✅ Avoids exposing secrets in process memory dumps (memory is zeroed after its no longer needed)
- ✅ Survives application restarts
- ✅ Can be updated without restarting the application
- ✅ Provides name-level access control
- ❌ Requires OS credential service
- ❌ Not very useful for deployment secrets (use environment variables in production)
## Best Practices
1. **Use descriptive service names**: Match the tool or application name
If you're building a CLI for external use, you probably should use a UTI (Uniform Type Identifier) for the service name.
```javascript
// Good - matches the actual tool
{ service: "com.docker.hub", name: "username" }
{ service: "com.vercel.cli", name: "team-name" }
// Avoid - too generic
{ service: "api", name: "key" }
```
2. **Credentials-only**: Don't store application configuration in this API
This API is slow, you probably still need to use a config file for some things.
3. **Use for local development tools**:
- ✅ CLI tools (gh, npm, docker, kubectl)
- ✅ Local development servers
- ✅ Personal API keys for testing
- ❌ Production servers (use proper secret management)
## TypeScript
```typescript
namespace Bun {
interface SecretsOptions {
service: string;
name: string;
}
interface Secrets {
get(options: SecretsOptions): Promise<string | null>;
set(options: SecretsOptions, value: string): Promise<void>;
delete(options: SecretsOptions): Promise<boolean>;
}
const secrets: Secrets;
}
```
## See Also
- [Environment Variables](./env.md) - For deployment configuration
- [Bun.password](./password.md) - For password hashing and verification

View File

@@ -1,20 +1,20 @@
Bun provides native bindings for working with SQL databases through a unified Promise-based API that supports both PostgreSQL and SQLite. The interface is designed to be simple and performant, using tagged template literals for queries and offering features like connection pooling, transactions, and prepared statements.
Bun provides native bindings for working with PostgreSQL databases with a modern, Promise-based API. The interface is designed to be simple and performant, using tagged template literals for queries and offering features like connection pooling, transactions, and prepared statements.
```ts
import { sql, SQL } from "bun";
import { sql } from "bun";
// PostgreSQL (default)
const users = await sql`
SELECT * FROM users
WHERE active = ${true}
LIMIT ${10}
`;
// With a a SQLite db
const sqlite = new SQL("sqlite://myapp.db");
const results = await sqlite`
SELECT * FROM users
WHERE active = ${1}
// Select with multiple conditions
const activeUsers = await sql`
SELECT *
FROM users
WHERE active = ${true}
AND age >= ${18}
`;
```
@@ -44,113 +44,6 @@ const results = await sqlite`
{% /features %}
## Database Support
Bun.SQL provides a unified API for multiple database systems:
### PostgreSQL
PostgreSQL is used when:
- The connection string doesn't match SQLite patterns (it's the fallback adapter)
- The connection string explicitly uses `postgres://` or `postgresql://` protocols
- No connection string is provided and environment variables point to PostgreSQL
```ts
import { sql } from "bun";
// Uses PostgreSQL if DATABASE_URL is not set or is a PostgreSQL URL
await sql`SELECT ...`;
import { SQL } from "bun";
const pg = new SQL("postgres://user:pass@localhost:5432/mydb");
await pg`SELECT ...`;
```
### SQLite
SQLite support is now built into Bun.SQL, providing the same tagged template literal interface as PostgreSQL:
```ts
import { SQL } from "bun";
// In-memory database
const memory = new SQL(":memory:");
const memory2 = new SQL("sqlite://:memory:");
// File-based database
const db = new SQL("sqlite://myapp.db");
// Using options object
const db2 = new SQL({
adapter: "sqlite",
filename: "./data/app.db",
});
// For simple filenames, specify adapter explicitly
const db3 = new SQL("myapp.db", { adapter: "sqlite" });
```
{% details summary="SQLite Connection String Formats" %}
SQLite accepts various URL formats for connection strings:
```ts
// Standard sqlite:// protocol
new SQL("sqlite://path/to/database.db");
new SQL("sqlite:path/to/database.db"); // Without slashes
// file:// protocol (also recognized as SQLite)
new SQL("file://path/to/database.db");
new SQL("file:path/to/database.db");
// Special :memory: database
new SQL(":memory:");
new SQL("sqlite://:memory:");
new SQL("file://:memory:");
// Relative and absolute paths
new SQL("sqlite://./local.db"); // Relative to current directory
new SQL("sqlite://../parent/db.db"); // Parent directory
new SQL("sqlite:///absolute/path.db"); // Absolute path
// With query parameters
new SQL("sqlite://data.db?mode=ro"); // Read-only mode
new SQL("sqlite://data.db?mode=rw"); // Read-write mode (no create)
new SQL("sqlite://data.db?mode=rwc"); // Read-write-create mode (default)
```
**Note:** Simple filenames without a protocol (like `"myapp.db"`) require explicitly specifying `{ adapter: "sqlite" }` to avoid ambiguity with PostgreSQL.
{% /details %}
{% details summary="SQLite-Specific Options" %}
SQLite databases support additional configuration options:
```ts
const db = new SQL({
adapter: "sqlite",
filename: "app.db",
// SQLite-specific options
readonly: false, // Open in read-only mode
create: true, // Create database if it doesn't exist
readwrite: true, // Open for reading and writing
// Additional Bun:sqlite options
strict: true, // Enable strict mode
safeIntegers: false, // Use JavaScript numbers for integers
});
```
Query parameters in the URL are parsed to set these options:
- `?mode=ro``readonly: true`
- `?mode=rw``readonly: false, create: false`
- `?mode=rwc``readonly: false, create: true` (default)
{% /details %}
### Inserting data
You can pass JavaScript values directly to the SQL template literal and escaping will be handled for you.
@@ -358,55 +251,14 @@ await query;
## Database Environment Variables
`sql` connection parameters can be configured using environment variables. The client checks these variables in a specific order of precedence and automatically detects the database type based on the connection string format.
`sql` connection parameters can be configured using environment variables. The client checks these variables in a specific order of precedence.
### Automatic Database Detection
When using `Bun.sql()` without arguments or `new SQL()` with a connection string, the adapter is automatically detected based on the URL format. SQLite becomes the default adapter in these cases:
#### SQLite Auto-Detection
SQLite is automatically selected when the connection string matches these patterns:
- `:memory:` - In-memory database
- `sqlite://...` - SQLite protocol URLs
- `sqlite:...` - SQLite protocol without slashes
- `file://...` - File protocol URLs
- `file:...` - File protocol without slashes
```ts
// These all use SQLite automatically (no adapter needed)
const sql1 = new SQL(":memory:");
const sql2 = new SQL("sqlite://app.db");
const sql3 = new SQL("file://./database.db");
// Works with DATABASE_URL environment variable
DATABASE_URL=":memory:" bun run app.js
DATABASE_URL="sqlite://myapp.db" bun run app.js
DATABASE_URL="file://./data/app.db" bun run app.js
```
#### PostgreSQL Auto-Detection
PostgreSQL is the default for all other connection strings:
```bash
# PostgreSQL is detected for these patterns
DATABASE_URL="postgres://user:pass@localhost:5432/mydb" bun run app.js
DATABASE_URL="postgresql://user:pass@localhost:5432/mydb" bun run app.js
# Or any URL that doesn't match SQLite patterns
DATABASE_URL="localhost:5432/mydb" bun run app.js
```
### PostgreSQL Environment Variables
The following environment variables can be used to define the PostgreSQL connection:
The following environment variables can be used to define the connection URL:
| Environment Variable | Description |
| --------------------------- | ------------------------------------------ |
| `POSTGRES_URL` | Primary connection URL for PostgreSQL |
| `DATABASE_URL` | Alternative connection URL (auto-detected) |
| `DATABASE_URL` | Alternative connection URL |
| `PGURL` | Alternative connection URL |
| `PG_URL` | Alternative connection URL |
| `TLS_POSTGRES_DATABASE_URL` | SSL/TLS-enabled connection URL |
@@ -422,19 +274,6 @@ If no connection URL is provided, the system checks for the following individual
| `PGPASSWORD` | - | (empty) | Database password |
| `PGDATABASE` | - | username | Database name |
### SQLite Environment Variables
SQLite connections can be configured via `DATABASE_URL` when it contains a SQLite-compatible URL:
```bash
# These are all recognized as SQLite
DATABASE_URL=":memory:"
DATABASE_URL="sqlite://./app.db"
DATABASE_URL="file:///absolute/path/to/db.sqlite"
```
**Note:** PostgreSQL-specific environment variables (`POSTGRES_URL`, `PGHOST`, etc.) are ignored when using SQLite.
## Runtime Preconnection
Bun can preconnect to PostgreSQL at startup to improve performance by establishing database connections before your application code runs. This is useful for reducing connection latency on the first database query.
@@ -454,18 +293,16 @@ The `--sql-preconnect` flag will automatically establish a PostgreSQL connection
## Connection Options
You can configure your database connection manually by passing options to the SQL constructor. Options vary depending on the database adapter:
### PostgreSQL Options
You can configure your database connection manually by passing options to the SQL constructor:
```ts
import { SQL } from "bun";
const db = new SQL({
// Connection details (adapter is auto-detected as PostgreSQL)
// Required
url: "postgres://user:pass@localhost:5432/dbname",
// Alternative connection parameters
// Optional configuration
hostname: "localhost",
port: 5432,
database: "myapp",
@@ -493,52 +330,14 @@ const db = new SQL({
// Callbacks
onconnect: client => {
console.log("Connected to PostgreSQL");
console.log("Connected to database");
},
onclose: client => {
console.log("PostgreSQL connection closed");
console.log("Connection closed");
},
});
```
### SQLite Options
```ts
import { SQL } from "bun";
const db = new SQL({
// Required for SQLite
adapter: "sqlite",
filename: "./data/app.db", // or ":memory:" for in-memory database
// SQLite-specific access modes
readonly: false, // Open in read-only mode
create: true, // Create database if it doesn't exist
readwrite: true, // Allow read and write operations
// SQLite data handling
strict: true, // Enable strict mode for better type safety
safeIntegers: false, // Use BigInt for integers exceeding JS number range
// Callbacks
onconnect: client => {
console.log("SQLite database opened");
},
onclose: client => {
console.log("SQLite database closed");
},
});
```
{% details summary="SQLite Connection Notes" %}
- **Connection Pooling**: SQLite doesn't use connection pooling as it's a file-based database. Each `SQL` instance represents a single connection.
- **Transactions**: SQLite supports nested transactions through savepoints, similar to PostgreSQL.
- **Concurrent Access**: SQLite handles concurrent access through file locking. Use WAL mode for better concurrency.
- **Memory Databases**: Using `:memory:` creates a temporary database that exists only for the connection lifetime.
{% /details %}
## Dynamic passwords
When clients need to use alternative authentication schemes such as access tokens or connections to databases with rotating passwords, provide either a synchronous or asynchronous function that will resolve the dynamic password value at connection time.
@@ -554,66 +353,11 @@ const sql = new SQL(url, {
});
```
## SQLite-Specific Features
### Query Execution
SQLite executes queries synchronously, unlike PostgreSQL which uses asynchronous I/O. However, the API remains consistent using Promises:
```ts
const sqlite = new SQL("sqlite://app.db");
// Works the same as PostgreSQL, but executes synchronously under the hood
const users = await sqlite`SELECT * FROM users`;
// Parameters work identically
const user = await sqlite`SELECT * FROM users WHERE id = ${userId}`;
```
### SQLite Pragmas
You can use PRAGMA statements to configure SQLite behavior:
```ts
const sqlite = new SQL("sqlite://app.db");
// Enable foreign keys
await sqlite`PRAGMA foreign_keys = ON`;
// Set journal mode to WAL for better concurrency
await sqlite`PRAGMA journal_mode = WAL`;
// Check integrity
const integrity = await sqlite`PRAGMA integrity_check`;
```
### Data Type Differences
SQLite has a more flexible type system than PostgreSQL:
```ts
// SQLite stores data in 5 storage classes: NULL, INTEGER, REAL, TEXT, BLOB
const sqlite = new SQL("sqlite://app.db");
// SQLite is more lenient with types
await sqlite`
CREATE TABLE flexible (
id INTEGER PRIMARY KEY,
data TEXT, -- Can store numbers as strings
value NUMERIC, -- Can store integers, reals, or text
blob BLOB -- Binary data
)
`;
// JavaScript values are automatically converted
await sqlite`INSERT INTO flexible VALUES (${1}, ${"text"}, ${123.45}, ${Buffer.from("binary")})`;
```
## Transactions
To start a new transaction, use `sql.begin`. This method works for both PostgreSQL and SQLite. For PostgreSQL, it reserves a dedicated connection from the pool. For SQLite, it begins a transaction on the single connection.
To start a new transaction, use `sql.begin`. This method reserves a dedicated connection for the duration of the transaction and provides a scoped `sql` instance to use within the callback function. Once the callback completes, `sql.begin` resolves with the return value of the callback.
The `BEGIN` command is sent automatically, including any optional configurations you specify. If an error occurs during the transaction, a `ROLLBACK` is triggered to ensure the process continues smoothly.
The `BEGIN` command is sent automatically, including any optional configurations you specify. If an error occurs during the transaction, a `ROLLBACK` is triggered to release the reserved connection and ensure the process continues smoothly.
### Basic Transactions
@@ -808,36 +552,9 @@ Note that disabling prepared statements may impact performance for queries that
## Error Handling
The client provides typed errors for different failure scenarios. Errors are database-specific and extend from base error classes:
The client provides typed errors for different failure scenarios:
### Error Classes
```ts
import { SQL } from "bun";
try {
await sql`SELECT * FROM users`;
} catch (error) {
if (error instanceof SQL.PostgresError) {
// PostgreSQL-specific error
console.log(error.code); // PostgreSQL error code
console.log(error.detail); // Detailed error message
console.log(error.hint); // Helpful hint from PostgreSQL
} else if (error instanceof SQL.SQLiteError) {
// SQLite-specific error
console.log(error.code); // SQLite error code (e.g., "SQLITE_CONSTRAINT")
console.log(error.errno); // SQLite error number
console.log(error.byteOffset); // Byte offset in SQL statement (if available)
} else if (error instanceof SQL.SQLError) {
// Generic SQL error (base class)
console.log(error.message);
}
}
```
{% details summary="PostgreSQL-Specific Error Codes" %}
### PostgreSQL Connection Errors
### Connection Errors
| Connection Errors | Description |
| --------------------------------- | ---------------------------------------------------- |
@@ -902,51 +619,6 @@ try {
| `ERR_POSTGRES_UNSAFE_TRANSACTION` | Unsafe transaction operation detected |
| `ERR_POSTGRES_INVALID_TRANSACTION_STATE` | Invalid transaction state |
{% /details %}
### SQLite-Specific Errors
SQLite errors provide error codes and numbers that correspond to SQLite's standard error codes:
{% details summary="Common SQLite Error Codes" %}
| Error Code | errno | Description |
| ------------------- | ----- | ---------------------------------------------------- |
| `SQLITE_CONSTRAINT` | 19 | Constraint violation (UNIQUE, CHECK, NOT NULL, etc.) |
| `SQLITE_BUSY` | 5 | Database is locked |
| `SQLITE_LOCKED` | 6 | Table in the database is locked |
| `SQLITE_READONLY` | 8 | Attempt to write to a readonly database |
| `SQLITE_IOERR` | 10 | Disk I/O error |
| `SQLITE_CORRUPT` | 11 | Database disk image is malformed |
| `SQLITE_FULL` | 13 | Database or disk is full |
| `SQLITE_CANTOPEN` | 14 | Unable to open database file |
| `SQLITE_PROTOCOL` | 15 | Database lock protocol error |
| `SQLITE_SCHEMA` | 17 | Database schema has changed |
| `SQLITE_TOOBIG` | 18 | String or BLOB exceeds size limit |
| `SQLITE_MISMATCH` | 20 | Data type mismatch |
| `SQLITE_MISUSE` | 21 | Library used incorrectly |
| `SQLITE_AUTH` | 23 | Authorization denied |
Example error handling:
```ts
const sqlite = new SQL("sqlite://app.db");
try {
await sqlite`INSERT INTO users (id, name) VALUES (1, 'Alice')`;
await sqlite`INSERT INTO users (id, name) VALUES (1, 'Bob')`; // Duplicate ID
} catch (error) {
if (error instanceof SQL.SQLiteError) {
if (error.code === "SQLITE_CONSTRAINT") {
console.log("Constraint violation:", error.message);
// Handle unique constraint violation
}
}
}
```
{% /details %}
## Numbers and BigInt
Bun's SQL client includes special handling for large numbers that exceed the range of a 53-bit integer. Here's how it works:
@@ -980,6 +652,7 @@ There's still some things we haven't finished yet.
- Connection preloading via `--db-preconnect` Bun CLI flag
- MySQL support: [we're working on it](https://github.com/oven-sh/bun/pull/15274)
- SQLite support: planned, but not started. Ideally, we implement it natively instead of wrapping `bun:sqlite`.
- Column name transforms (e.g. `snake_case` to `camelCase`). This is mostly blocked on a unicode-aware implementation of changing the case in C++ using WebKit's `WTF::String`.
- Column type transforms
@@ -998,7 +671,13 @@ We also haven't implemented some of the more uncommon features like:
- Point & PostGIS types
- All the multi-dimensional integer array types (only a couple of the types are supported)
## Why not just use an existing library?
## Frequently Asked Questions
> Why is this `Bun.sql` and not `Bun.postgres`?
The plan is to add more database drivers in the future.
> Why not just use an existing library?
npm packages like postgres.js, pg, and node-postgres can be used in Bun too. They're great options.

View File

@@ -208,8 +208,8 @@ export class ArrayBufferSink {
*
* This API might change later to separate Uint8ArraySink and ArrayBufferSink
*/
flush(): number | Uint8Array<ArrayBuffer> | ArrayBuffer;
end(): ArrayBuffer | Uint8Array<ArrayBuffer>;
flush(): number | Uint8Array | ArrayBuffer;
end(): ArrayBuffer | Uint8Array;
}
```

View File

@@ -772,65 +772,6 @@ console.log(obj); // => { foo: "bar" }
Internally, [`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) and [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) serialize and deserialize the same way. This exposes the underlying [HTML Structured Clone Algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) to JavaScript as an ArrayBuffer.
## `Bun.stripANSI()` ~6-57x faster `strip-ansi` alternative
`Bun.stripANSI(text: string): string`
Strip ANSI escape codes from a string. This is useful for removing colors and formatting from terminal output.
```ts
const coloredText = "\u001b[31mHello\u001b[0m \u001b[32mWorld\u001b[0m";
const plainText = Bun.stripANSI(coloredText);
console.log(plainText); // => "Hello World"
// Works with various ANSI codes
const formatted = "\u001b[1m\u001b[4mBold and underlined\u001b[0m";
console.log(Bun.stripANSI(formatted)); // => "Bold and underlined"
```
`Bun.stripANSI` is significantly faster than the popular [`strip-ansi`](https://www.npmjs.com/package/strip-ansi) npm package:
```js
> bun bench/snippets/strip-ansi.mjs
cpu: Apple M3 Max
runtime: bun 1.2.21 (arm64-darwin)
benchmark avg (min … max) p75 / p99
------------------------------------------------------- ----------
Bun.stripANSI 11 chars no-ansi 8.13 ns/iter 8.27 ns
(7.45 ns … 33.59 ns) 10.29 ns
Bun.stripANSI 13 chars ansi 51.68 ns/iter 52.51 ns
(46.16 ns … 113.71 ns) 57.71 ns
Bun.stripANSI 16,384 chars long-no-ansi 298.39 ns/iter 305.44 ns
(281.50 ns … 331.65 ns) 320.70 ns
Bun.stripANSI 212,992 chars long-ansi 227.65 µs/iter 234.50 µs
(216.46 µs … 401.92 µs) 262.25 µs
```
```js
> node bench/snippets/strip-ansi.mjs
cpu: Apple M3 Max
runtime: node 24.6.0 (arm64-darwin)
benchmark avg (min … max) p75 / p99
-------------------------------------------------------- ---------
npm/strip-ansi 11 chars no-ansi 466.79 ns/iter 468.67 ns
(454.08 ns … 570.67 ns) 543.67 ns
npm/strip-ansi 13 chars ansi 546.77 ns/iter 550.23 ns
(532.74 ns … 651.08 ns) 590.35 ns
npm/strip-ansi 16,384 chars long-no-ansi 4.85 µs/iter 4.89 µs
(4.71 µs … 5.00 µs) 4.98 µs
npm/strip-ansi 212,992 chars long-ansi 1.36 ms/iter 1.38 ms
(1.27 ms … 1.73 ms) 1.49 ms
```
## `estimateShallowMemoryUsageOf` in `bun:jsc`
The `estimateShallowMemoryUsageOf` function returns a best-effort estimate of the memory usage of an object in bytes, excluding the memory usage of properties or other objects it references. For accurate per-object memory usage, use `Bun.generateHeapSnapshot`.

View File

@@ -1,5 +1,5 @@
{% callout %}
**🚧** — The `Worker` API is still experimental (particularly for terminating workers). We are actively working on improving this.
**🚧** — The `Worker` API is still experimental and should not be considered ready for production.
{% /callout %}
[`Worker`](https://developer.mozilla.org/en-US/docs/Web/API/Worker) lets you start and communicate with a new JavaScript instance running on a separate thread while sharing I/O resources with the main thread.

View File

@@ -1,459 +0,0 @@
In Bun, YAML is a first-class citizen alongside JSON and TOML.
Bun provides built-in support for YAML files through both runtime APIs and bundler integration. You can
- Parse YAML strings with `Bun.YAML.parse`
- import & require YAML files as modules at runtime (including hot reloading & watch mode support)
- import & require YAML files in frontend apps via bun's bundler
## Conformance
Bun's YAML parser currently passes over 90% of the official YAML test suite. While we're actively working on reaching 100% conformance, the current implementation covers the vast majority of real-world use cases. The parser is written in Zig for optimal performance and is continuously being improved.
## Runtime API
### `Bun.YAML.parse()`
Parse a YAML string into a JavaScript object.
```ts
import { YAML } from "bun";
const text = `
name: John Doe
age: 30
email: john@example.com
hobbies:
- reading
- coding
- hiking
`;
const data = YAML.parse(text);
console.log(data);
// {
// name: "John Doe",
// age: 30,
// email: "john@example.com",
// hobbies: ["reading", "coding", "hiking"]
// }
```
#### Multi-document YAML
When parsing YAML with multiple documents (separated by `---`), `Bun.YAML.parse()` returns an array:
```ts
const multiDoc = `
---
name: Document 1
---
name: Document 2
---
name: Document 3
`;
const docs = Bun.YAML.parse(multiDoc);
console.log(docs);
// [
// { name: "Document 1" },
// { name: "Document 2" },
// { name: "Document 3" }
// ]
```
#### Supported YAML Features
Bun's YAML parser supports the full YAML 1.2 specification, including:
- **Scalars**: strings, numbers, booleans, null values
- **Collections**: sequences (arrays) and mappings (objects)
- **Anchors and Aliases**: reusable nodes with `&` and `*`
- **Tags**: type hints like `!!str`, `!!int`, `!!float`, `!!bool`, `!!null`
- **Multi-line strings**: literal (`|`) and folded (`>`) scalars
- **Comments**: using `#`
- **Directives**: `%YAML` and `%TAG`
```ts
const yaml = `
# Employee record
employee: &emp
name: Jane Smith
department: Engineering
skills:
- JavaScript
- TypeScript
- React
manager: *emp # Reference to employee
config: !!str 123 # Explicit string type
description: |
This is a multi-line
literal string that preserves
line breaks and spacing.
summary: >
This is a folded string
that joins lines with spaces
unless there are blank lines.
`;
const data = Bun.YAML.parse(yaml);
```
#### Error Handling
`Bun.YAML.parse()` throws a `SyntaxError` if the YAML is invalid:
```ts
try {
Bun.YAML.parse("invalid: yaml: content:");
} catch (error) {
console.error("Failed to parse YAML:", error.message);
}
```
## Module Import
### ES Modules
You can import YAML files directly as ES modules. The YAML content is parsed and made available as both default and named exports:
```yaml#config.yaml
database:
host: localhost
port: 5432
name: myapp
redis:
host: localhost
port: 6379
features:
auth: true
rateLimit: true
analytics: false
```
#### Default Import
```ts#app.ts
import config from "./config.yaml";
console.log(config.database.host); // "localhost"
console.log(config.redis.port); // 6379
```
#### Named Imports
You can destructure top-level YAML properties as named imports:
```ts
import { database, redis, features } from "./config.yaml";
console.log(database.host); // "localhost"
console.log(redis.port); // 6379
console.log(features.auth); // true
```
Or combine both:
```ts
import config, { database, features } from "./config.yaml";
// Use the full config object
console.log(config);
// Or use specific parts
if (features.rateLimit) {
setupRateLimiting(database);
}
```
### CommonJS
YAML files can also be required in CommonJS:
```js
const config = require("./config.yaml");
console.log(config.database.name); // "myapp"
// Destructuring also works
const { database, redis } = require("./config.yaml");
console.log(database.port); // 5432
```
## Hot Reloading with YAML
One of the most powerful features of Bun's YAML support is hot reloading. When you run your application with `bun --hot`, changes to YAML files are automatically detected and reloaded without closing connections
### Configuration Hot Reloading
```yaml#config.yaml
server:
port: 3000
host: localhost
features:
debug: true
verbose: false
```
```ts#server.ts
import { server, features } from "./config.yaml";
console.log(`Starting server on ${server.host}:${server.port}`);
if (features.debug) {
console.log("Debug mode enabled");
}
// Your server code here
Bun.serve({
port: server.port,
hostname: server.host,
fetch(req) {
if (features.verbose) {
console.log(`${req.method} ${req.url}`);
}
return new Response("Hello World");
},
});
```
Run with hot reloading:
```bash
bun --hot server.ts
```
Now when you modify `config.yaml`, the changes are immediately reflected in your running application. This is perfect for:
- Adjusting configuration during development
- Testing different settings without restarts
- Live debugging with configuration changes
- Feature flag toggling
## Configuration Management
### Environment-Based Configuration
YAML excels at managing configuration across different environments:
```yaml#config.yaml
defaults: &defaults
timeout: 5000
retries: 3
cache:
enabled: true
ttl: 3600
development:
<<: *defaults
api:
url: http://localhost:4000
key: dev_key_12345
logging:
level: debug
pretty: true
staging:
<<: *defaults
api:
url: https://staging-api.example.com
key: ${STAGING_API_KEY}
logging:
level: info
pretty: false
production:
<<: *defaults
api:
url: https://api.example.com
key: ${PROD_API_KEY}
cache:
enabled: true
ttl: 86400
logging:
level: error
pretty: false
```
```ts#app.ts
import configs from "./config.yaml";
const env = process.env.NODE_ENV || "development";
const config = configs[env];
// Environment variables in YAML values can be interpolated
function interpolateEnvVars(obj: any): any {
if (typeof obj === "string") {
return obj.replace(/\${(\w+)}/g, (_, key) => process.env[key] || "");
}
if (typeof obj === "object") {
for (const key in obj) {
obj[key] = interpolateEnvVars(obj[key]);
}
}
return obj;
}
export default interpolateEnvVars(config);
```
### Feature Flags Configuration
```yaml#features.yaml
features:
newDashboard:
enabled: true
rolloutPercentage: 50
allowedUsers:
- admin@example.com
- beta@example.com
experimentalAPI:
enabled: false
endpoints:
- /api/v2/experimental
- /api/v2/beta
darkMode:
enabled: true
default: auto # auto, light, dark
```
```ts#feature-flags.ts
import { features } from "./features.yaml";
export function isFeatureEnabled(
featureName: string,
userEmail?: string,
): boolean {
const feature = features[featureName];
if (!feature?.enabled) {
return false;
}
// Check rollout percentage
if (feature.rolloutPercentage < 100) {
const hash = hashCode(userEmail || "anonymous");
if (hash % 100 >= feature.rolloutPercentage) {
return false;
}
}
// Check allowed users
if (feature.allowedUsers && userEmail) {
return feature.allowedUsers.includes(userEmail);
}
return true;
}
// Use with hot reloading to toggle features in real-time
if (isFeatureEnabled("newDashboard", user.email)) {
renderNewDashboard();
} else {
renderLegacyDashboard();
}
```
### Database Configuration
```yaml#database.yaml
connections:
primary:
type: postgres
host: ${DB_HOST:-localhost}
port: ${DB_PORT:-5432}
database: ${DB_NAME:-myapp}
username: ${DB_USER:-postgres}
password: ${DB_PASS}
pool:
min: 2
max: 10
idleTimeout: 30000
cache:
type: redis
host: ${REDIS_HOST:-localhost}
port: ${REDIS_PORT:-6379}
password: ${REDIS_PASS}
db: 0
analytics:
type: clickhouse
host: ${ANALYTICS_HOST:-localhost}
port: 8123
database: analytics
migrations:
autoRun: ${AUTO_MIGRATE:-false}
directory: ./migrations
seeds:
enabled: ${SEED_DB:-false}
directory: ./seeds
```
```ts#db.ts
import { connections, migrations } from "./database.yaml";
import { createConnection } from "./database-driver";
// Parse environment variables with defaults
function parseConfig(config: any) {
return JSON.parse(
JSON.stringify(config).replace(
/\${([^:-]+)(?::([^}]+))?}/g,
(_, key, defaultValue) => process.env[key] || defaultValue || "",
),
);
}
const dbConfig = parseConfig(connections);
export const db = await createConnection(dbConfig.primary);
export const cache = await createConnection(dbConfig.cache);
export const analytics = await createConnection(dbConfig.analytics);
// Auto-run migrations if configured
if (parseConfig(migrations).autoRun === "true") {
await runMigrations(db, migrations.directory);
}
```
### Bundler Integration
When you import YAML files in your application and bundle it with Bun, the YAML is parsed at build time and included as a JavaScript module:
```bash
bun build app.ts --outdir=dist
```
This means:
- Zero runtime YAML parsing overhead in production
- Smaller bundle sizes
- Tree-shaking support for unused configuration (named imports)
### Dynamic Imports
YAML files can be dynamically imported, useful for loading configuration on demand:
```ts#Load configuration based on environment
const env = process.env.NODE_ENV || "development";
const config = await import(`./configs/${env}.yaml`);
// Load user-specific settings
async function loadUserSettings(userId: string) {
try {
const settings = await import(`./users/${userId}/settings.yaml`);
return settings.default;
} catch {
return await import("./users/default-settings.yaml");
}
}
```

View File

@@ -408,119 +408,16 @@ $ bun build --compile --asset-naming="[name].[ext]" ./index.ts
To trim down the size of the executable a little, pass `--minify` to `bun build --compile`. This uses Bun's minifier to reduce the code size. Overall though, Bun's binary is still way too big and we need to make it smaller.
## Using Bun.build() API
You can also generate standalone executables using the `Bun.build()` JavaScript API. This is useful when you need programmatic control over the build process.
### Basic usage
```js
await Bun.build({
entrypoints: ["./app.ts"],
outdir: "./dist",
compile: {
target: "bun-windows-x64",
outfile: "myapp.exe",
},
});
```
### Windows metadata with Bun.build()
When targeting Windows, you can specify metadata through the `windows` object:
```js
await Bun.build({
entrypoints: ["./app.ts"],
outdir: "./dist",
compile: {
target: "bun-windows-x64",
outfile: "myapp.exe",
windows: {
title: "My Application",
publisher: "My Company Inc",
version: "1.2.3.4",
description: "A powerful application built with Bun",
copyright: "© 2024 My Company Inc",
hideConsole: false, // Set to true for GUI applications
icon: "./icon.ico", // Path to icon file
},
},
});
```
### Cross-compilation with Bun.build()
You can cross-compile for different platforms:
```js
// Build for multiple platforms
const platforms = [
{ target: "bun-windows-x64", outfile: "app-windows.exe" },
{ target: "bun-linux-x64", outfile: "app-linux" },
{ target: "bun-darwin-arm64", outfile: "app-macos" },
];
for (const platform of platforms) {
await Bun.build({
entrypoints: ["./app.ts"],
outdir: "./dist",
compile: platform,
});
}
```
## Windows-specific flags
When compiling a standalone executable for Windows, there are several platform-specific options that can be used to customize the generated `.exe` file:
When compiling a standalone executable on Windows, there are two platform-specific options that can be used to customize metadata on the generated `.exe` file:
### Visual customization
- `--windows-icon=path/to/icon.ico` - Set the executable file icon
- `--windows-hide-console` - Disable the background terminal window (useful for GUI applications)
### Metadata customization
You can embed version information and other metadata into your Windows executable:
- `--windows-title <STR>` - Set the product name (appears in file properties)
- `--windows-publisher <STR>` - Set the company name
- `--windows-version <STR>` - Set the version number (e.g. "1.2.3.4")
- `--windows-description <STR>` - Set the file description
- `--windows-copyright <STR>` - Set the copyright information
#### Example with all metadata flags:
```sh
bun build --compile ./app.ts \
--outfile myapp.exe \
--windows-title "My Application" \
--windows-publisher "My Company Inc" \
--windows-version "1.2.3.4" \
--windows-description "A powerful application built with Bun" \
--windows-copyright "© 2024 My Company Inc"
```
This metadata will be visible in Windows Explorer when viewing the file properties:
1. Right-click the executable in Windows Explorer
2. Select "Properties"
3. Go to the "Details" tab
#### Version string format
The `--windows-version` flag accepts version strings in the following formats:
- `"1"` - Will be normalized to "1.0.0.0"
- `"1.2"` - Will be normalized to "1.2.0.0"
- `"1.2.3"` - Will be normalized to "1.2.3.0"
- `"1.2.3.4"` - Full version format
Each version component must be a number between 0 and 65535.
- `--windows-icon=path/to/icon.ico` to customize the executable file icon.
- `--windows-hide-console` to disable the background terminal, which can be used for applications that do not need a TTY.
{% callout %}
These flags currently cannot be used when cross-compiling because they depend on Windows APIs. They are only available when building on Windows itself.
These flags currently cannot be used when cross-compiling because they depend on Windows APIs.
{% /callout %}

View File

@@ -1,4 +1,4 @@
Bun's fast native bundler can be used via the `bun build` CLI command or the `Bun.build()` JavaScript API.
Bun's fast native bundler is now in beta. It can be used via the `bun build` CLI command or the `Bun.build()` JavaScript API.
{% codetabs group="a" %}
@@ -1259,33 +1259,6 @@ $ bun build ./index.tsx --outdir ./out --drop=console --drop=debugger --drop=any
{% /codetabs %}
### `throw`
Controls error handling behavior when the build fails. When set to `true` (default), the returned promise rejects with an `AggregateError`. When set to `false`, the promise resolves with a `BuildOutput` object where `success` is `false`.
```ts#JavaScript
// Default behavior: throws on error
try {
await Bun.build({
entrypoints: ['./index.tsx'],
throw: true, // default
});
} catch (error) {
// Handle AggregateError
console.error("Build failed:", error);
}
// Alternative: handle errors via success property
const result = await Bun.build({
entrypoints: ['./index.tsx'],
throw: false,
});
if (!result.success) {
console.error("Build failed with errors:", result.logs);
}
```
## Outputs
The `Bun.build` function returns a `Promise<BuildOutput>`, defined as:
@@ -1596,7 +1569,8 @@ interface BuildConfig {
* When set to `true`, the returned promise rejects with an AggregateError when a build failure happens.
* When set to `false`, the `success` property of the returned object will be `false` when a build failure happens.
*
* This defaults to `true`.
* This defaults to `false` in Bun 1.1 and will change to `true` in Bun 1.2
* as most usage of `Bun.build` forgets to check for errors.
*/
throw?: boolean;
}

View File

@@ -1,6 +1,6 @@
The Bun bundler implements a set of default loaders out of the box. As a rule of thumb, the bundler and the runtime both support the same set of file types out of the box.
`.js` `.cjs` `.mjs` `.mts` `.cts` `.ts` `.tsx` `.jsx` `.toml` `.json` `.yaml` `.yml` `.txt` `.wasm` `.node` `.html`
`.js` `.cjs` `.mjs` `.mts` `.cts` `.ts` `.tsx` `.jsx` `.toml` `.json` `.txt` `.wasm` `.node` `.html`
Bun uses the file extension to determine which built-in _loader_ should be used to parse the file. Every loader has a name, such as `js`, `tsx`, or `json`. These names are used when building [plugins](https://bun.com/docs/bundler/plugins) that extend Bun with custom loaders.
@@ -121,55 +121,6 @@ export default {
{% /codetabs %}
### `yaml`
**YAML loader**. Default for `.yaml` and `.yml`.
YAML files can be directly imported. Bun will parse them with its fast native YAML parser.
```ts
import config from "./config.yaml";
config.database.host; // => "localhost"
// via import attribute:
// import myCustomYAML from './my.config' with {type: "yaml"};
```
During bundling, the parsed YAML is inlined into the bundle as a JavaScript object.
```ts
var config = {
database: {
host: "localhost",
port: 5432,
},
// ...other fields
};
config.database.host;
```
If a `.yaml` or `.yml` file is passed as an entrypoint, it will be converted to a `.js` module that `export default`s the parsed object.
{% codetabs %}
```yaml#Input
name: John Doe
age: 35
email: johndoe@example.com
```
```js#Output
export default {
name: "John Doe",
age: 35,
email: "johndoe@example.com"
}
```
{% /codetabs %}
For more details on YAML support including the runtime API `Bun.YAML.parse()`, see the [YAML API documentation](/docs/api/yaml).
### `text`
**Text loader**. Default for `.txt`.

View File

@@ -9,7 +9,6 @@ Plugins can register callbacks to be run at various points in the lifecycle of a
- [`onStart()`](#onstart): Run once the bundler has started a bundle
- [`onResolve()`](#onresolve): Run before a module is resolved
- [`onLoad()`](#onload): Run before a module is loaded.
- [`onEnd()`](#onend): Run after the bundle has completed
- [`onBeforeParse()`](#onbeforeparse): Run zero-copy native addons in the parser thread before a file is parsed.
### Reference
@@ -19,7 +18,6 @@ A rough overview of the types (please refer to Bun's `bun.d.ts` for the full typ
```ts
type PluginBuilder = {
onStart(callback: () => void): void;
onEnd(callback: (result: BuildOutput) => void | Promise<void>): void;
onResolve: (
args: { filter: RegExp; namespace?: string },
callback: (args: { path: string; importer: string }) => {
@@ -287,53 +285,6 @@ plugin({
Note that the `.defer()` function currently has the limitation that it can only be called once per `onLoad` callback.
### `onEnd`
```ts
onEnd(callback: (result: BuildOutput) => void | Promise<void>): void;
```
Registers a callback to be run when the bundler completes a bundle (whether successful or not).
The callback receives the `BuildOutput` object containing:
- `success`: boolean indicating if the build succeeded
- `outputs`: array of generated build artifacts
- `logs`: array of build messages (warnings, errors, etc.)
This is useful for post-processing, cleanup, notifications, or custom error handling.
```ts
await Bun.build({
entrypoints: ["./index.ts"],
outdir: "./out",
plugins: [
{
name: "onEnd example",
setup(build) {
build.onEnd(result => {
if (result.success) {
console.log(
`✅ Build succeeded with ${result.outputs.length} outputs`,
);
} else {
console.error(`❌ Build failed with ${result.logs.length} errors`);
}
});
},
},
],
});
```
The `onEnd` callbacks are called:
- **Before** the build promise resolves or rejects
- **After** all bundling is complete
- **In the order** they were registered
Multiple plugins can register `onEnd` callbacks, and they will all be called sequentially. If an `onEnd` callback returns a promise, the build will wait for it to resolve before continuing.
## Native plugins
One of the reasons why Bun's bundler is so fast is that it is written in native code and leverages multi-threading to load and parse modules in parallel.

View File

@@ -158,7 +158,7 @@ See [Test > Lifecycle](https://bun.com/docs/test/lifecycle) for complete documen
## Mocks
Create mock functions with the `mock` function.
Create mock functions with the `mock` function. Mocks are automatically reset between tests.
```ts
import { test, expect, mock } from "bun:test";

View File

@@ -1,76 +0,0 @@
---
name: Import a YAML file
---
Bun natively supports `.yaml` and `.yml` imports.
```yaml#config.yaml
database:
host: localhost
port: 5432
name: myapp
server:
port: 3000
timeout: 30
features:
auth: true
rateLimit: true
```
---
Import the file like any other source file.
```ts
import config from "./config.yaml";
config.database.host; // => "localhost"
config.server.port; // => 3000
config.features.auth; // => true
```
---
You can also use named imports to destructure top-level properties:
```ts
import { database, server, features } from "./config.yaml";
console.log(database.name); // => "myapp"
console.log(server.timeout); // => 30
console.log(features.rateLimit); // => true
```
---
Bun also supports [Import Attributes](https://github.com/tc39/proposal-import-attributes) syntax:
```ts
import config from "./config.yaml" with { type: "yaml" };
config.database.port; // => 5432
```
---
For parsing YAML strings at runtime, use `Bun.YAML.parse()`:
```ts
const yamlString = `
name: John Doe
age: 30
hobbies:
- reading
- coding
`;
const data = Bun.YAML.parse(yamlString);
console.log(data.name); // => "John Doe"
console.log(data.hobbies); // => ["reading", "coding"]
```
---
See [Docs > API > YAML](https://bun.com/docs/api/yaml) for complete documentation on YAML support in Bun.

View File

@@ -17,7 +17,7 @@ Bun reads the following files automatically (listed in order of increasing prece
- `.env`
- `.env.production`, `.env.development`, `.env.test` (depending on value of `NODE_ENV`)
- `.env.local` (not loaded when `NODE_ENV=test`)
- `.env.local`
```txt#.env
FOO=hello

View File

@@ -14,7 +14,7 @@ if (typeof Bun !== "undefined") {
---
In TypeScript environments, the previous approach will result in a type error unless `@types/bun` is installed. To avoid this, you can check `process.versions` instead.
In TypeScript environments, the previous approach will result in a type error unless `bun-types` is globally installed. To avoid this, you can check `process.versions` instead.
```ts
if (process.versions.bun) {

View File

@@ -1,81 +0,0 @@
Bun's package manager can scan packages for security vulnerabilities before installation, helping protect your applications from supply chain attacks and known vulnerabilities.
## Quick Start
Configure a security scanner in your `bunfig.toml`:
```toml
[install.security]
scanner = "@acme/bun-security-scanner"
```
When configured, Bun will:
- Scan all packages before installation
- Display security warnings and advisories
- Cancel installation if critical vulnerabilities are found
- Automatically disable auto-install for security
## How It Works
Security scanners analyze packages during `bun install`, `bun add`, and other package operations. They can detect:
- Known security vulnerabilities (CVEs)
- Malicious packages
- License compliance issues
- ...and more!
### Security Levels
Scanners report issues at two severity levels:
- **`fatal`** - Installation stops immediately, exits with non-zero code
- **`warn`** - In interactive terminals, prompts to continue; in CI, exits immediately
## Using Pre-built Scanners
Many security companies publish Bun security scanners as npm packages that you can install and use immediately.
### Installing a Scanner
Install a security scanner from npm:
```bash
$ bun add -d @acme/bun-security-scanner
```
> **Note:** Consult your security scanner's documentation for their specific package name and installation instructions. Most scanners will be installed with `bun add`.
### Configuring the Scanner
After installation, configure it in your `bunfig.toml`:
```toml
[install.security]
scanner = "@acme/bun-security-scanner"
```
### Enterprise Configuration
Some enterprise scanners might support authentication and/or configuration through environment variables:
```bash
# This might go in ~/.bashrc, for example
export SECURITY_API_KEY="your-api-key"
# The scanner will now use these credentials automatically
bun install
```
Consult your security scanner's documentation to learn which environment variables to set and if any additional configuration is required.
### Authoring your own scanner
For a complete example with tests and CI setup, see the official template:
[github.com/oven-sh/security-scanner-template](https://github.com/oven-sh/security-scanner-template)
## Related
- [Configuration (bunfig.toml)](/docs/runtime/bunfig#install-security-scanner)
- [Package Manager](/docs/install)
- [Security Scanner Template](https://github.com/oven-sh/security-scanner-template)

View File

@@ -219,9 +219,6 @@ export default {
page("install/npmrc", ".npmrc support", {
description: "Bun supports loading some configuration options from .npmrc",
}),
page("install/security-scanner-api", "Security Scanner API", {
description: "Scan your project for vulnerabilities with Bun's security scanner API.",
}),
// page("install/utilities", "Utilities", {
// description: "Use `bun pm` to introspect your global module cache or project dependency tree.",
// }),
@@ -386,9 +383,6 @@ export default {
page("api/spawn", "Child processes", {
description: `Spawn sync and async child processes with easily configurable input and output streams.`,
}), // "`Bun.spawn`"),
page("api/yaml", "YAML", {
description: `Bun.YAML.parse(string) lets you parse YAML files in JavaScript`,
}), // "`Bun.spawn`"),
page("api/html-rewriter", "HTMLRewriter", {
description: `Parse and transform HTML with Bun's native HTMLRewriter API, inspired by Cloudflare Workers.`,
}), // "`HTMLRewriter`"),

View File

@@ -195,12 +195,12 @@ Click the link in the right column to jump to the associated documentation.
---
- Parsing & Formatting
- [`Bun.semver`](https://bun.com/docs/api/semver), `Bun.TOML.parse`, [`Bun.YAML.parse`](https://bun.com/docs/api/yaml), [`Bun.color`](https://bun.com/docs/api/color)
- [`Bun.semver`](https://bun.com/docs/api/semver), `Bun.TOML.parse`, [`Bun.color`](https://bun.com/docs/api/color)
---
- Low-level / Internals
- `Bun.mmap`, `Bun.gc`, `Bun.generateHeapSnapshot`, [`bun:jsc`](https://bun.com/reference/bun/jsc)
- `Bun.mmap`, `Bun.gc`, `Bun.generateHeapSnapshot`, [`bun:jsc`](https://bun.com/docs/api/bun-jsc)
---

View File

@@ -94,7 +94,6 @@ Bun supports the following loaders:
- `file`
- `json`
- `toml`
- `yaml`
- `wasm`
- `napi`
- `base64`
@@ -497,62 +496,6 @@ Whether to generate a non-Bun lockfile alongside `bun.lock`. (A `bun.lock` will
print = "yarn"
```
### `install.security.scanner`
Configure a security scanner to scan packages for vulnerabilities before installation.
First, install a security scanner from npm:
```bash
$ bun add -d @acme/bun-security-scanner
```
Then configure it in your `bunfig.toml`:
```toml
[install.security]
scanner = "@acme/bun-security-scanner"
```
When a security scanner is configured:
- Auto-install is automatically disabled for security
- Packages are scanned before installation
- Installation is cancelled if fatal issues are found
- Security warnings are displayed during installation
Learn more about [using and writing security scanners](/docs/install/security).
### `install.linker`
Configure the default linker strategy. Default `"hoisted"`.
For complete documentation refer to [Package manager > Isolated installs](https://bun.com/docs/install/isolated).
```toml
[install]
linker = "hoisted"
```
Valid values are:
{% table %}
- Value
- Description
---
- `"hoisted"`
- Link dependencies in a shared `node_modules` directory.
---
- `"isolated"`
- Link dependencies inside each package installation.
{% /table %}
<!-- ## Debugging -->
<!--

View File

@@ -8,10 +8,6 @@ Bun reads the following files automatically (listed in order of increasing prece
- `.env.production`, `.env.development`, `.env.test` (depending on value of `NODE_ENV`)
- `.env.local`
{% callout %}
**Note:** When `NODE_ENV=test`, `.env.local` is **not** loaded. This ensures consistent test environments across different executions by preventing local overrides during testing. This behavior matches popular frameworks like [Next.js](https://nextjs.org/docs/pages/guides/environment-variables#test-environment-variables) and [Create React App](https://create-react-app.dev/docs/adding-custom-environment-variables/#what-other-env-files-can-be-used).
{% /callout %}
```txt#.env
FOO=hello
BAR=world

View File

@@ -92,18 +92,15 @@ every file before execution. Its transpiler can directly run TypeScript and JSX
## JSX
## JSON, TOML, and YAML
## JSON and TOML
Source files can import `*.json`, `*.toml`, or `*.yaml` files to load their contents as plain JavaScript objects.
Source files can import a `*.json` or `*.toml` file to load its contents as a plain old JavaScript object.
```ts
import pkg from "./package.json";
import bunfig from "./bunfig.toml";
import config from "./config.yaml";
```
See the [YAML API documentation](/docs/api/yaml) for more details on YAML support.
## WASI
{% callout %}

View File

@@ -52,18 +52,15 @@ Hello world!
{% /codetabs %}
## JSON, TOML, and YAML
## JSON and TOML
JSON, TOML, and YAML files can be directly imported from a source file. The contents will be loaded and returned as a JavaScript object.
JSON and TOML files can be directly imported from a source file. The contents will be loaded and returned as a JavaScript object.
```ts
import pkg from "./package.json";
import data from "./data.toml";
import config from "./config.yaml";
```
For more details on YAML support, see the [YAML API documentation](/docs/api/yaml).
## WASI
{% callout %}

View File

@@ -148,7 +148,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
### [`node:vm`](https://nodejs.org/api/vm.html)
🟡 Core functionality and ES modules are implemented, including `vm.Script`, `vm.createContext`, `vm.runInContext`, `vm.runInNewContext`, `vm.runInThisContext`, `vm.compileFunction`, `vm.isContext`, `vm.Module`, `vm.SourceTextModule`, `vm.SyntheticModule`, and `importModuleDynamically` support. Options like `timeout` and `breakOnSigint` are fully supported. Missing `vm.measureMemory` and some `cachedData` functionality.
🟡 Core functionality works, but experimental VM ES modules are not implemented, including `vm.Module`, `vm.SourceTextModule`, `vm.SyntheticModule`,`importModuleDynamically`, and `vm.measureMemory`. Options like `timeout`, `breakOnSigint`, `cachedData` are not implemented yet.
### [`node:wasi`](https://nodejs.org/api/wasi.html)
@@ -214,10 +214,6 @@ The table below lists all globals implemented by Node.js and Bun's current compa
🟢 Fully implemented.
### [`Atomics`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics)
🟢 Fully implemented.
### [`BroadcastChannel`](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel)
🟢 Fully implemented.

View File

@@ -532,74 +532,6 @@ Hello World! pwd=C:\Users\Demo
Bun Shell is a small programming language in Bun that is implemented in Zig. It includes a handwritten lexer, parser, and interpreter. Unlike bash, zsh, and other shells, Bun Shell runs operations concurrently.
## Security in the Bun shell
By design, the Bun shell _does not invoke a system shell_ (like `/bin/sh`) and
is instead a re-implementation of bash that runs in the same Bun process,
designed with security in mind.
When parsing command arguments, it treats all _interpolated variables_ as single, literal strings.
This protects the Bun shell against **command injection**:
```js
import { $ } from "bun";
const userInput = "my-file.txt; rm -rf /";
// SAFE: `userInput` is treated as a single quoted string
await $`ls ${userInput}`;
```
In the above example, `userInput` is treated as a single string. This causes
the `ls` command to try to read the contents of a single directory named
"my-file; rm -rf /".
### Security considerations
While command injection is prevented by default, developers are still
responsible for security in certain scenarios.
Similar to the `Bun.spawn` or `node:child_process.exec()` APIs, you can intentionally
execute a command which spawns a new shell (e.g. `bash -c`) with arguments.
When you do this, you hand off control, and Bun's built-in protections no
longer apply to the string interpreted by that new shell.
```js
import { $ } from "bun";
const userInput = "world; touch /tmp/pwned";
// UNSAFE: You have explicitly started a new shell process with `bash -c`.
// This new shell will execute the `touch` command. Any user input
// passed this way must be rigorously sanitized.
await $`bash -c "echo ${userInput}"`;
```
### Argument injection
The Bun shell cannot know how an external command interprets its own
command-line arguments. An attacker can supply input that the target program
recognizes as one of its own options or flags, leading to unintended behavior.
```js
import { $ } from "bun";
// Malicious input formatted as a Git command-line flag
const branch = "--upload-pack=echo pwned";
// UNSAFE: While Bun safely passes the string as a single argument,
// the `git` program itself sees and acts upon the malicious flag.
await $`git ls-remote origin ${branch}`;
```
{% callout %}
**Recommendation** — As is best practice in every language, always sanitize
user-provided input before passing it as an argument to an external command.
The responsibility for validating arguments rests with your application code.
{% /callout %}
## Credits
Large parts of this API were inspired by [zx](https://github.com/google/zx), [dax](https://github.com/dsherret/dax), and [bnx](https://github.com/wobsoriano/bnx). Thank you to the authors of those projects.

View File

@@ -12,8 +12,6 @@ test("NODE_ENV is set to test", () => {
});
```
When `NODE_ENV` is set to `"test"`, Bun will not load `.env.local` files. This ensures consistent test environments across different executions by preventing local overrides during testing. Instead, use `.env.test` for test-specific environment variables, which should be committed to your repository for consistency across all developers and CI environments.
#### `$TZ` environment variable
By default, all `bun test` runs use UTC (`Etc/UTC`) as the time zone unless overridden by the `TZ` environment variable. This ensures consistent date and time behavior across different development environments.

View File

@@ -426,54 +426,6 @@ test("exactly two assertions", () => {
This helps ensure all your assertions run, especially in complex async code with multiple code paths.
## Type Testing
Bun includes `expectTypeOf` for testing typescript types, compatible with Vitest.
### expectTypeOf
{% callout %}
**Note** — These functions are no-ops at runtime - you need to run TypeScript separately to verify the type checks.
{% endcallout %}
The `expectTypeOf` function provides type-level assertions that are checked by TypeScript's type checker. **Important**:
To test your types:
1. Write your type assertions using `expectTypeOf`
2. Run `bunx tsc --noEmit` to check that your types are correct
```ts
import { expectTypeOf } from "bun:test";
// Basic type assertions
expectTypeOf<string>().toEqualTypeOf<string>();
expectTypeOf(123).toBeNumber();
expectTypeOf("hello").toBeString();
// Object type matching
expectTypeOf({ a: 1, b: "hello" }).toMatchObjectType<{ a: number }>();
// Function types
function greet(name: string): string {
return `Hello ${name}`;
}
expectTypeOf(greet).toBeFunction();
expectTypeOf(greet).parameters.toEqualTypeOf<[string]>();
expectTypeOf(greet).returns.toEqualTypeOf<string>();
// Array types
expectTypeOf([1, 2, 3]).items.toBeNumber();
// Promise types
expectTypeOf(Promise.resolve(42)).resolves.toBeNumber();
```
For full documentation on expectTypeOf matchers, see the [API Reference](/reference/bun/test/expectTypeOf)
## Matchers
Bun implements the following matchers. Full Jest compatibility is on the roadmap; track progress [here](https://github.com/oven-sh/bun/issues/1825).
@@ -677,17 +629,17 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
---
-
-
- [`.toHaveReturnedWith()`](https://jestjs.io/docs/expect#tohavereturnedwithvalue)
---
-
-
- [`.toHaveLastReturnedWith()`](https://jestjs.io/docs/expect#tohavelastreturnedwithvalue)
---
-
-
- [`.toHaveNthReturnedWith()`](https://jestjs.io/docs/expect#tohaventhreturnedwithnthcall-value)
---

1
examples/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
bun-examples-all

View File

7
examples/add.rs Normal file
View File

@@ -0,0 +1,7 @@
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
a + b
}
// to compile:
// rustc --crate-type cdylib add.rs

12
examples/add.ts Normal file
View File

@@ -0,0 +1,12 @@
import { dlopen, suffix } from "bun:ffi";
const {
symbols: { add },
} = dlopen(`./libadd.${suffix}`, {
add: {
args: ["i32", "i32"],
returns: "i32",
},
});
console.log(add(1, 2));

6
examples/add.zig Normal file
View File

@@ -0,0 +1,6 @@
pub export fn add(a: i32, b: i32) i32 {
return a + b;
}
// to compile:
// zig build-lib -OReleaseFast ./add.zig -dynamic --name add

View File

@@ -0,0 +1,89 @@
// To run this example:
//
// bun --hot bun-hot-websockets.js
//
const css = ([inner]) => {
return inner;
};
const styles = css`
#bun {
margin: 0 auto;
margin-top: 200px;
object-fit: cover;
}
html,
body {
margin: 0;
padding: 0;
}
body {
background: #f1239f;
font-family: "Inter", sans-serif;
display: flex;
align-items: center;
justify-content: center;
align-content: center;
color: white;
}
h1 {
padding: 0;
text-align: center;
font-size: 3rem;
-webkit-text-stroke: 2px black;
}
* {
box-sizing: border-box;
}
`;
Bun.serve({
websocket: {
message(ws, msg) {
ws.send(styles);
},
},
fetch(req, server) {
if (req.url.endsWith("/hot")) {
if (server.upgrade(req))
return new Response("", {
status: 101,
});
}
return new Response(
`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebSockets</title>
</head>
<body>
<style></style>
<script>
const ws = new WebSocket("ws://localhost:3000/hot");
const style = document.querySelector("style");
ws.onmessage = (e) => {
style.innerHTML = e.data;
};
setInterval(() => {
ws.send("ping");
}, 8);
</script>
<div id="app">
<img src="https://bun.com/logo.svg" alt="Bun" id='bun' />
<h1>bun --hot websockets</h1>
</div>
</body>
`,
{
headers: {
"Content-Type": "text/html; charset=utf-8",
},
},
);
},
});

9
examples/cat.ts Normal file
View File

@@ -0,0 +1,9 @@
import { resolve } from "path";
const { write, stdout, file } = Bun;
import { argv } from "process";
const path = resolve(argv.at(-1)!);
await write(stdout, file(path));
Bun.stdout;
process.stdout;

View File

@@ -0,0 +1,11 @@
const sequence = [1, 2, 3];
sequence.toReversed(); // => [3, 2, 1]
sequence; // => [1, 2, 3]
const outOfOrder = new Uint8Array([3, 1, 2]);
outOfOrder.toSorted(); // => Uint8Array [1, 2, 3]
outOfOrder; // => Uint8Array [3, 1, 2]
const correctionNeeded = [1, 1, 3];
correctionNeeded.with(1, 2); // => [1, 2, 3]
correctionNeeded; // => [1, 1, 3]

23
examples/hashing.js Normal file
View File

@@ -0,0 +1,23 @@
// Accepts a string, TypedArray, or Blob (file blob support is not implemented but planned)
const input = "hello world".repeat(400);
// Bun.hash() defaults to Wyhash because it's fast
console.log(Bun.hash(input));
console.log(Bun.hash.wyhash(input));
// and returns a bigint
// all of these hashing functions return number if 32-bit or bigint if 64-bit, not typed arrays.
console.log(Bun.hash.adler32(input)); // number
console.log(Bun.hash.crc32(input)); // number
console.log(Bun.hash.cityHash32(input)); // number
console.log(Bun.hash.cityHash64(input)); // bigint
console.log(Bun.hash.xxHash32(input)); // number
console.log(Bun.hash.xxHash64(input)); // bigint
console.log(Bun.hash.xxHash3(input)); // bigint
console.log(Bun.hash.murmur32v3(input)); // number
console.log(Bun.hash.murmur32v2(input)); // number
console.log(Bun.hash.murmur64v2(input)); // bigint
console.log(Bun.hash.rapidhash(input)); // bigint
// Second argument accepts a seed where relevant
console.log(Bun.hash(input, 12345));

37
examples/html-rewriter.ts Normal file
View File

@@ -0,0 +1,37 @@
// Start a fast HTTP server from a function
Bun.serve({
async fetch(req) {
const { pathname } = new URL(req.url);
if (!(pathname.startsWith("/https://") || pathname.startsWith("/http://"))) {
return new Response("Enter a path that starts with https:// or http://\n", {
status: 400,
});
}
const response = await fetch(req.url.substring("http://localhost:3000/".length), req.clone());
return new HTMLRewriter()
.on("a[href]", {
element(element) {
element.setAttribute("href", "https://www.youtube.com/watch?v=dQw4w9WgXcQ");
},
})
.transform(response);
},
// this is called when fetch() throws or rejects
// error(err: Error) {
// },
// this boolean enables the bun's default error handler
// sometime after the initial release, it will auto reload as well
development: process.env.NODE_ENV !== "production",
// note: this isn't node, but for compatibility bun supports process.env + more stuff in process
// SSL is enabled if these two are set
// certFile: './cert.pem',
// keyFile: './key.pem',
port: 3000, // number or string
});

View File

@@ -0,0 +1,76 @@
import { file, serve } from "bun";
import { existsSync, statSync } from "fs";
serve({
fetch(req: Request) {
let pathname = new URL(req.url).pathname.substring(1);
if (pathname == "") {
pathname = import.meta.url.replace("file://", "");
}
if (!existsSync(pathname)) {
return new Response(null, { status: 404 });
}
const stats = statSync(pathname);
// https://github.com/gornostay25/svelte-adapter-bun/blob/master/src/sirv.js
const headers = new Headers({
"Content-Length": "" + stats.size,
"Last-Modified": stats.mtime.toUTCString(),
ETag: `W/"${stats.size}-${stats.mtime.getTime()}"`,
});
if (req.headers.get("if-none-match") === headers.get("ETag")) {
return new Response(null, { status: 304 });
}
const opts = { code: 200, start: 0, end: Infinity, range: false };
if (req.headers.has("range")) {
opts.code = 206;
let [x, y] = req.headers.get("range")!.replace("bytes=", "").split("-");
let end = (opts.end = parseInt(y, 10) || stats.size - 1);
let start = (opts.start = parseInt(x, 10) || 0);
if (start >= stats.size || end >= stats.size) {
headers.set("Content-Range", `bytes */${stats.size}`);
return new Response(null, {
headers: headers,
status: 416,
});
}
headers.set("Content-Range", `bytes ${start}-${end}/${stats.size}`);
headers.set("Content-Length", "" + (end - start + 1));
headers.set("Accept-Ranges", "bytes");
opts.range = true;
}
if (opts.range) {
return new Response(file(pathname).slice(opts.start, opts.end), {
headers,
status: opts.code,
});
}
return new Response(file(pathname), { headers, status: opts.code });
},
// this is called when fetch() throws or rejects
// error(err: Error) {
// return new Response("uh oh! :(" + String(err.toString()), { status: 500 });
// },
// this boolean enables the bun's default error handler
// sometime after the initial release, it will auto reload as well
development: process.env.NODE_ENV !== "production",
// note: this isn't node, but for compatibility bun supports process.env + more stuff in process
// SSL is enabled if these two are set
// certFile: './cert.pem',
// keyFile: './key.pem',
port: 3000, // number or string
hostname: "localhost", // defaults to 0.0.0.0
});

31
examples/http-file.ts Normal file
View File

@@ -0,0 +1,31 @@
import { file, serve } from "bun";
serve({
fetch(req: Request) {
const pathname = new URL(req.url).pathname.substring(1);
// If the URL is empty, display this file.
if (pathname === "") {
return new Response(file(import.meta.url.replace("file://", "")));
}
return new Response(file(pathname));
},
// this is called when fetch() throws or rejects
// error(err: Error) {
// return new Response("uh oh! :(" + String(err.toString()), { status: 500 });
// },
// this boolean enables the bun's default error handler
// sometime after the initial release, it will auto reload as well
development: process.env.NODE_ENV !== "production",
// note: this isn't node, but for compatibility bun supports process.env + more stuff in process
// SSL is enabled if these two are set
// certFile: './cert.pem',
// keyFile: './key.pem',
port: 3000, // number or string
hostname: "localhost", // defaults to 0.0.0.0
});

View File

@@ -0,0 +1,17 @@
import { serve } from "bun";
serve({
async fetch(req) {
// body is a ReadableStream
const body = req.body;
const writer = Bun.file(`upload.${Date.now()}.txt`).writer();
for await (const chunk of body!) {
writer.write(chunk);
}
const wrote = await writer.end();
// @ts-ignore
return Response.json({ wrote, type: req.headers.get("Content-Type") });
},
});

12
examples/http-stop.ts Normal file
View File

@@ -0,0 +1,12 @@
import { serve } from "bun";
const server = serve({
fetch(req) {
return new Response(`Pending requests count: ${this.pendingRequests}`);
},
});
// Stop the server after 5 seconds
setTimeout(() => {
server.stop();
}, 5000);

34
examples/http.ts Normal file
View File

@@ -0,0 +1,34 @@
// Start a fast HTTP server from a function
Bun.serve({
fetch(req: Request) {
return new Response(`Echo: ${req.url}`);
},
// baseURI: "http://localhost:3000",
// this is called when fetch() throws or rejects
// error(err: Error) {
// return new Response("uh oh! :(\n" + err.toString(), { status: 500 });
// },
// this boolean enables bun's default error handler
development: process.env.NODE_ENV !== "production",
// note: this isn't node, but for compatibility bun supports process.env + more stuff in process
// SSL is enabled if these two are set
// certFile: './cert.pem',
// keyFile: './key.pem',
port: 3000, // number or string
});
// Start a fast HTTP server from the main file's export
// export default {
// fetch(req) {
// return new Response(
// `This is another way to start a server!
// if the main file export default's an object
// with 'fetch'. Bun automatically calls Bun.serve`
// );
// },
// // so autocomplete & type checking works
// } as Bun.Serve;

193
examples/lambda.ts Normal file
View File

@@ -0,0 +1,193 @@
const { AWS_LAMBDA_RUNTIME_API, LAMBDA_TASK_ROOT, _HANDLER } = process.env;
if (!AWS_LAMBDA_RUNTIME_API || AWS_LAMBDA_RUNTIME_API === "") {
throw new Error("AWS_LAMBDA_RUNTIME_API is not set");
}
const nextURL = `http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next`;
const sourceDir = LAMBDA_TASK_ROOT;
if (!sourceDir) {
throw new Error("handler is not set");
}
if (!_HANDLER) {
throw new Error("handler is not set");
}
// don't care if this fails
if (process.cwd() !== sourceDir) {
try {
process.chdir(sourceDir);
} catch (e) {}
}
var handlerDot = _HANDLER.lastIndexOf(".");
var sourcefile = handlerDot > 0 ? _HANDLER.substring(0, handlerDot) : _HANDLER;
if (sourcefile.length === 0) {
throw new Error("handler is not set");
}
if (!sourcefile.startsWith("/")) {
sourcefile = `./${sourcefile}`;
}
function noop() {}
const method = (handlerDot > 0 ? _HANDLER.substring(handlerDot) : "") || "GET";
if (typeof process.env.VERBOSE !== "undefined") {
console.time(`Loaded ${sourcefile}`);
}
var Handler;
try {
Handler = await import(sourcefile);
} catch (e: any) {
console.error("Error loading sourcefile:", e);
try {
await fetch(new URL(`http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/init/error`).href, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
errorMessage: e.message,
errorType: e.name,
stackTrace: e?.stack?.split("\n") ?? [],
}),
});
} catch (e2) {
console.error("Error sending error to runtime:", e2);
}
process.exit(1);
}
if (typeof process.env.VERBOSE !== "undefined") {
console.timeEnd(`Loaded ${sourcefile}`);
}
const handlerFunction = Handler.default?.fetch;
if (typeof handlerFunction !== "function") {
const e = new Error(`${sourcefile} must export default a function called fetch
Here is an example:
export default {
fetch(req) {
return new Response("Hello World");
}
}
`);
console.error(e);
try {
await fetch(new URL(`http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/init/error`).href, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
errorMessage: e.message,
errorType: e.name,
stackTrace: e?.stack?.split("\n") ?? [],
}),
});
} catch (e2) {
console.error("Error sending error to runtime:", e2);
}
process.exit(1);
}
var baseURLString = AWS_LAMBDA_RUNTIME_API;
if ("baseURI" in Handler.default) {
baseURLString = Handler.default.baseURI?.toString();
}
var baseURL;
try {
baseURL = new URL(baseURLString);
} catch (e: any) {
console.error("Error parsing baseURI:", e);
try {
await fetch(new URL(`http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/init/error`).href, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
errorMessage: e.message,
errorType: e.name,
stackTrace: e?.stack?.split("\n") || [],
}),
});
} catch (e2) {
console.error("Error sending error to runtime:", e2);
}
process.exit(1);
}
async function runHandler(response: Response) {
const traceID = response.headers.get("Lambda-Runtime-Trace-Id");
const requestID = response.headers.get("Lambda-Runtime-Aws-Request-Id");
var request = new Request(baseURL.href, {
method,
headers: response.headers,
body: parseInt(response.headers.get("Content-Length") || "0", 10) > 0 ? await response.blob() : undefined,
});
// we are done with the Response object here
// allow it to be GC'd
(response as any) = undefined;
var result: Response;
try {
if (typeof process.env.VERBOSE !== "undefined") {
console.time(`[${traceID}] Run ${request.url}`);
}
result = handlerFunction(request, {});
if (result && (result as any).then) {
await result;
}
} catch (e1: any) {
if (typeof process.env.VERBOSE !== "undefined") {
console.error(`[${traceID}] Error running handler:`, e1);
}
fetch(`http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/${requestID}/error`, {
method: "POST",
body: JSON.stringify({
errorMessage: e1.message,
errorType: e1.name,
stackTrace: e1?.stack?.split("\n") ?? [],
}),
}).finally(noop);
return;
} finally {
if (typeof process.env.VERBOSE !== "undefined") {
console.timeEnd(`[${traceID}] Run ${request.url}`);
}
}
if (!result || !("headers" in result)) {
await fetch(`http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/${requestID}/error`, {
method: "POST",
body: JSON.stringify({
errorMessage: "Expected Response object",
errorType: "ExpectedResponseObject",
stackTrace: [],
}),
});
return;
}
await fetch(`http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/${requestID}/response`, {
method: "POST",
headers: result.headers,
body: await result.blob(),
});
(result as any) = undefined;
}
while (true) {
fetch(nextURL).then(runHandler, console.error);
}
export {};

48
examples/macros/bun.lock Normal file
View File

@@ -0,0 +1,48 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "macros",
"dependencies": {
"moment": "^2.29.1",
"papaparse": "^5.3.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-refresh": "^0.10.0",
},
"devDependencies": {
"@types/react": "^17.0.24",
"@types/react-dom": "^17.0.9",
},
},
},
"packages": {
"@types/prop-types": ["@types/prop-types@15.7.5", "", {}, "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="],
"@types/react": ["@types/react@17.0.53", "", { "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, "sha512-1yIpQR2zdYu1Z/dc1OxC+MA6GR240u3gcnP4l6mvj/PJiVaqHsQPmWttsvHsfnhfPbU2FuGmo0wSITPygjBmsw=="],
"@types/react-dom": ["@types/react-dom@17.0.19", "", { "dependencies": { "@types/react": "^17" } }, "sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ=="],
"@types/scheduler": ["@types/scheduler@0.16.2", "", {}, "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="],
"csstype": ["csstype@3.1.1", "", {}, "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="],
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"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=="],
"moment": ["moment@2.29.4", "", {}, "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="],
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
"papaparse": ["papaparse@5.3.2", "", {}, "sha512-6dNZu0Ki+gyV0eBsFKJhYr+MdQYAzFUGlBMNj3GNrmHxmz1lfRa24CjFObPXtjcetlOv5Ad299MhIK0znp3afw=="],
"react": ["react@17.0.2", "", { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA=="],
"react-dom": ["react-dom@17.0.2", "", { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "scheduler": "^0.20.2" }, "peerDependencies": { "react": "17.0.2" } }, "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA=="],
"react-refresh": ["react-refresh@0.10.0", "", {}, "sha512-PgidR3wST3dDYKr6b4pJoqQFpPGNKDSCDx4cZoshjXipw3LzO7mG1My2pwEzz2JVkF+inx3xRpDeQLFQGH/hsQ=="],
"scheduler": ["scheduler@0.20.2", "", { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ=="],
}
}

View File

@@ -0,0 +1,30 @@
import { fetchCSV } from "macro:fetchCSV";
export const Covid19 = () => {
const rows = fetchCSV("https://covid19.who.int/WHO-COVID-19-global-data.csv", {
last: 100,
columns: ["New_cases", "Date_reported", "Country"],
});
return (
<div>
<h2>Covid-19</h2>
<h6>last {rows.length} updates from the WHO</h6>
<div className="Table">
<div className="Header">
<div className="Heading">New Cases</div>
<div className="Heading">Date</div>
<div className="Heading">Country</div>
</div>
{rows.map((row, index) => (
<div className="Row" key={index}>
<div className="Column">{row[0]}</div>
<div className="Column">{row[1]}</div>
<div className="Column">{row[2]}</div>
</div>
))}
</div>
</div>
);
};

View File

@@ -0,0 +1,15 @@
// source code
import { matchInFile } from "macro:matchInFile";
export const IPAddresses = () => (
<div>
<h2>recent ip addresses</h2>
<div className="Lines">
{matchInFile("access.log", /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}/).map((ipAddress, index) => (
<div className="Line" key={index}>
{ipAddress}
</div>
))}
</div>
</div>
);

View File

@@ -0,0 +1,15 @@
import * as ReactDOM from "react-dom";
import * as React from "react";
import { IPAddresses } from "./example";
import { Covid19 } from "./covid19";
const Start = function () {
const root = document.createElement("div");
document.body.appendChild(root);
// comment out to switch between examples
// ReactDOM.render(<IPAddresses />, root);
ReactDOM.render(<Covid19 />, root);
};
Start();

View File

@@ -0,0 +1,4 @@
// source code
import { mysteryBox } from "macro:./mystery-box";
export default "You roll! " + mysteryBox(123);

View File

@@ -0,0 +1,54 @@
import Pappa from "papaparse";
// Example usage:
// const rows = fetchCSV(
// "https://covid19.who.int/WHO-COVID-19-global-data.csv",
// {
// last: 100,
// columns: ["New_cases", "Date_reported", "Country"],
// }
// );
export async function fetchCSV(callExpression) {
console.time("fetchCSV Total");
const [
urlNode,
{
properties: { last: limit = 10, columns = [] },
},
] = callExpression.arguments;
const url = urlNode.get();
console.time("Fetch");
const response = await fetch(url);
const csvText = await response.text();
console.timeEnd("Fetch");
console.time("Parse");
let rows = Pappa.parse(csvText, { fastMode: true }).data;
console.timeEnd("Parse");
console.time("Render");
const columnIndices = new Array(columns.length);
for (let i = 0; i < columns.length; i++) {
columnIndices[i] = rows[0].indexOf(columns[i]);
}
rows = rows
.slice(Math.max(limit, rows.length) - limit)
.reverse()
.filter(columns => columns.every(Boolean));
const value = (
<array>
{rows.map(columns => (
<array>
{columnIndices.map(columnIndex => (
<string value={columns[columnIndex]} />
))}
</array>
))}
</array>
);
console.timeEnd("Render");
console.timeEnd("fetchCSV Total");
return value;
}

View File

@@ -0,0 +1,23 @@
// macro code
export async function matchInFile(callExpression: BunAST.CallExpression) {
const [filePathNode, matcherNode] = callExpression.arguments;
let filePath: string;
filePath = filePathNode.get();
let matcher: RegExp;
matcher = matcherNode.get();
const file: string = await Bun.file(Bun.cwd + filePath).text();
return (
<array>
{file
.split("\n")
.map(line => line.match(matcher))
.filter(Boolean)
.reverse()
.map(line => (
<string value={line[0]} />
))}
</array>
);
}

View File

@@ -0,0 +1,13 @@
export function mysteryBox(callExpression) {
console.log(callExpression.log);
// get arguments
const [countNode] = callExpression.arguments;
const countString: string = countNode.get();
const count: number = parseInt(countString, 10);
// validate
if (!(count >= 1 && count <= 1000)) return new Error(`Argument ${countString} is expected to be between 1 and 1000`);
// return a value
return (Math.random() * count) | 0;
}

10
examples/macros/now.tsx Normal file
View File

@@ -0,0 +1,10 @@
import moment from "moment";
export function now(node) {
var fmt = "HH:mm:ss";
const args = node.arguments;
if (args[0] instanceof <string />) {
fmt = args[0].get();
}
const time = moment().format(fmt);
return <string value={time}></string>;
}

View File

@@ -0,0 +1,17 @@
{
"name": "macros",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"moment": "^2.29.1",
"papaparse": "^5.3.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-refresh": "^0.10.0"
},
"devDependencies": {
"@types/react": "^17.0.24",
"@types/react-dom": "^17.0.9"
}
}

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title>Macro test</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/styles.css" type="text/css" />
</head>
<body>
<script async type="module" src="/components/index.tsx"></script>
</body>
</html>

View File

@@ -0,0 +1,47 @@
html {
font-size: 4rem;
margin: 0;
padding: 0;
background-color: black;
color: rgb(0, 255, 0);
font-family: "Courier";
}
body {
margin: 48px auto;
text-align: center;
}
.Line {
font-size: 0.5rem;
font-family: monospace;
}
.Table {
display: grid;
width: fit-content;
}
.Row,
.Header {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
text-align: right;
column-gap: 2rem;
}
.Heading {
text-align: right;
}
.Header {
border-bottom: 1px solid rgb(0, 255, 0);
margin-bottom: 20px;
padding-bottom: 20px;
}
.Heading:nth-of-type(2) {
text-align: left;
}

View File

@@ -0,0 +1,7 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {},
"jsx": "preserve"
}
}

11
examples/mmap/1.js Normal file
View File

@@ -0,0 +1,11 @@
const map = Bun.mmap("./mmap.txt", { shared: true });
const utf8decoder = new TextDecoder("utf-8");
let old = new TextEncoder().encode("12345");
setInterval(() => {
old = old.sort((a, b) => (Math.random() > 0.5 ? -1 : 1));
console.log(`changing mmap to ~> ${utf8decoder.decode(old)}`);
map.set(old);
}, 4);

22
examples/mmap/2.js Normal file
View File

@@ -0,0 +1,22 @@
const map = Bun.mmap("./mmap.txt");
function buffer_hash(buffer) {
let hash = 0;
for (let i = 0; i < buffer.length; i++) {
hash = (hash << 5) - hash + buffer[i];
hash |= 0; // Convert to 32bit integer
}
return hash;
}
const decoder = new TextDecoder();
let hash = buffer_hash(map);
console.log(decoder.decode(map));
while (true) {
if (buffer_hash(map) !== hash) {
hash = buffer_hash(map);
console.log(`mmap changed to ~> ${decoder.decode(map)}`);
}
}

1
examples/mmap/mmap.txt Normal file
View File

@@ -0,0 +1 @@
43521

23
examples/openInEditor.js Normal file
View File

@@ -0,0 +1,23 @@
import { resolve } from "path";
import { parse } from "querystring";
export default {
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/favicon.ico") return new Response("nooo dont open favicon in editor", { status: 404 });
var pathname = req.url.substring(1);
const q = pathname.indexOf("?");
var { editor } = parse(pathname.substring(q + 1)) || {};
if (q > 0) {
pathname = pathname.substring(0, q);
}
Bun.openInEditor(resolve(pathname), {
editor,
});
return new Response(`Opened ${req.url}`);
},
};

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