Compare commits

..

8 Commits

Author SHA1 Message Date
Jarred Sumner
8bc9b2e741 Merge branch 'main' into dylan/fix-worker-threads-double-dispatch 2026-01-29 01:28:02 -08:00
Dylan Conway
45302e60b1 Merge branch 'main' into dylan/fix-worker-threads-double-dispatch 2026-01-23 10:43:15 -08:00
Jarred Sumner
657feebdf6 Merge branch 'main' into dylan/fix-worker-threads-double-dispatch 2026-01-20 22:43:03 -08:00
Claude Bot
0f59bb00b2 fix(worker_threads): dispatch messages synchronously to prevent race with exit
The previous implementation used postTask to defer message dispatch from
the parent's MessagePort to the Worker object. This caused a race condition
where the worker could exit before the queued message was processed,
resulting in the message event never firing.

Changed to dispatch the message event synchronously. This is safe because:
1. Worker is a different EventTarget from MessagePort, so no "event
   already being dispatched" assertion will fire
2. Synchronous dispatch ensures messages are processed before exit events

This fixes the test-worker-sharedarraybuffer-from-worker-thread.js failure
on Windows CI.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 01:21:49 +00:00
Claude Bot
c1da935e5e fix(test): update worker-fixture-argv.js for new parentPort behavior
The fixture was using `globalThis.addEventListener` first (which is
available in worker threads), but with the new MessagePort-based
parentPort, messages from `worker.postMessage()` now correctly go to
parentPort rather than self.onmessage. Updated the fixture to
explicitly check for parentPort availability first.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 00:42:01 +00:00
Dylan Conway
ffd80531a1 update 2026-01-19 22:05:51 -08:00
Dylan Conway
a85133aa3b fix(worker_threads): remove unused self declaration
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Claude-Generated-By: Claude Code (cli/claude-opus-4-5=100%)
Claude-Steers: 0
Claude-Permission-Prompts: 1
Claude-Escapes: 0
2026-01-19 21:27:35 -08:00
Dylan Conway
94d609cd69 fix(worker_threads): use MessagePort for parentPort instead of dispatching to self
Node.js worker_threads delivers messages only to parentPort, not to
self.onmessage. Libraries like fflate set both handlers expecting only
parentPort.on('message') to fire.

Previously, Bun dispatched messages to both self.onmessage AND
parentPort event listeners, causing handlers to run twice.

This fix creates a real MessagePort pair for Node workers:
- Parent keeps port1 (m_parentPort) for worker.postMessage()
- Worker gets port2 as parentPort via entangle()
- WorkerMessageForwarder forwards port1 messages to Worker object

This matches Node.js architecture where worker.postMessage() goes
through a MessagePort channel, not the global scope.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Claude-Generated-By: Claude Code (cli/claude-opus-4-5=100%)
Claude-Steers: 0
Claude-Permission-Prompts: 4
Claude-Escapes: 0
2026-01-19 21:22:48 -08:00
350 changed files with 3078 additions and 26116 deletions

View File

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

View File

@@ -99,23 +99,6 @@ function getTargetLabel(target) {
* @property {string[]} [features]
*/
// Azure VM sizes for Windows CI runners.
// DDSv6 = x64, DPSv6 = ARM64 (Cobalt 100). Quota: 100 cores per family in eastus2.
const azureVmSizes = {
"windows-x64": {
build: "Standard_D16ds_v6", // 16 vCPU, 64 GiB — C++ build, link
test: "Standard_D4ds_v6", // 4 vCPU, 16 GiB — test shards
},
"windows-aarch64": {
build: "Standard_D16ps_v6", // 16 vCPU, 64 GiB — C++ build, link
test: "Standard_D4ps_v6", // 4 vCPU, 16 GiB — test shards
},
};
function getAzureVmSize(os, arch, tier = "build") {
return azureVmSizes[`${os}-${arch}`]?.[tier];
}
/**
* @type {Platform[]}
*/
@@ -126,12 +109,13 @@ const buildPlatforms = [
{ os: "linux", arch: "x64", distro: "amazonlinux", release: "2023", features: ["docker"] },
{ os: "linux", arch: "x64", baseline: true, distro: "amazonlinux", release: "2023", features: ["docker"] },
{ os: "linux", arch: "x64", profile: "asan", distro: "amazonlinux", release: "2023", features: ["docker"] },
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.23" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.23" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.23" },
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.22" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.22" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.22" },
{ os: "windows", arch: "x64", release: "2019" },
{ os: "windows", arch: "x64", baseline: true, release: "2019" },
{ os: "windows", arch: "aarch64", release: "11" },
// TODO: Enable when Windows ARM64 CI runners are ready
// { os: "windows", arch: "aarch64", release: "2019" },
];
/**
@@ -149,12 +133,13 @@ const testPlatforms = [
{ os: "linux", arch: "aarch64", distro: "ubuntu", release: "25.04", tier: "latest" },
{ os: "linux", arch: "x64", distro: "ubuntu", release: "25.04", tier: "latest" },
{ os: "linux", arch: "x64", baseline: true, distro: "ubuntu", release: "25.04", tier: "latest" },
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.23", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.23", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.23", tier: "latest" },
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.22", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.22", tier: "latest" },
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.22", tier: "latest" },
{ os: "windows", arch: "x64", release: "2019", tier: "oldest" },
{ os: "windows", arch: "x64", release: "2019", baseline: true, tier: "oldest" },
{ os: "windows", arch: "aarch64", release: "11", tier: "latest" },
// TODO: Enable when Windows ARM64 CI runners are ready
// { os: "windows", arch: "aarch64", release: "2019", tier: "oldest" },
];
/**
@@ -320,7 +305,7 @@ function getCppAgent(platform, options) {
}
return getEc2Agent(platform, options, {
instanceType: os === "windows" ? getAzureVmSize(os, arch) : arch === "aarch64" ? "c8g.4xlarge" : "c7i.4xlarge",
instanceType: arch === "aarch64" ? "c8g.4xlarge" : "c7i.4xlarge",
});
}
@@ -342,7 +327,7 @@ function getLinkBunAgent(platform, options) {
if (os === "windows") {
return getEc2Agent(platform, options, {
instanceType: getAzureVmSize(os, arch),
instanceType: arch === "aarch64" ? "r8g.large" : "r7i.large",
});
}
@@ -360,7 +345,7 @@ function getZigPlatform() {
arch: "aarch64",
abi: "musl",
distro: "alpine",
release: "3.23",
release: "3.22",
};
}
@@ -369,17 +354,7 @@ function getZigPlatform() {
* @param {PipelineOptions} options
* @returns {Agent}
*/
function getZigAgent(platform, options) {
const { os, arch } = platform;
// Windows builds Zig natively on Azure
if (os === "windows") {
return getEc2Agent(platform, options, {
instanceType: getAzureVmSize(os, arch),
});
}
// Everything else cross-compiles from Linux aarch64
function getZigAgent(_platform, options) {
return getEc2Agent(getZigPlatform(), options, {
instanceType: "r8g.large",
});
@@ -404,7 +379,7 @@ function getTestAgent(platform, options) {
// TODO: delete this block when we upgrade to mimalloc v3
if (os === "windows") {
return getEc2Agent(platform, options, {
instanceType: getAzureVmSize(os, arch, "test"),
instanceType: "c7i.2xlarge",
cpuCount: 2,
threadsPerCore: 1,
});
@@ -488,7 +463,6 @@ function getBuildCommand(target, options, label) {
*/
function getBuildCppStep(platform, options) {
const command = getBuildCommand(platform, options);
return {
key: `${getTargetKey(platform)}-build-cpp`,
label: `${getTargetLabel(platform)} - build-cpp`,
@@ -528,10 +502,7 @@ function getBuildToolchain(target) {
* @returns {Step}
*/
function getBuildZigStep(platform, options) {
const { os, arch } = platform;
const toolchain = getBuildToolchain(platform);
// Native Windows builds don't need a cross-compilation toolchain
const toolchainArg = os === "windows" ? "" : ` --toolchain ${toolchain}`;
return {
key: `${getTargetKey(platform)}-build-zig`,
retry: getRetry(),
@@ -539,7 +510,7 @@ function getBuildZigStep(platform, options) {
agents: getZigAgent(platform, options),
cancel_on_build_failing: isMergeQueue(),
env: getBuildEnv(platform, options),
command: `${getBuildCommand(platform, options)} --target bun-zig${toolchainArg}`,
command: `${getBuildCommand(platform, options)} --target bun-zig --toolchain ${toolchain}`,
timeout_in_minutes: 35,
};
}
@@ -566,109 +537,6 @@ function getLinkBunStep(platform, options) {
};
}
/**
* Returns the artifact triplet for a platform, e.g. "bun-linux-aarch64" or "bun-linux-x64-musl-baseline".
* Matches the naming convention in cmake/targets/BuildBun.cmake.
* @param {Platform} platform
* @returns {string}
*/
function getTargetTriplet(platform) {
const { os, arch, abi, baseline } = platform;
let triplet = `bun-${os}-${arch}`;
if (abi === "musl") {
triplet += "-musl";
}
if (baseline) {
triplet += "-baseline";
}
return triplet;
}
/**
* Returns true if a platform needs QEMU-based baseline CPU verification.
* x64 baseline builds verify no AVX/AVX2 instructions snuck in.
* aarch64 builds verify no LSE/SVE instructions snuck in.
* @param {Platform} platform
* @returns {boolean}
*/
function needsBaselineVerification(platform) {
const { os, arch, baseline } = platform;
if (os !== "linux") return false;
return (arch === "x64" && baseline) || arch === "aarch64";
}
/**
* @param {Platform} platform
* @param {PipelineOptions} options
* @returns {Step}
*/
function getVerifyBaselineStep(platform, options) {
const { arch } = platform;
const targetKey = getTargetKey(platform);
const archArg = arch === "x64" ? "x64" : "aarch64";
return {
key: `${targetKey}-verify-baseline`,
label: `${getTargetLabel(platform)} - verify-baseline`,
depends_on: [`${targetKey}-build-bun`],
agents: getLinkBunAgent(platform, options),
retry: getRetry(),
cancel_on_build_failing: isMergeQueue(),
timeout_in_minutes: 5,
command: [
`buildkite-agent artifact download '*.zip' . --step ${targetKey}-build-bun`,
`unzip -o '${getTargetTriplet(platform)}.zip'`,
`unzip -o '${getTargetTriplet(platform)}-profile.zip'`,
`chmod +x ${getTargetTriplet(platform)}/bun ${getTargetTriplet(platform)}-profile/bun-profile`,
`./scripts/verify-baseline-cpu.sh --arch ${archArg} --binary ${getTargetTriplet(platform)}/bun`,
`./scripts/verify-baseline-cpu.sh --arch ${archArg} --binary ${getTargetTriplet(platform)}-profile/bun-profile`,
],
};
}
/**
* Returns true if the PR modifies SetupWebKit.cmake (WebKit version changes).
* JIT stress tests under QEMU should run when WebKit is updated to catch
* JIT-generated code that uses unsupported CPU instructions.
* @param {PipelineOptions} options
* @returns {boolean}
*/
function hasWebKitChanges(options) {
const { changedFiles = [] } = options;
return changedFiles.some(file => file.includes("SetupWebKit.cmake"));
}
/**
* Returns a step that runs JSC JIT stress tests under QEMU.
* This verifies that JIT-compiled code doesn't use CPU instructions
* beyond the baseline target (no AVX on x64, no LSE on aarch64).
* @param {Platform} platform
* @param {PipelineOptions} options
* @returns {Step}
*/
function getJitStressTestStep(platform, options) {
const { arch } = platform;
const targetKey = getTargetKey(platform);
const archArg = arch === "x64" ? "x64" : "aarch64";
return {
key: `${targetKey}-jit-stress-qemu`,
label: `${getTargetLabel(platform)} - jit-stress-qemu`,
depends_on: [`${targetKey}-build-bun`],
agents: getLinkBunAgent(platform, options),
retry: getRetry(),
cancel_on_build_failing: isMergeQueue(),
// JIT stress tests are slow under QEMU emulation
timeout_in_minutes: 30,
command: [
`buildkite-agent artifact download '*.zip' . --step ${targetKey}-build-bun`,
`unzip -o '${getTargetTriplet(platform)}.zip'`,
`chmod +x ${getTargetTriplet(platform)}/bun`,
`./scripts/verify-jit-stress-qemu.sh --arch ${archArg} --binary ${getTargetTriplet(platform)}/bun`,
],
};
}
/**
* @param {Platform} platform
* @param {PipelineOptions} options
@@ -724,14 +592,14 @@ function getTestBunStep(platform, options, testOptions = {}) {
agents: getTestAgent(platform, options),
retry: getRetry(),
cancel_on_build_failing: isMergeQueue(),
parallelism: os === "darwin" ? 2 : os === "windows" ? 8 : 20,
parallelism: os === "darwin" ? 2 : 20,
timeout_in_minutes: profile === "asan" || os === "windows" ? 45 : 30,
env: {
ASAN_OPTIONS: "allow_user_segv_handler=1:disable_coredump=0:detect_leaks=0",
},
command:
os === "windows"
? `pwsh -NoProfile -File .\\scripts\\vs-shell.ps1 node .\\scripts\\runner.node.mjs ${args.join(" ")}`
? `node .\\scripts\\runner.node.mjs ${args.join(" ")}`
: `./scripts/runner.node.mjs ${args.join(" ")}`,
};
}
@@ -746,7 +614,6 @@ function getBuildImageStep(platform, options) {
const { publishImages } = options;
const action = publishImages ? "publish-image" : "create-image";
const cloud = os === "windows" ? "azure" : "aws";
const command = [
"node",
"./scripts/machine.mjs",
@@ -755,7 +622,7 @@ function getBuildImageStep(platform, options) {
`--arch=${arch}`,
distro && `--distro=${distro}`,
`--release=${release}`,
`--cloud=${cloud}`,
"--cloud=aws",
"--ci",
"--authorized-org=oven-sh",
];
@@ -907,7 +774,6 @@ function getBenchmarkStep() {
* @property {Platform[]} [buildPlatforms]
* @property {Platform[]} [testPlatforms]
* @property {string[]} [testFiles]
* @property {string[]} [changedFiles]
*/
/**
@@ -1177,10 +1043,9 @@ async function getPipelineOptions() {
skipBuilds: parseOption(/\[(skip builds?|no builds?|only tests?)\]/i),
forceBuilds: parseOption(/\[(force builds?)\]/i),
skipTests: parseOption(/\[(skip tests?|no tests?|only builds?)\]/i),
buildImages: parseOption(/\[(build (?:(?:windows|linux) )?images?)\]/i),
buildImages: parseOption(/\[(build images?)\]/i),
dryRun: parseOption(/\[(dry run)\]/i),
publishImages: parseOption(/\[(publish (?:(?:windows|linux) )?images?)\]/i),
imageFilter: (commitMessage.match(/\[(?:build|publish) (windows|linux) images?\]/i) || [])[1]?.toLowerCase(),
publishImages: parseOption(/\[(publish images?)\]/i),
buildPlatforms: Array.from(buildPlatformsMap.values()),
testPlatforms: Array.from(testPlatformsMap.values()),
};
@@ -1205,12 +1070,11 @@ async function getPipeline(options = {}) {
return;
}
const { buildPlatforms = [], testPlatforms = [], buildImages, publishImages, imageFilter } = options;
const { buildPlatforms = [], testPlatforms = [], buildImages, publishImages } = options;
const imagePlatforms = new Map(
buildImages || publishImages
? [...buildPlatforms, ...testPlatforms]
.filter(({ os }) => os !== "darwin")
.filter(({ os, distro }) => !imageFilter || os === imageFilter || distro === imageFilter)
.map(platform => [getImageKey(platform), platform])
: [],
);
@@ -1262,14 +1126,6 @@ async function getPipeline(options = {}) {
steps.push(getBuildZigStep(target, options));
steps.push(getLinkBunStep(target, options));
if (needsBaselineVerification(target)) {
steps.push(getVerifyBaselineStep(target, options));
// Run JIT stress tests under QEMU when WebKit is updated
if (hasWebKitChanges(options)) {
steps.push(getJitStressTestStep(target, options));
}
}
return getStepWithDependsOn(
{
key: getTargetKey(target),
@@ -1367,7 +1223,6 @@ async function main() {
console.log(`- PR is only docs, skipping tests!`);
return;
}
options.changedFiles = allFiles;
}
startGroup("Generating pipeline...");

View File

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

View File

@@ -33,8 +33,8 @@ The workflow runs all three formatters simultaneously:
#### 3. Tool Installation
##### Clang-format-21
- Installs ONLY `clang-format-21` package (not the entire LLVM toolchain)
##### 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`

View File

@@ -1,30 +0,0 @@
name: Close stale robobun PRs
on:
schedule:
- cron: "30 0 * * *"
workflow_dispatch:
jobs:
close-stale-robobun-prs:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
pull-requests: write
steps:
- name: Close stale robobun PRs
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
run: |
ninety_days_ago=$(date -u -d '90 days ago' +%Y-%m-%dT%H:%M:%SZ)
gh pr list \
--author robobun \
--state open \
--json number,updatedAt \
--limit 1000 \
--jq ".[] | select(.updatedAt < \"$ninety_days_ago\") | .number" |
while read -r pr_number; do
echo "Closing PR #$pr_number (last updated before $ninety_days_ago)"
gh pr close "$pr_number" --comment "Closing this PR because it has been inactive for more than 90 days."
done

View File

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

View File

@@ -161,31 +161,6 @@ test("(multi-file test) my feature", async () => {
- `src/sql/` - SQL database integrations
- `src/bake/` - Server-side rendering framework
#### Vendored Dependencies (`vendor/`)
Third-party C/C++ libraries are vendored locally and can be read from disk (these are not git submodules):
- `vendor/boringssl/` - BoringSSL (TLS/crypto)
- `vendor/brotli/` - Brotli compression
- `vendor/cares/` - c-ares (async DNS)
- `vendor/hdrhistogram/` - HdrHistogram (latency tracking)
- `vendor/highway/` - Google Highway (SIMD)
- `vendor/libarchive/` - libarchive (tar/zip)
- `vendor/libdeflate/` - libdeflate (fast deflate)
- `vendor/libuv/` - libuv (Windows event loop)
- `vendor/lolhtml/` - lol-html (HTML rewriter)
- `vendor/lshpack/` - ls-hpack (HTTP/2 HPACK)
- `vendor/mimalloc/` - mimalloc (memory allocator)
- `vendor/nodejs/` - Node.js headers (compatibility)
- `vendor/picohttpparser/` - PicoHTTPParser (HTTP parsing)
- `vendor/tinycc/` - TinyCC (FFI JIT compiler, fork: oven-sh/tinycc)
- `vendor/WebKit/` - WebKit/JavaScriptCore (JS engine)
- `vendor/zig/` - Zig compiler/stdlib
- `vendor/zlib/` - zlib (compression, cloudflare fork)
- `vendor/zstd/` - Zstandard (compression)
Build configuration for these is in `cmake/targets/Build*.cmake`.
### JavaScript Class Implementation (C++)
When implementing JavaScript classes in C++:

View File

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

2
LATEST
View File

@@ -1 +1 @@
1.3.9
1.3.7

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -434,7 +434,7 @@ function(register_command)
endif()
# SKIP_CODEGEN: Skip commands that use BUN_EXECUTABLE if all outputs exist
# Useful for bootstrapping new platforms where bun may not be available
# This is used for Windows ARM64 builds where x64 bun crashes under emulation
if(SKIP_CODEGEN AND CMD_EXECUTABLE STREQUAL "${BUN_EXECUTABLE}")
set(ALL_OUTPUTS_EXIST TRUE)
foreach(output ${CMD_OUTPUTS})
@@ -456,7 +456,7 @@ function(register_command)
endif()
return()
else()
message(FATAL_ERROR "SKIP_CODEGEN: Cannot skip ${CMD_TARGET} - missing outputs.")
message(FATAL_ERROR "SKIP_CODEGEN: Cannot skip ${CMD_TARGET} - missing outputs. Run codegen on x64 first.")
endif()
endif()
@@ -831,6 +831,13 @@ function(register_cmake_command)
list(APPEND MAKE_EFFECTIVE_ARGS "-DCMAKE_${flag}=${MAKE_${flag}}")
endforeach()
# Workaround for CMake 4.1.0 bug: Force correct machine type for Windows ARM64
# Use toolchain file and set CMP0197 policy to prevent duplicate /machine: flags
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64|AARCH64")
list(APPEND MAKE_EFFECTIVE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CWD}/cmake/toolchains/windows-aarch64.cmake")
list(APPEND MAKE_EFFECTIVE_ARGS "-DCMAKE_POLICY_DEFAULT_CMP0197=NEW")
list(APPEND MAKE_EFFECTIVE_ARGS "-DCMAKE_PROJECT_INCLUDE=${CWD}/cmake/arm64-static-lib-fix.cmake")
endif()
if(DEFINED FRESH)
list(APPEND MAKE_EFFECTIVE_ARGS --fresh)

View File

@@ -4,7 +4,7 @@ endif()
optionx(BUN_LINK_ONLY BOOL "If only the linking step should be built" DEFAULT OFF)
optionx(BUN_CPP_ONLY BOOL "If only the C++ part of Bun should be built" DEFAULT OFF)
optionx(SKIP_CODEGEN BOOL "Skip JavaScript codegen (useful for bootstrapping new platforms)" DEFAULT OFF)
optionx(SKIP_CODEGEN BOOL "Skip JavaScript codegen (for Windows ARM64 debug)" DEFAULT OFF)
optionx(BUILDKITE BOOL "If Buildkite is enabled" DEFAULT OFF)
optionx(GITHUB_ACTIONS BOOL "If GitHub Actions is enabled" DEFAULT OFF)
@@ -58,6 +58,18 @@ else()
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}")
endif()
# CMake 4.0+ policy CMP0197 controls how MSVC machine type flags are handled
# Setting to NEW prevents duplicate /machine: flags being added to linker commands
if(WIN32 AND ARCH STREQUAL "aarch64")
set(CMAKE_POLICY_DEFAULT_CMP0197 NEW)
set(CMAKE_MSVC_CMP0197 NEW)
# Set linker flags for exe/shared linking
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /machine:ARM64")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /machine:ARM64")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /machine:ARM64")
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /machine:ARM64")
endif()
# Windows Code Signing Option
if(WIN32)
optionx(ENABLE_WINDOWS_CODESIGNING BOOL "Enable Windows code signing with DigiCert KeyLocker" DEFAULT OFF)

View File

@@ -0,0 +1,8 @@
# This file is included after project() via CMAKE_PROJECT_INCLUDE
# It fixes the static library creation command to use ARM64 machine type
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL \"aarch64\")
# Override the static library creation commands to avoid spurious /machine:x64 flags
set(CMAKE_C_CREATE_STATIC_LIBRARY \"<CMAKE_AR> /nologo /machine:ARM64 /out:<TARGET> <OBJECTS>\" CACHE STRING \"\" FORCE)
set(CMAKE_CXX_CREATE_STATIC_LIBRARY \"<CMAKE_AR> /nologo /machine:ARM64 /out:<TARGET> <OBJECTS>\" CACHE STRING \"\" FORCE)
endif()

View File

@@ -21,7 +21,12 @@ if(NOT DEFINED CMAKE_HOST_SYSTEM_PROCESSOR)
endif()
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm64|ARM64|aarch64|AARCH64")
set(ZIG_ARCH "aarch64")
# Windows ARM64 can run x86_64 via emulation, and no native ARM64 Zig build exists yet
if(CMAKE_HOST_WIN32)
set(ZIG_ARCH "x86_64")
else()
set(ZIG_ARCH "aarch64")
endif()
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|AMD64|x86_64|X86_64|x64|X64")
set(ZIG_ARCH "x86_64")
else()

View File

@@ -0,0 +1,34 @@
@echo off
setlocal enabledelayedexpansion
REM Wrapper for llvm-lib that strips conflicting /machine:x64 flag for ARM64 builds
REM This is a workaround for CMake 4.1.0 bug
REM Find llvm-lib.exe - check LLVM_LIB env var, then PATH, then known locations
if defined LLVM_LIB (
set "LLVM_LIB_EXE=!LLVM_LIB!"
) else (
where llvm-lib.exe >nul 2>&1
if !ERRORLEVEL! equ 0 (
for /f "delims=" %%i in ('where llvm-lib.exe') do set "LLVM_LIB_EXE=%%i"
) else if exist "C:\Program Files\LLVM\bin\llvm-lib.exe" (
set "LLVM_LIB_EXE=C:\Program Files\LLVM\bin\llvm-lib.exe"
) else (
echo Error: Cannot find llvm-lib.exe. Set LLVM_LIB environment variable or add LLVM to PATH.
exit /b 1
)
)
set "ARGS="
for %%a in (%*) do (
set "ARG=%%a"
if /i "!ARG!"=="/machine:x64" (
REM Skip this argument
) else (
set "ARGS=!ARGS! %%a"
)
)
"!LLVM_LIB_EXE!" %ARGS%
exit /b %ERRORLEVEL%

View File

@@ -0,0 +1,18 @@
# Wrapper for llvm-lib that strips conflicting /machine:x64 flag for ARM64 builds
# This is a workaround for CMake 4.1.0 bug where both /machine:ARM64 and /machine:x64 are added
# Find llvm-lib.exe - check LLVM_LIB env var, then PATH, then known locations
if ($env:LLVM_LIB) {
$llvmLib = $env:LLVM_LIB
} elseif (Get-Command llvm-lib.exe -ErrorAction SilentlyContinue) {
$llvmLib = (Get-Command llvm-lib.exe).Source
} elseif (Test-Path "C:\Program Files\LLVM\bin\llvm-lib.exe") {
$llvmLib = "C:\Program Files\LLVM\bin\llvm-lib.exe"
} else {
Write-Error "Cannot find llvm-lib.exe. Set LLVM_LIB environment variable or add LLVM to PATH."
exit 1
}
$filteredArgs = $args | Where-Object { $_ -ne "/machine:x64" }
& $llvmLib @filteredArgs
exit $LASTEXITCODE

View File

@@ -0,0 +1,34 @@
@echo off
setlocal enabledelayedexpansion
REM Wrapper for llvm-lib that strips conflicting /machine:x64 flag for ARM64 builds
REM This is a workaround for CMake 4.1.0 bug
REM Find llvm-lib.exe - check LLVM_LIB env var, then PATH, then known locations
if defined LLVM_LIB (
set "LLVM_LIB_EXE=!LLVM_LIB!"
) else (
where llvm-lib.exe >nul 2>&1
if !ERRORLEVEL! equ 0 (
for /f "delims=" %%i in ('where llvm-lib.exe') do set "LLVM_LIB_EXE=%%i"
) else if exist "C:\Program Files\LLVM\bin\llvm-lib.exe" (
set "LLVM_LIB_EXE=C:\Program Files\LLVM\bin\llvm-lib.exe"
) else (
echo Error: Cannot find llvm-lib.exe. Set LLVM_LIB environment variable or add LLVM to PATH.
exit /b 1
)
)
set NEWARGS=
for %%a in (%*) do (
set "ARG=%%a"
if /i "!ARG!"=="/machine:x64" (
REM Skip /machine:x64 argument
) else (
set "NEWARGS=!NEWARGS! %%a"
)
)
"!LLVM_LIB_EXE!" %NEWARGS%
exit /b %ERRORLEVEL%

View File

@@ -341,7 +341,6 @@ register_command(
SOURCES
${BUN_JAVASCRIPT_CODEGEN_SOURCES}
${BUN_CXX_SOURCES}
${ESBUILD_EXECUTABLE}
OUTPUTS
${BUN_CPP_OUTPUTS}
)
@@ -363,7 +362,7 @@ register_command(
)
if(SKIP_CODEGEN)
# Skip JavaScript codegen - useful for bootstrapping new platforms
# Skip JavaScript codegen - useful for Windows ARM64 debug builds where bun crashes
message(STATUS "SKIP_CODEGEN is ON - skipping bun-js-modules codegen")
foreach(output ${BUN_JAVASCRIPT_OUTPUTS})
if(NOT EXISTS ${output})
@@ -681,7 +680,8 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|ARM|arm64|ARM64|aarch64|AARCH64")
if(APPLE)
set(ZIG_CPU "apple_m1")
elseif(WIN32)
# Windows ARM64: use a specific CPU target for consistent builds
# Windows ARM64: use a specific CPU with NEON support
# Zig running under x64 emulation would detect wrong CPU with "native"
set(ZIG_CPU "cortex_a76")
else()
set(ZIG_CPU "native")
@@ -1016,7 +1016,6 @@ if(NOT WIN32)
-Wno-unused-function
-Wno-c++23-lambda-attributes
-Wno-nullability-completeness
-Wno-character-conversion
-Werror
)
else()
@@ -1034,7 +1033,6 @@ if(NOT WIN32)
-Werror=sometimes-uninitialized
-Wno-c++23-lambda-attributes
-Wno-nullability-completeness
-Wno-character-conversion
-Werror
)
@@ -1063,7 +1061,6 @@ else()
-Wno-inconsistent-dllimport
-Wno-incompatible-pointer-types
-Wno-deprecated-declarations
-Wno-character-conversion
)
endif()
@@ -1139,15 +1136,6 @@ if(LINUX)
-Wl,--wrap=pow
-Wl,--wrap=powf
)
# Disable LTO for workaround-missing-symbols.cpp to prevent LLD 21 from emitting
# glibc versioned symbol names (e.g. exp@GLIBC_2.17) from .symver directives into
# the .lto_discard assembler directive, which fails to parse the '@' character.
if(ENABLE_LTO)
set_source_files_properties(${CWD}/src/bun.js/bindings/workaround-missing-symbols.cpp
PROPERTIES COMPILE_OPTIONS "-fno-lto"
)
endif()
endif()
if(NOT ABI STREQUAL "musl")
@@ -1285,18 +1273,13 @@ else()
${WEBKIT_LIB_PATH}/libWTF.a
${WEBKIT_LIB_PATH}/libJavaScriptCore.a
)
if(WEBKIT_LOCAL OR NOT APPLE OR EXISTS ${WEBKIT_LIB_PATH}/libbmalloc.a)
if(NOT APPLE OR EXISTS ${WEBKIT_LIB_PATH}/libbmalloc.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libbmalloc.a)
endif()
endif()
include_directories(${WEBKIT_INCLUDE_PATH})
# When building with a local WebKit, ensure JSC is built before compiling Bun's C++ sources.
if(WEBKIT_LOCAL AND TARGET jsc)
add_dependencies(${bun} jsc)
endif()
# Include the generated dependency versions header
include_directories(${CMAKE_BINARY_DIR})
@@ -1341,14 +1324,9 @@ if(LINUX)
target_link_libraries(${bun} PUBLIC libatomic.so)
endif()
if(WEBKIT_LOCAL)
find_package(ICU REQUIRED COMPONENTS data i18n uc)
target_link_libraries(${bun} PRIVATE ICU::data ICU::i18n ICU::uc)
else()
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicudata.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicui18n.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicuuc.a)
endif()
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicudata.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicui18n.a)
target_link_libraries(${bun} PRIVATE ${WEBKIT_LIB_PATH}/libicuuc.a)
endif()
if(WIN32)

View File

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

View File

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

View File

@@ -7,32 +7,6 @@ register_repository(
886098f3f339617b4243b286f5ed364b9989e245
)
# cloudflare/zlib hardcodes STATIC_LIBRARY_FLAGS "/machine:x64" for 64-bit MSVC,
# which conflicts with ARM64 object files. Patch it after clone to use the correct
# machine type based on CMAKE_SYSTEM_PROCESSOR.
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64|AARCH64")
set(ZLIB_PATCH_SCRIPT "${BUILD_PATH}/zlib-arm64-patch.cmake")
file(WRITE ${ZLIB_PATCH_SCRIPT} "
file(READ \"\${ZLIB_CMAKELISTS}\" content)
string(REPLACE \"/machine:x64\" \"/machine:ARM64\" content \"\${content}\")
file(WRITE \"\${ZLIB_CMAKELISTS}\" \"\${content}\")
file(TOUCH \"\${ZLIB_PATCH_MARKER}\")
")
register_command(
COMMENT "Patching zlib for ARM64"
TARGET patch-zlib
COMMAND ${CMAKE_COMMAND}
-DZLIB_CMAKELISTS=${VENDOR_PATH}/zlib/CMakeLists.txt
-DZLIB_PATCH_MARKER=${VENDOR_PATH}/zlib/.arm64-patched
-P ${ZLIB_PATCH_SCRIPT}
SOURCES ${VENDOR_PATH}/zlib/.ref
OUTPUTS ${VENDOR_PATH}/zlib/.arm64-patched
)
if(TARGET clone-zlib)
add_dependencies(patch-zlib clone-zlib)
endif()
endif()
# https://gitlab.kitware.com/cmake/cmake/-/issues/25755
if(APPLE)
set(ZLIB_CMAKE_C_FLAGS "-fno-define-target-os-macros")
@@ -64,8 +38,3 @@ register_cmake_command(
INCLUDES
.
)
# Ensure zlib is patched before configure
if(TARGET patch-zlib)
add_dependencies(configure-zlib patch-zlib)
endif()

View File

@@ -3,4 +3,18 @@ set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER_WORKS ON)
set(CMAKE_CXX_COMPILER_WORKS ON)
set(CMAKE_CROSSCOMPILING ON)
# Force ARM64 architecture ID - this is what CMake uses to determine /machine: flag
set(MSVC_C_ARCHITECTURE_ID ARM64 CACHE INTERNAL "")
set(MSVC_CXX_ARCHITECTURE_ID ARM64 CACHE INTERNAL "")
# CMake 4.0+ policy CMP0197 controls how MSVC machine type flags are handled
set(CMAKE_POLICY_DEFAULT_CMP0197 NEW CACHE INTERNAL "")
# Clear any inherited static linker flags that might have wrong machine types
set(CMAKE_STATIC_LINKER_FLAGS "" CACHE STRING "" FORCE)
# Use wrapper script for llvm-lib that strips /machine:x64 flags
# This works around CMake 4.1.0 bug where both ARM64 and x64 machine flags are added
get_filename_component(_TOOLCHAIN_DIR "${CMAKE_CURRENT_LIST_DIR}" DIRECTORY)
set(CMAKE_AR "${_TOOLCHAIN_DIR}/scripts/llvm-lib-wrapper.bat" CACHE FILEPATH "" FORCE)

View File

@@ -17,7 +17,13 @@ if (NOT CI)
set(BUN_EXECUTABLE ${BUN_EXECUTABLE} CACHE FILEPATH "Bun executable" FORCE)
endif()
set(BUN_FLAGS "" CACHE STRING "Extra flags for bun executable")
# On Windows ARM64, we need to add --smol flag to avoid crashes when running
# x64 bun under WoW64 emulation
if(WIN32 AND ARCH STREQUAL "aarch64")
set(BUN_FLAGS "--smol" CACHE STRING "Extra flags for bun executable")
else()
set(BUN_FLAGS "" CACHE STRING "Extra flags for bun executable")
endif()
# If this is not set, some advanced features are not checked.
# https://github.com/oven-sh/bun/blob/cd7f6a1589db7f1e39dc4e3f4a17234afbe7826c/src/bun.js/javascript.zig#L1069-L1072

View File

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

View File

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

View File

@@ -20,7 +20,7 @@ else()
unsupported(CMAKE_SYSTEM_NAME)
endif()
set(ZIG_COMMIT "c031cbebf5b063210473ff5204a24ebfb2492c72")
set(ZIG_COMMIT "c1423ff3fc7064635773a4a4616c5bf986eb00fe")
optionx(ZIG_TARGET STRING "The zig target to use" DEFAULT ${DEFAULT_ZIG_TARGET})
if(CMAKE_BUILD_TYPE STREQUAL "Release")
@@ -55,14 +55,7 @@ optionx(ZIG_OBJECT_FORMAT "obj|bc" "Output file format for Zig object files" DEF
optionx(ZIG_LOCAL_CACHE_DIR FILEPATH "The path to local the zig cache directory" DEFAULT ${CACHE_PATH}/zig/local)
optionx(ZIG_GLOBAL_CACHE_DIR FILEPATH "The path to the global zig cache directory" DEFAULT ${CACHE_PATH}/zig/global)
# The ReleaseSafe Zig compiler for Windows ARM64 has an LLVM SEH epilogue bug
# (incorrect size for compiler_rt.rem_pio2_large epilogue). Use the default build instead.
if(CI AND WIN32 AND DEFAULT_ZIG_ARCH STREQUAL "aarch64")
set(DEFAULT_ZIG_COMPILER_SAFE OFF)
else()
set(DEFAULT_ZIG_COMPILER_SAFE ${CI})
endif()
optionx(ZIG_COMPILER_SAFE BOOL "Download a ReleaseSafe build of the Zig compiler." DEFAULT ${DEFAULT_ZIG_COMPILER_SAFE})
optionx(ZIG_COMPILER_SAFE BOOL "Download a ReleaseSafe build of the Zig compiler." DEFAULT ${CI})
setenv(ZIG_LOCAL_CACHE_DIR ${ZIG_LOCAL_CACHE_DIR})
setenv(ZIG_GLOBAL_CACHE_DIR ${ZIG_GLOBAL_CACHE_DIR})

View File

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

View File

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

View File

@@ -7,9 +7,9 @@ Bytecode caching is a build-time optimization that dramatically improves applica
## Usage
### Basic usage (CommonJS)
### Basic usage
Enable bytecode caching with the `--bytecode` flag. Without `--format`, this defaults to CommonJS:
Enable bytecode caching with the `--bytecode` flag:
```bash terminal icon="terminal"
bun build ./index.ts --target=bun --bytecode --outdir=./dist
@@ -17,7 +17,7 @@ bun build ./index.ts --target=bun --bytecode --outdir=./dist
This generates two files:
- `dist/index.js` - Your bundled JavaScript (CommonJS)
- `dist/index.js` - Your bundled JavaScript
- `dist/index.jsc` - The bytecode cache file
At runtime, Bun automatically detects and uses the `.jsc` file:
@@ -28,24 +28,14 @@ bun ./dist/index.js # Automatically uses index.jsc
### With standalone executables
When creating executables with `--compile`, bytecode is embedded into the binary. Both ESM and CommonJS formats are supported:
When creating executables with `--compile`, bytecode is embedded into the binary:
```bash terminal icon="terminal"
# ESM (requires --compile)
bun build ./cli.ts --compile --bytecode --format=esm --outfile=mycli
# CommonJS (works with or without --compile)
bun build ./cli.ts --compile --bytecode --outfile=mycli
```
The resulting executable contains both the code and bytecode, giving you maximum performance in a single file.
### ESM bytecode
ESM bytecode requires `--compile` because Bun embeds module metadata (import/export information) in the compiled binary. This metadata allows the JavaScript engine to skip parsing entirely at runtime.
Without `--compile`, ESM bytecode would still require parsing the source to analyze module dependencies—defeating the purpose of bytecode caching.
### Combining with other optimizations
Bytecode works great with minification and source maps:
@@ -100,9 +90,35 @@ Larger applications benefit more because they have more code to parse.
- ❌ **Code that runs once**
- ❌ **Development builds**
- ❌ **Size-constrained environments**
- ❌ **Code with top-level await** (not supported)
## Limitations
### CommonJS only
Bytecode caching currently works with CommonJS output format. Bun's bundler automatically converts most ESM code to CommonJS, but **top-level await** is the exception:
```js
// This prevents bytecode caching
const data = await fetch("https://api.example.com");
export default data;
```
**Why**: Top-level await requires async module evaluation, which can't be represented in CommonJS. The module graph becomes asynchronous, and the CommonJS wrapper function model breaks down.
**Workaround**: Move async initialization into a function:
```js
async function init() {
const data = await fetch("https://api.example.com");
return data;
}
export default init;
```
Now the module exports a function that the consumer can await when needed.
### Version compatibility
Bytecode is **not portable across Bun versions**. The bytecode format is tied to JavaScriptCore's internal representation, which changes between versions.
@@ -220,6 +236,8 @@ It's normal for it it to log a cache miss multiple times since Bun doesn't curre
- Compressing `.jsc` files for network transfer (gzip/brotli)
- Evaluating if the startup performance gain is worth the size increase
**Top-level await**: Not supported. Refactor to use async initialization functions.
## What is bytecode?
When you run JavaScript, the JavaScript engine doesn't execute your source code directly. Instead, it goes through several steps:

View File

@@ -198,16 +198,13 @@ const myPlugin: BunPlugin = {
};
```
The builder object provides some methods for hooking into parts of the bundling process. Bun implements `onStart`, `onEnd`, `onResolve`, and `onLoad`. It does not yet implement the esbuild hooks `onDispose` and `resolve`. `initialOptions` is partially implemented, being read-only and only having a subset of esbuild's options; use `config` (same thing but with Bun's `BuildConfig` format) instead.
The builder object provides some methods for hooking into parts of the bundling process. Bun implements `onResolve` and `onLoad`; it does not yet implement the esbuild hooks `onStart`, `onEnd`, and `onDispose`, and `resolve` utilities. `initialOptions` is partially implemented, being read-only and only having a subset of esbuild's options; use `config` (same thing but with Bun's `BuildConfig` format) instead.
```ts title="myPlugin.ts" icon="/icons/typescript.svg"
import type { BunPlugin } from "bun";
const myPlugin: BunPlugin = {
name: "my-plugin",
setup(builder) {
builder.onStart(() => {
/* called when the bundle starts */
});
builder.onResolve(
{
/* onResolve.options */
@@ -228,9 +225,6 @@ const myPlugin: BunPlugin = {
};
},
);
builder.onEnd(result => {
/* called when the bundle is complete */
});
},
};
```

View File

@@ -322,7 +322,10 @@ Using bytecode compilation, `tsc` starts 2x faster:
Bytecode compilation moves parsing overhead for large input files from runtime to bundle time. Your app starts faster, in exchange for making the `bun build` command a little slower. It doesn't obscure source code.
<Note>Bytecode compilation supports both `cjs` and `esm` formats when used with `--compile`.</Note>
<Warning>
**Experimental:** Bytecode compilation is an experimental feature. Only `cjs` format is supported (which means no
top-level-await). Let us know if you run into any issues!
</Warning>
### What do these flags do?
@@ -1184,8 +1187,7 @@ Currently, the `--compile` flag can only accept a single entrypoint at a time an
- `--outdir` — use `outfile` instead (except when using with `--splitting`).
- `--public-path`
- `--target=node`
- `--target=browser` (without HTML entrypoints — see [Standalone HTML](/bundler/standalone-html) for `--compile --target=browser` with `.html` files)
- `--target=node` or `--target=browser`
- `--no-bundle` - we always bundle everything into the executable.
---

View File

@@ -481,16 +481,6 @@ All paths are resolved relative to your HTML file, making it easy to organize yo
This is a small wrapper around Bun's support for HTML imports in JavaScript.
## Standalone HTML
You can bundle your entire frontend into a **single self-contained `.html` file** with no external dependencies using `--compile --target=browser`. All JavaScript, CSS, and images are inlined directly into the HTML.
```bash terminal icon="terminal"
bun build --compile --target=browser ./index.html --outdir=dist
```
Learn more in the [Standalone HTML docs](/bundler/standalone-html).
## Adding a backend to your frontend
To add a backend to your frontend, you can use the "routes" option in `Bun.serve`.

View File

@@ -1508,43 +1508,22 @@ BuildArtifact (entry-point) {
## Bytecode
The `bytecode: boolean` option can be used to generate bytecode for any JavaScript/TypeScript entrypoints. This can greatly improve startup times for large applications. Requires `"target": "bun"` and is dependent on a matching version of Bun.
- **CommonJS**: Works with or without `compile: true`. Generates a `.jsc` file alongside each entrypoint.
- **ESM**: Requires `compile: true`. Bytecode and module metadata are embedded in the standalone executable.
Without an explicit `format`, bytecode defaults to CommonJS.
The `bytecode: boolean` option can be used to generate bytecode for any JavaScript/TypeScript entrypoints. This can greatly improve startup times for large applications. Only supported for `"cjs"` format, only supports `"target": "bun"` and dependent on a matching version of Bun. This adds a corresponding `.jsc` file for each entrypoint.
<Tabs>
<Tab title="JavaScript">
```ts title="build.ts" icon="/icons/typescript.svg"
// CommonJS bytecode (generates .jsc files)
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./out",
bytecode: true,
})
// ESM bytecode (requires compile)
await Bun.build({
entrypoints: ["./index.tsx"],
outfile: "./mycli",
bytecode: true,
format: "esm",
compile: true,
})
```
</Tab>
<Tab title="CLI">
```bash terminal icon="terminal"
# CommonJS bytecode
bun build ./index.tsx --outdir ./out --bytecode
# ESM bytecode (requires --compile)
bun build ./index.tsx --outfile ./mycli --bytecode --format=esm --compile
```
</Tab>
</Tabs>
@@ -1711,10 +1690,7 @@ interface BuildConfig {
* start times, but will make the final output larger and slightly increase
* memory usage.
*
* - CommonJS: works with or without `compile: true`
* - ESM: requires `compile: true`
*
* Without an explicit `format`, defaults to CommonJS.
* Bytecode is currently only supported for CommonJS (`format: "cjs"`).
*
* Must be `target: "bun"`
* @default false

View File

@@ -15,7 +15,6 @@ Plugins can register callbacks to be run at various points in the lifecycle of a
- `onResolve()`: Run before a module is resolved
- `onLoad()`: Run before a module is loaded
- `onBeforeParse()`: Run zero-copy native addons in the parser thread before a file is parsed
- `onEnd()`: Run after the bundle is complete
## Reference
@@ -40,7 +39,6 @@ type PluginBuilder = {
exports?: Record<string, any>;
},
) => void;
onEnd(callback: (result: BuildOutput) => void | Promise<void>): void;
config: BuildConfig;
};
@@ -425,53 +423,3 @@ This lifecycle callback is run immediately before a file is parsed by Bun's bund
As input, it receives the file's contents and can optionally return new source code.
<Info>This callback can be called from any thread and so the napi module implementation must be thread-safe.</Info>
### onEnd
```ts
onEnd(callback: (result: BuildOutput) => void | Promise<void>): void;
```
Registers a callback to be run after the bundle is complete. The callback receives the [`BuildOutput`](/docs/bundler#outputs) object containing the build results, including output files and any build messages.
```ts title="index.ts" icon="/icons/typescript.svg"
const result = await Bun.build({
entrypoints: ["./app.ts"],
outdir: "./dist",
plugins: [
{
name: "onEnd example",
setup(build) {
build.onEnd(result => {
console.log(`Build completed with ${result.outputs.length} files`);
for (const log of result.logs) {
console.log(log);
}
});
},
},
],
});
```
The callback can return a `Promise`. The build output promise from `Bun.build()` will not resolve until all `onEnd()` callbacks have completed.
```ts title="index.ts" icon="/icons/typescript.svg"
const result = await Bun.build({
entrypoints: ["./app.ts"],
outdir: "./dist",
plugins: [
{
name: "Upload to S3",
setup(build) {
build.onEnd(async result => {
if (!result.success) return;
for (const output of result.outputs) {
await uploadToS3(output);
}
});
},
},
],
});
```

View File

@@ -1,314 +0,0 @@
---
title: Standalone HTML
description: Bundle a single-page app into a single self-contained .html file with no external dependencies
---
Bun can bundle your entire frontend into a **single `.html` file** with zero external dependencies. JavaScript, TypeScript, JSX, CSS, images, fonts, videos, WASM — everything gets inlined into one file.
```bash terminal icon="terminal"
bun build --compile --target=browser ./index.html --outdir=dist
```
The output is a completely self-contained HTML document. No relative paths. No external files. No server required. Just one `.html` file that works anywhere a browser can open it.
## One file. Upload anywhere. It just works.
The output is a single `.html` file you can put anywhere:
- **Upload it to S3** or any static file host — no directory structure to maintain, just one file
- **Double-click it from your desktop** — it opens in the browser and works offline, no localhost server needed
- **Embed it in your webview** — No need to deal with relative files
- **Insert it in an `<iframe>`** — embed interactive content in another page with a single file URL
- **Serve it from anywhere** — any HTTP server, CDN, or file share. One file, zero configuration.
There's nothing to install, no `node_modules` to deploy, no build artifacts to coordinate, no relative paths to think about. The entire app — framework code, stylesheets, images, everything — lives in that one file.
## Truly one file
Normally, distributing a web page means managing a folder of assets — the HTML, the JavaScript bundles, the CSS files, the images. Move the HTML without the rest and everything breaks. Browsers have tried to solve this before: Safari's `.webarchive` and `.mhtml` are supposed to save a page as a single file, but in practice they unpack into a folder of loose files on your computer — defeating the purpose.
Standalone HTML is different. The output is a plain `.html` file. Not an archive. Not a folder. One file, with everything inside it. Every image, every font, every line of CSS and JavaScript is embedded directly in the HTML using standard `<style>` tags, `<script>` tags, and `data:` URIs. Any browser can open it. Any server can host it. Any file host can store it.
This makes it practical to distribute web pages the same way you'd distribute a PDF — as a single file you can move, copy, upload, or share without worrying about broken paths or missing assets.
## Quick start
<CodeGroup>
```html index.html icon="file-code"
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<div id="root"></div>
<script src="./app.tsx"></script>
</body>
</html>
```
```tsx app.tsx icon="/icons/typescript.svg"
import React from "react";
import { createRoot } from "react-dom/client";
function App() {
return <h1>Hello from a single HTML file!</h1>;
}
createRoot(document.getElementById("root")!).render(<App />);
```
```css styles.css icon="file-code"
body {
margin: 0;
font-family: system-ui, sans-serif;
background: #f5f5f5;
}
```
</CodeGroup>
```bash terminal icon="terminal"
bun build --compile --target=browser ./index.html --outdir=dist
```
Open `dist/index.html` — the React app works with no server.
## Everything gets inlined
Bun inlines every local asset it finds in your HTML. If it has a relative path, it gets embedded into the output file. This isn't limited to images and stylesheets — it works with any file type.
### What gets inlined
| In your source | In the output |
| ------------------------------------------------ | ------------------------------------------------------------------------ |
| `<script src="./app.tsx">` | `<script type="module">...bundled code...</script>` |
| `<link rel="stylesheet" href="./styles.css">` | `<style>...bundled CSS...</style>` |
| `<img src="./logo.png">` | `<img src="data:image/png;base64,...">` |
| `<img src="./icon.svg">` | `<img src="data:image/svg+xml;base64,...">` |
| `<video src="./demo.mp4">` | `<video src="data:video/mp4;base64,...">` |
| `<audio src="./click.wav">` | `<audio src="data:audio/wav;base64,...">` |
| `<source src="./clip.webm">` | `<source src="data:video/webm;base64,...">` |
| `<video poster="./thumb.jpg">` | `<video poster="data:image/jpeg;base64,...">` |
| `<link rel="icon" href="./favicon.ico">` | `<link rel="icon" href="data:image/x-icon;base64,...">` |
| `<link rel="manifest" href="./app.webmanifest">` | `<link rel="manifest" href="data:application/manifest+json;base64,...">` |
| CSS `url("./bg.png")` | CSS `url(data:image/png;base64,...)` |
| CSS `@import "./reset.css"` | Flattened into the `<style>` tag |
| CSS `url("./font.woff2")` | CSS `url(data:font/woff2;base64,...)` |
| JS `import "./styles.css"` | Merged into the `<style>` tag |
Images, fonts, WASM binaries, videos, audio files, SVGs — any file referenced by a relative path gets base64-encoded into a `data:` URI and embedded directly in the HTML. The MIME type is automatically detected from the file extension.
External URLs (like CDN links or absolute URLs) are left untouched.
## Using with React
React apps work out of the box. Bun handles JSX transpilation and npm package resolution automatically.
```bash terminal icon="terminal"
bun install react react-dom
```
<CodeGroup>
```html index.html icon="file-code"
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>My App</title>
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<div id="root"></div>
<script src="./app.tsx"></script>
</body>
</html>
```
```tsx app.tsx icon="/icons/typescript.svg"
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import { Counter } from "./components/Counter.tsx";
function App() {
return (
<main>
<h1>Single-file React App</h1>
<Counter />
</main>
);
}
createRoot(document.getElementById("root")!).render(<App />);
```
```tsx components/Counter.tsx icon="/icons/typescript.svg"
import React, { useState } from "react";
export function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}
```
</CodeGroup>
```bash terminal icon="terminal"
bun build --compile --target=browser ./index.html --outdir=dist
```
All of React, your components, and your CSS are bundled into `dist/index.html`. Upload that one file anywhere and it works.
## Using with Tailwind CSS
Install the plugin and reference Tailwind in your HTML or CSS:
```bash terminal icon="terminal"
bun install --dev bun-plugin-tailwind
```
<CodeGroup>
```html index.html icon="file-code"
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="tailwindcss" />
</head>
<body class="bg-gray-100 flex items-center justify-center min-h-screen">
<div id="root"></div>
<script src="./app.tsx"></script>
</body>
</html>
```
```tsx app.tsx icon="/icons/typescript.svg"
import React from "react";
import { createRoot } from "react-dom/client";
function App() {
return (
<div className="bg-white rounded-lg shadow-lg p-8 max-w-md">
<h1 className="text-2xl font-bold text-gray-800">Hello Tailwind</h1>
<p className="text-gray-600 mt-2">This is a single HTML file.</p>
</div>
);
}
createRoot(document.getElementById("root")!).render(<App />);
```
</CodeGroup>
Build with the plugin using the JavaScript API:
```ts build.ts icon="/icons/typescript.svg"
await Bun.build({
entrypoints: ["./index.html"],
compile: true,
target: "browser",
outdir: "./dist",
plugins: [require("bun-plugin-tailwind")],
});
```
```bash terminal icon="terminal"
bun run build.ts
```
The generated Tailwind CSS is inlined directly into the HTML file as a `<style>` tag.
## How it works
When you pass `--compile --target=browser` with an HTML entrypoint, Bun:
1. Parses the HTML and discovers all `<script>`, `<link>`, `<img>`, `<video>`, `<audio>`, `<source>`, and other asset references
2. Bundles all JavaScript/TypeScript/JSX into a single module
3. Bundles all CSS (including `@import` chains and CSS imported from JS) into a single stylesheet
4. Converts every relative asset reference into a base64 `data:` URI
5. Inlines the bundled JS as `<script type="module">` before `</body>`
6. Inlines the bundled CSS as `<style>` in `<head>`
7. Outputs a single `.html` file with no external dependencies
## Minification
Add `--minify` to minify the JavaScript and CSS:
```bash terminal icon="terminal"
bun build --compile --target=browser --minify ./index.html --outdir=dist
```
Or via the API:
```ts build.ts icon="/icons/typescript.svg"
await Bun.build({
entrypoints: ["./index.html"],
compile: true,
target: "browser",
outdir: "./dist",
minify: true,
});
```
## JavaScript API
You can use `Bun.build()` to produce standalone HTML programmatically:
```ts build.ts icon="/icons/typescript.svg"
const result = await Bun.build({
entrypoints: ["./index.html"],
compile: true,
target: "browser",
outdir: "./dist", // optional — omit to get output as BuildArtifact
minify: true,
});
if (!result.success) {
console.error("Build failed:");
for (const log of result.logs) {
console.error(log);
}
} else {
console.log("Built:", result.outputs[0].path);
}
```
When `outdir` is omitted, the output is available as a `BuildArtifact` in `result.outputs`:
```ts icon="/icons/typescript.svg"
const result = await Bun.build({
entrypoints: ["./index.html"],
compile: true,
target: "browser",
});
const html = await result.outputs[0].text();
await Bun.write("output.html", html);
```
## Multiple HTML files
You can pass multiple HTML files as entrypoints. Each produces its own standalone HTML file:
```bash terminal icon="terminal"
bun build --compile --target=browser ./index.html ./about.html --outdir=dist
```
## Environment variables
Use `--env` to inline environment variables into the bundled JavaScript:
```bash terminal icon="terminal"
API_URL=https://api.example.com bun build --compile --target=browser --env=inline ./index.html --outdir=dist
```
References to `process.env.API_URL` in your JavaScript are replaced with the literal value at build time.
## Limitations
- **Code splitting** is not supported — `--splitting` cannot be used with `--compile --target=browser`
- **Large assets** increase file size since they're base64-encoded (33% overhead vs the raw binary)
- **External URLs** (CDN links, absolute URLs) are left as-is — only relative paths are inlined

View File

@@ -234,7 +234,7 @@
{
"group": "Asset Processing",
"icon": "image",
"pages": ["/bundler/html-static", "/bundler/standalone-html", "/bundler/css", "/bundler/loaders"]
"pages": ["/bundler/html-static", "/bundler/css", "/bundler/loaders"]
},
{
"group": "Single File Executable",

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,9 +3,9 @@ title: Markdown
description: Parse and render Markdown with Bun's built-in Markdown API, supporting GFM extensions and custom rendering callbacks
---
<Callout type="note">
**Unstable API** — This API is under active development and may change in future versions of Bun.
</Callout>
{% callout type="note" %}
**Unstable API** — This API is under active development and may change in future versions of Bun.
{% /callout %}
Bun includes a fast, built-in Markdown parser written in Zig. It supports GitHub Flavored Markdown (GFM) extensions and provides three APIs:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,9 +22,8 @@ bun upgrade
- [Linux, arm64](https://www.npmjs.com/package/@oven/bun-linux-aarch64)
- [Linux, x64](https://www.npmjs.com/package/@oven/bun-linux-x64)
- [Linux, x64 (without AVX2 instructions)](https://www.npmjs.com/package/@oven/bun-linux-x64-baseline)
- [Windows, x64](https://www.npmjs.com/package/@oven/bun-windows-x64)
- [Windows, x64 (without AVX2 instructions)](https://www.npmjs.com/package/@oven/bun-windows-x64-baseline)
- [Windows ARM64](https://www.npmjs.com/package/@oven/bun-windows-aarch64)
- [Windows](https://www.npmjs.com/package/@oven/bun-windows-x64)
- [Windows (without AVX2 instructions)](https://www.npmjs.com/package/@oven/bun-windows-x64-baseline)
### Future Platforms

View File

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

View File

@@ -2154,7 +2154,7 @@ declare module "bun" {
interface Hash {
wyhash: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: bigint) => bigint;
adler32: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer) => number;
crc32: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number) => number;
crc32: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer) => number;
cityHash32: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer) => number;
cityHash64: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: bigint) => bigint;
xxHash32: (data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number) => number;
@@ -2428,29 +2428,23 @@ declare module "bun" {
}
namespace Build {
type Architecture = "x64" | "arm64" | "aarch64";
type Architecture = "x64" | "arm64";
type Libc = "glibc" | "musl";
type SIMD = "baseline" | "modern";
type CompileTarget =
| `bun-darwin-${Architecture}`
| `bun-darwin-${Architecture}-${SIMD}`
| `bun-darwin-x64-${SIMD}`
| `bun-linux-${Architecture}`
| `bun-linux-${Architecture}-${Libc}`
| `bun-linux-${Architecture}-${SIMD}`
| `bun-linux-${Architecture}-${SIMD}-${Libc}`
| `bun-windows-${Architecture}`
| `bun-windows-x64-${SIMD}`;
| "bun-windows-x64"
| `bun-windows-x64-${SIMD}`
| `bun-linux-x64-${SIMD}-${Libc}`;
}
/**
* @see [Bun.build API docs](https://bun.com/docs/bundler#api)
*/
interface BuildConfig {
/**
* Enable code splitting
*/
splitting?: boolean;
interface BuildConfigBase {
/**
* List of entrypoints, usually file paths
*/
@@ -2599,10 +2593,7 @@ declare module "bun" {
* start times, but will make the final output larger and slightly increase
* memory usage.
*
* - CommonJS: works with or without `compile: true`
* - ESM: requires `compile: true`
*
* Without an explicit `format`, defaults to CommonJS.
* Bytecode is currently only supported for CommonJS (`format: "cjs"`).
*
* Must be `target: "bun"`
* @default false
@@ -2779,46 +2770,6 @@ declare module "bun" {
metafile?: boolean;
outdir?: string;
/**
* Create a standalone executable or self-contained HTML.
*
* When `true`, creates an executable for the current platform.
* When a target string, creates an executable for that platform.
*
* When used with `target: "browser"`, produces self-contained HTML files
* with all scripts, styles, and assets inlined. All `<script>` tags become
* inline `<script>` with bundled code, all `<link rel="stylesheet">` tags
* become inline `<style>` tags, and all asset references become `data:` URIs.
* All entrypoints must be HTML files. Cannot be used with `splitting`.
*
* @example
* ```ts
* // Create executable for current platform
* await Bun.build({
* entrypoints: ['./app.js'],
* compile: {
* target: 'linux-x64',
* },
* outfile: './my-app'
* });
*
* // Cross-compile for Linux x64
* await Bun.build({
* entrypoints: ['./app.js'],
* compile: 'linux-x64',
* outfile: './my-app'
* });
*
* // Produce self-contained HTML
* await Bun.build({
* entrypoints: ['./index.html'],
* target: 'browser',
* compile: true,
* });
* ```
*/
compile?: boolean | Bun.Build.CompileTarget | CompileBuildOptions;
}
interface CompileBuildOptions {
@@ -2877,6 +2828,57 @@ declare module "bun" {
};
}
// Compile build config - uses outfile for executable output
interface CompileBuildConfig extends BuildConfigBase {
/**
* Create a standalone executable
*
* When `true`, creates an executable for the current platform.
* When a target string, creates an executable for that platform.
*
* @example
* ```ts
* // Create executable for current platform
* await Bun.build({
* entrypoints: ['./app.js'],
* compile: {
* target: 'linux-x64',
* },
* outfile: './my-app'
* });
*
* // Cross-compile for Linux x64
* await Bun.build({
* entrypoints: ['./app.js'],
* compile: 'linux-x64',
* outfile: './my-app'
* });
* ```
*/
compile: boolean | Bun.Build.CompileTarget | CompileBuildOptions;
/**
* Splitting is not currently supported with `.compile`
*/
splitting?: never;
}
interface NormalBuildConfig extends BuildConfigBase {
/**
* Enable code splitting
*
* This does not currently work with {@link CompileBuildConfig.compile `compile`}
*
* @default true
*/
splitting?: boolean;
}
/**
* @see [Bun.build API docs](https://bun.com/docs/bundler#api)
*/
type BuildConfig = CompileBuildConfig | NormalBuildConfig;
/**
* Hash and verify passwords using argon2 or bcrypt
*
@@ -5676,7 +5678,7 @@ declare module "bun" {
*
* This will apply to all sockets from the same {@link Listener}. it is per socket only for {@link Bun.connect}.
*/
reload(options: Pick<SocketOptions<Data>, "socket">): void;
reload(handler: SocketHandler): void;
/**
* Get the server that created this socket
@@ -6019,7 +6021,7 @@ declare module "bun" {
stop(closeActiveConnections?: boolean): void;
ref(): void;
unref(): void;
reload(options: Pick<SocketOptions<Data>, "socket">): void;
reload(options: Pick<Partial<SocketOptions>, "socket">): void;
data: Data;
}
interface TCPSocketListener<Data = unknown> extends SocketListener<Data> {

View File

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

View File

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

View File

@@ -828,7 +828,7 @@ struct us_socket_t *us_socket_context_adopt_socket(int ssl, struct us_socket_con
struct us_socket_t *new_s = s;
if (ext_size != -1) {
struct us_poll_t *pool_ref = &s->p;
new_s = (struct us_socket_t *) us_poll_resize(pool_ref, loop, sizeof(struct us_socket_t) - sizeof(struct us_poll_t) + old_ext_size, sizeof(struct us_socket_t) - sizeof(struct us_poll_t) + ext_size);
new_s = (struct us_socket_t *) us_poll_resize(pool_ref, loop, sizeof(struct us_socket_t) + old_ext_size, sizeof(struct us_socket_t) + ext_size);
if(new_s != s) {
/* Mark the old socket as closed */
s->flags.is_closed = 1;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -86,48 +86,6 @@ static constexpr auto supportedHttpMethods = makeArray<std::string_view>(
"UNSUBSCRIBE"
);
// Same as supportedHttpMethods but also includes the "*" (ANY) method token,
// so that handlers registered with "*" also catch unknown/custom HTTP methods
// that don't match any known method node in the router.
static constexpr auto supportedHttpMethodsAndAny = makeArray<std::string_view>(
"ACL",
"BIND",
"CHECKOUT",
"CONNECT",
"COPY",
"DELETE",
"GET",
"HEAD",
"LINK",
"LOCK",
"M-SEARCH",
"MERGE",
"MKACTIVITY",
"MKCALENDAR",
"MKCOL",
"MOVE",
"NOTIFY",
"OPTIONS",
"PATCH",
"POST",
"PROPFIND",
"PROPPATCH",
"PURGE",
"PUT",
"QUERY",
"REBIND",
"REPORT",
"SEARCH",
"SOURCE",
"SUBSCRIBE",
"TRACE",
"UNBIND",
"UNLINK",
"UNLOCK",
"UNSUBSCRIBE",
"*"
);
} // namespace detail
template<bool> struct HttpResponse;
@@ -628,9 +586,7 @@ public:
std::string_view method_sv_buffer;
// When it's NOT node:http, allow the uWS default precedence ordering.
if (method == "*" && !httpContextData->flags.useStrictMethodValidation) {
// Register for all known methods AND the "*" (ANY) node so that
// unknown/custom methods also get routed to this handler.
methods = detail::supportedHttpMethodsAndAny;
methods = detail::supportedHttpMethods;
} else {
method_buffer = std::string(method);
method_sv_buffer = std::string_view(method_buffer);

View File

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

View File

@@ -1,665 +0,0 @@
// Azure REST API client for machine.mjs
// Used by the [build images] pipeline to create Windows VM images (x64 and ARM64)
import { getSecret, isCI } from "./utils.mjs";
/**
* @typedef {Object} AzureConfig
* @property {string} tenantId
* @property {string} clientId
* @property {string} clientSecret
* @property {string} subscriptionId
* @property {string} resourceGroup
* @property {string} location
* @property {string} galleryName
*/
/** @returns {AzureConfig} */
function getConfig() {
const env = (name, fallback) => {
if (isCI) {
try {
return getSecret(name, { required: !fallback }) || fallback;
} catch {
if (fallback) return fallback;
throw new Error(`Azure secret not found: ${name}`);
}
}
return process.env[name] || fallback;
};
return {
tenantId: env("AZURE_TENANT_ID"),
clientId: env("AZURE_CLIENT_ID"),
clientSecret: env("AZURE_CLIENT_SECRET"),
subscriptionId: env("AZURE_SUBSCRIPTION_ID"),
resourceGroup: env("AZURE_RESOURCE_GROUP", "BUN-CI"),
location: env("AZURE_LOCATION", "eastus2"),
galleryName: env("AZURE_GALLERY_NAME", "bunCIGallery2"),
};
}
let _config;
function config() {
return (_config ??= getConfig());
}
// ============================================================================
// Authentication
// ============================================================================
let _accessToken = null;
let _tokenExpiry = 0;
async function getAccessToken() {
if (_accessToken && Date.now() < _tokenExpiry - 300_000) {
return _accessToken;
}
const { tenantId, clientId, clientSecret } = config();
const response = await fetch(`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: clientId,
client_secret: clientSecret,
scope: "https://management.azure.com/.default",
}),
});
if (!response.ok) {
throw new Error(`[azure] Auth failed: ${response.status} ${await response.text()}`);
}
const data = await response.json();
_accessToken = data.access_token;
_tokenExpiry = Date.now() + data.expires_in * 1000;
return _accessToken;
}
// ============================================================================
// REST Client
// ============================================================================
/**
* @param {"GET"|"PUT"|"POST"|"PATCH"|"DELETE"} method
* @param {string} path - Relative path under management.azure.com, or absolute URL
* @param {object} [body]
* @param {string} [apiVersion]
*/
async function azureFetch(method, path, body, apiVersion = "2024-07-01") {
const token = await getAccessToken();
const url = path.startsWith("http") ? new URL(path) : new URL(`https://management.azure.com${path}`);
if (!url.searchParams.has("api-version")) {
url.searchParams.set("api-version", apiVersion);
}
const options = {
method,
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
};
if (body && method !== "GET" && method !== "DELETE") {
options.body = JSON.stringify(body);
}
for (let attempt = 0; attempt < 3; attempt++) {
const response = await fetch(url, options);
if (response.status === 429 || response.status >= 500) {
const wait = Math.pow(2, attempt) * 1000;
console.warn(`[azure] ${method} ${path} returned ${response.status}, retrying in ${wait}ms...`);
await new Promise(r => setTimeout(r, wait));
continue;
}
// 202 Accepted — async operation, poll for completion
if (response.status === 202) {
const operationUrl = response.headers.get("Azure-AsyncOperation") || response.headers.get("Location");
if (operationUrl) {
return waitForOperation(operationUrl);
}
}
if (response.status === 204) {
return null;
}
if (!response.ok) {
const text = await response.text();
throw new Error(`[azure] ${method} ${path} failed: ${response.status} ${text}`);
}
const text = await response.text();
return text ? JSON.parse(text) : null;
}
throw new Error(`[azure] ${method} ${path} failed after 3 retries`);
}
async function waitForOperation(operationUrl, maxWaitMs = 3_600_000) {
const start = Date.now();
let fetchErrors = 0;
while (Date.now() - start < maxWaitMs) {
const token = await getAccessToken();
let response;
try {
response = await fetch(operationUrl, {
headers: { Authorization: `Bearer ${token}` },
});
} catch (err) {
fetchErrors++;
if (fetchErrors > 10) {
throw new Error(`[azure] Operation poll failed after ${fetchErrors} fetch errors`, { cause: err });
}
console.warn(`[azure] Operation poll fetch error (${fetchErrors}), retrying...`);
await new Promise(r => setTimeout(r, 10_000));
continue;
}
if (!response.ok) {
throw new Error(`[azure] Operation poll failed: ${response.status} ${await response.text()}`);
}
const data = await response.json();
if (data.status === "Succeeded") {
return data.properties?.output ?? data;
}
if (data.status === "Failed" || data.status === "Canceled") {
throw new Error(`[azure] Operation ${data.status}: ${data.error?.message ?? "unknown"}`);
}
await new Promise(r => setTimeout(r, 5000));
}
throw new Error(`[azure] Operation timed out after ${maxWaitMs}ms`);
}
// ============================================================================
// Resource helpers
// ============================================================================
function rgPath() {
const { subscriptionId, resourceGroup } = config();
return `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}`;
}
// ============================================================================
// Public IP
// ============================================================================
async function createPublicIp(name) {
const { location } = config();
console.log(`[azure] Creating public IP: ${name}`);
const result = await azureFetch("PUT", `${rgPath()}/providers/Microsoft.Network/publicIPAddresses/${name}`, {
location,
sku: { name: "Standard" },
properties: {
publicIPAllocationMethod: "Static",
deleteOption: "Delete",
},
});
return result?.properties?.ipAddress;
}
async function deletePublicIp(name) {
await azureFetch("DELETE", `${rgPath()}/providers/Microsoft.Network/publicIPAddresses/${name}`).catch(() => {});
}
// ============================================================================
// Network Security Group
// ============================================================================
// ============================================================================
// Network Interface
// ============================================================================
async function createNic(name, publicIpName, subnetId, nsgId) {
const { location } = config();
console.log(`[azure] Creating NIC: ${name}`);
const publicIpId = `${rgPath()}/providers/Microsoft.Network/publicIPAddresses/${publicIpName}`;
await azureFetch("PUT", `${rgPath()}/providers/Microsoft.Network/networkInterfaces/${name}`, {
location,
properties: {
ipConfigurations: [
{
name: "ipconfig1",
properties: {
privateIPAllocationMethod: "Dynamic",
publicIPAddress: { id: publicIpId, properties: { deleteOption: "Delete" } },
subnet: { id: subnetId },
},
},
],
...(nsgId ? { networkSecurityGroup: { id: nsgId } } : {}),
},
});
return `${rgPath()}/providers/Microsoft.Network/networkInterfaces/${name}`;
}
async function deleteNic(name) {
await azureFetch("DELETE", `${rgPath()}/providers/Microsoft.Network/networkInterfaces/${name}`).catch(() => {});
}
// ============================================================================
// Virtual Machines
// ============================================================================
/**
* @param {object} opts
* @param {string} opts.name
* @param {string} opts.vmSize
* @param {object} opts.imageReference
* @param {number} opts.osDiskSizeGB
* @param {string} opts.nicId
* @param {string} opts.adminUsername
* @param {string} opts.adminPassword
* @param {Record<string, string>} [opts.tags]
*/
async function createVm(opts) {
const { location } = config();
console.log(`[azure] Creating VM: ${opts.name} (${opts.vmSize})`);
const result = await azureFetch("PUT", `${rgPath()}/providers/Microsoft.Compute/virtualMachines/${opts.name}`, {
location,
tags: opts.tags,
properties: {
hardwareProfile: { vmSize: opts.vmSize },
storageProfile: {
imageReference: opts.imageReference,
osDisk: {
createOption: "FromImage",
diskSizeGB: opts.osDiskSizeGB,
deleteOption: "Delete",
managedDisk: { storageAccountType: "Premium_LRS" },
},
},
osProfile: {
computerName: opts.name.substring(0, 15),
adminUsername: opts.adminUsername,
adminPassword: opts.adminPassword,
},
securityProfile: {
securityType: "TrustedLaunch",
},
networkProfile: {
networkInterfaces: [{ id: opts.nicId, properties: { deleteOption: "Delete" } }],
},
},
});
return result;
}
async function getVm(name) {
try {
return await azureFetch(
"GET",
`${rgPath()}/providers/Microsoft.Compute/virtualMachines/${name}?$expand=instanceView`,
);
} catch {
return null;
}
}
async function getVmPowerState(name) {
const vm = await getVm(name);
const statuses = vm?.properties?.instanceView?.statuses ?? [];
const powerStatus = statuses.find(s => s.code?.startsWith("PowerState/"));
return powerStatus?.code;
}
async function stopVm(name) {
console.log(`[azure] Stopping VM: ${name}`);
await azureFetch("POST", `${rgPath()}/providers/Microsoft.Compute/virtualMachines/${name}/deallocate`);
}
async function generalizeVm(name) {
console.log(`[azure] Generalizing VM: ${name}`);
await azureFetch("POST", `${rgPath()}/providers/Microsoft.Compute/virtualMachines/${name}/generalize`);
}
async function deleteVm(name) {
console.log(`[azure] Deleting VM: ${name}`);
await azureFetch("DELETE", `${rgPath()}/providers/Microsoft.Compute/virtualMachines/${name}?forceDeletion=true`);
}
async function getPublicIpAddress(publicIpName) {
const result = await azureFetch("GET", `${rgPath()}/providers/Microsoft.Network/publicIPAddresses/${publicIpName}`);
return result?.properties?.ipAddress;
}
/**
* Run a PowerShell script on a Windows VM via Azure Run Command.
* This works even without SSH installed on the VM.
*/
async function runCommand(vmName, script) {
console.log(`[azure] Running command on VM: ${vmName}`);
return azureFetch("POST", `${rgPath()}/providers/Microsoft.Compute/virtualMachines/${vmName}/runCommand`, {
commandId: "RunPowerShellScript",
script: Array.isArray(script) ? script : [script],
});
}
/**
* Install OpenSSH server and configure authorized keys on a Windows VM.
*/
// SSH is not used — all remote operations go through Azure Run Command API.
// ============================================================================
// Virtual Network
// ============================================================================
// ============================================================================
// Compute Gallery
// ============================================================================
const GALLERY_API_VERSION = "2024-03-03";
async function ensureImageDefinition(name, os, arch) {
const { location, galleryName } = config();
const path = `${rgPath()}/providers/Microsoft.Compute/galleries/${galleryName}/images/${name}`;
try {
const def = await azureFetch("GET", path, undefined, GALLERY_API_VERSION);
if (def) return;
} catch {}
console.log(`[azure] Creating image definition: ${name}`);
await azureFetch(
"PUT",
path,
{
location,
properties: {
osType: os === "windows" ? "Windows" : "Linux",
osState: "Generalized",
hyperVGeneration: "V2",
architecture: arch === "aarch64" ? "Arm64" : "x64",
identifier: {
publisher: "bun",
offer: `${os}-${arch}-ci`,
sku: name,
},
features: [
{ name: "DiskControllerTypes", value: "SCSI, NVMe" },
{ name: "SecurityType", value: "TrustedLaunch" },
],
},
},
GALLERY_API_VERSION,
);
}
async function createImageVersion(imageDefName, version, vmId) {
const { location, galleryName } = config();
const path = `${rgPath()}/providers/Microsoft.Compute/galleries/${galleryName}/images/${imageDefName}/versions/${version}`;
console.log(`[azure] Creating image version: ${imageDefName}/${version}`);
const result = await azureFetch(
"PUT",
path,
{
location,
properties: {
storageProfile: {
source: { virtualMachineId: vmId },
},
},
},
GALLERY_API_VERSION,
);
return result;
}
// ============================================================================
// Base Images
// ============================================================================
function getBaseImageReference(os, arch) {
if (os === "windows") {
if (arch === "aarch64") {
return {
publisher: "MicrosoftWindowsDesktop",
offer: "windows11preview-arm64",
sku: "win11-24h2-pro",
version: "latest",
};
}
// Windows Server 2019 x64 — oldest supported version
return {
publisher: "MicrosoftWindowsServer",
offer: "WindowsServer",
sku: "2019-datacenter-gensecond",
version: "latest",
};
}
throw new Error(`[azure] Unsupported OS: ${os}`);
}
function getVmSize(arch) {
return arch === "aarch64" ? "Standard_D4ps_v6" : "Standard_D4ds_v6";
}
// ============================================================================
// Exports
// ============================================================================
export const azure = {
get name() {
return "azure";
},
config,
/**
* @param {import("./machine.mjs").MachineOptions} options
* @returns {Promise<import("./machine.mjs").Machine>}
*/
async createMachine(options) {
const { os, arch, tags, sshKeys } = options;
const vmName = `bun-${os}-${arch}-${Date.now()}`;
const publicIpName = `${vmName}-ip`;
const nicName = `${vmName}-nic`;
const vmSize = options.instanceType || getVmSize(arch);
const diskSizeGB = options.diskSizeGb || (os === "windows" ? 150 : 40);
// Generate a random password for the admin account
const adminPassword = `P@${crypto.randomUUID().replace(/-/g, "").substring(0, 20)}!`;
const subnetId = `${rgPath()}/providers/Microsoft.Network/virtualNetworks/bun-ci-vnet/subnets/default`;
const nsgId = `${rgPath()}/providers/Microsoft.Network/networkSecurityGroups/bun-ci-ssh-nsg`;
await createPublicIp(publicIpName);
const nicId = await createNic(nicName, publicIpName, subnetId, nsgId);
// Create VM
const imageReference = options.imageId ? { id: options.imageId } : getBaseImageReference(os, arch);
await createVm({
name: vmName,
vmSize,
imageReference,
osDiskSizeGB: diskSizeGB,
nicId,
adminUsername: "bunadmin",
adminPassword,
tags: tags
? Object.fromEntries(
Object.entries(tags)
.filter(([_, v]) => v != null)
.map(([k, v]) => [k, String(v)]),
)
: undefined,
});
// Wait for public IP to be assigned
let publicIp;
for (let i = 0; i < 30; i++) {
publicIp = await getPublicIpAddress(publicIpName);
if (publicIp) break;
await new Promise(r => setTimeout(r, 5000));
}
if (!publicIp) {
throw new Error(`[azure] Failed to get public IP for ${vmName}`);
}
console.log(`[azure] VM created: ${vmName} at ${publicIp}`);
// Use Azure Run Command for all remote operations instead of SSH.
// This avoids the sshd startup issues on Azure Windows VMs.
const spawnFn = async (command, opts) => {
const script = command.join(" ");
console.log(`[azure] Run: ${script}`);
// Note: Azure Run Command output is limited to the last 4096 bytes.
// Full output is not available — only the tail is returned.
// value[0] = stdout (ComponentStatus/StdOut), value[1] = stderr (ComponentStatus/StdErr)
const result = await runCommand(vmName, [script]);
const values = result?.value ?? [];
const stdout = values[0]?.message ?? "";
const stderr = values[1]?.message ?? "";
if (opts?.stdio === "inherit") {
if (stdout) process.stdout.write(stdout);
if (stderr) process.stderr.write(stderr);
}
// Only use displayStatus to detect errors — stderr often contains non-error
// output (rustup progress, cargo warnings, PowerShell Write-Warning, etc.)
const hasError = values.some(v => v?.displayStatus === "Provisioning failed");
const exitCode = hasError ? 1 : 0;
return { exitCode, stdout, stderr };
};
const spawnSafeFn = async (command, opts) => {
const result = await spawnFn(command, opts);
if (result.exitCode !== 0) {
const msg = result.stderr || result.stdout || "Unknown error";
throw new Error(`[azure] Command failed (exit ${result.exitCode}): ${command.join(" ")}\n${msg}`);
}
return result;
};
const upload = async (source, destination) => {
// Read the file locally and write it on the VM via Run Command
const { readFileSync } = await import("node:fs");
const content = readFileSync(source, "utf-8");
// Escape for PowerShell — use base64 to avoid escaping issues
const b64 = Buffer.from(content).toString("base64");
const script = [
`$bytes = [Convert]::FromBase64String('${b64}')`,
`$dir = Split-Path '${destination}' -Parent`,
`if (-not (Test-Path $dir)) { New-Item -Path $dir -ItemType Directory -Force | Out-Null }`,
`[IO.File]::WriteAllBytes('${destination}', $bytes)`,
`Write-Host "Uploaded to ${destination} ($($bytes.Length) bytes)"`,
];
console.log(`[azure] Uploading ${source} -> ${destination}`);
await runCommand(vmName, script);
};
const attach = async () => {
console.log(`[azure] Attach not supported via Run Command (VM: ${vmName}, IP: ${publicIp})`);
};
const waitForSsh = async () => {
// No SSH needed — Run Command works immediately after VM is provisioned
// Just verify the VM is responsive
console.log(`[azure] Verifying VM is responsive...`);
await runCommand(vmName, ["Write-Host 'VM is ready'"]);
console.log(`[azure] VM is responsive`);
};
const snapshot = async label => {
const vmId = `${rgPath()}/providers/Microsoft.Compute/virtualMachines/${vmName}`;
// Run sysprep inside the VM before deallocating.
// This prepares Windows for generalization so the gallery image
// can be used to create new VMs with OS provisioning.
console.log(`[azure] Running sysprep on ${vmName}...`);
await runCommand(vmName, ["C:\\Windows\\System32\\Sysprep\\sysprep.exe /generalize /oobe /shutdown /quiet"]);
// Wait for VM to shut down after sysprep (sysprep triggers shutdown)
for (let i = 0; i < 60; i++) {
const state = await getVmPowerState(vmName);
if (state === "PowerState/stopped" || state === "PowerState/deallocated") break;
await new Promise(r => setTimeout(r, 10000));
}
// Deallocate the VM
await stopVm(vmName);
// Wait for VM to be deallocated
for (let i = 0; i < 60; i++) {
const state = await getVmPowerState(vmName);
if (state === "PowerState/deallocated") break;
await new Promise(r => setTimeout(r, 5000));
}
await generalizeVm(vmName);
// Ensure gallery and image definition exist.
// Use the label as the image definition name — this matches what ci.mjs
// emits as the image-name agent tag, so robobun can look it up directly.
const imageDefName = label;
await ensureImageDefinition(imageDefName, os, arch);
// Create a single version "1.0.0" under this definition.
await createImageVersion(imageDefName, "1.0.0", vmId);
// Wait for image replication to complete before returning.
// Single-region replication typically takes 5-15 minutes.
const { galleryName } = config();
const versionPath = `${rgPath()}/providers/Microsoft.Compute/galleries/${galleryName}/images/${imageDefName}/versions/1.0.0`;
console.log(`[azure] Waiting for image replication...`);
for (let i = 0; i < 120; i++) {
const ver = await azureFetch("GET", versionPath, undefined, GALLERY_API_VERSION);
const state = ver?.properties?.provisioningState;
if (state === "Succeeded") {
console.log(`[azure] Image ready: ${imageDefName}/1.0.0`);
break;
}
if (state === "Failed") {
throw new Error(`[azure] Image replication failed: ${JSON.stringify(ver?.properties)}`);
}
if (i % 6 === 0) {
console.log(`[azure] Image replicating... (${i}m elapsed)`);
}
await new Promise(r => setTimeout(r, 10_000));
}
return label;
};
const terminate = async () => {
await deleteVm(vmName);
// Resources with deleteOption=Delete are cleaned up automatically
// But clean up anything that might be left
await deleteNic(nicName);
await deletePublicIp(publicIpName);
};
return {
cloud: "azure",
id: vmName,
imageId: options.imageId,
instanceType: vmSize,
region: config().location,
get publicIp() {
return publicIp;
},
spawn: spawnFn,
spawnSafe: spawnSafeFn,
upload,
attach,
snapshot,
waitForSsh,
close: terminate,
[Symbol.asyncDispose]: terminate,
};
},
};

View File

@@ -1,7 +1,6 @@
# Version: 14
# A script that installs the dependencies needed to build and test Bun on Windows.
# Supports both x64 and ARM64 using Scoop for package management.
# Used by Azure [build images] pipeline.
# Version: 11
# A script that installs the dependencies needed to build and test Bun.
# This should work on Windows 10 or newer with PowerShell.
# If this script does not work on your machine, please open an issue:
# https://github.com/oven-sh/bun/issues
@@ -12,7 +11,7 @@
param (
[Parameter(Mandatory = $false)]
[switch]$CI = ($env:CI -eq "true"),
[switch]$CI = $false,
[Parameter(Mandatory = $false)]
[switch]$Optimize = $CI
)
@@ -20,26 +19,17 @@ param (
$ErrorActionPreference = "Stop"
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
# Detect ARM64 from registry (works even under x64 emulation)
$realArch = (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment').PROCESSOR_ARCHITECTURE
$script:IsARM64 = $realArch -eq "ARM64"
function Execute-Command {
$command = $args -join ' '
Write-Output "$ $command"
# If we're on ARM64 but running under x64 emulation, re-launch as native ARM64.
# Azure Run Command uses x64-emulated PowerShell which breaks package installs.
if ($script:IsARM64 -and $env:PROCESSOR_ARCHITECTURE -ne "ARM64") {
$nativePS = "$env:SystemRoot\Sysnative\WindowsPowerShell\v1.0\powershell.exe"
if (Test-Path $nativePS) {
Write-Output "Re-launching bootstrap as native ARM64 PowerShell..."
& $nativePS -NoProfile -ExecutionPolicy Bypass -File $MyInvocation.MyCommand.Path @PSBoundParameters
exit $LASTEXITCODE
& $args[0] $args[1..$args.Length]
if ((-not $?) -or ($LASTEXITCODE -ne 0 -and $null -ne $LASTEXITCODE)) {
throw "Command failed: $command"
}
}
# ============================================================================
# Utility functions
# ============================================================================
function Which {
param ([switch]$Required = $false)
@@ -56,6 +46,16 @@ function Which {
}
}
function Execute-Script {
param (
[Parameter(Mandatory = $true, Position = 0)]
[string]$Path
)
$pwsh = Which pwsh powershell -Required
Execute-Command $pwsh $Path
}
function Download-File {
param (
[Parameter(Mandatory = $true, Position = 0)]
@@ -87,6 +87,18 @@ function Download-File {
return $Path
}
function Install-Chocolatey {
if (Which choco) {
return
}
Write-Output "Installing Chocolatey..."
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
$installScript = Download-File "https://community.chocolatey.org/install.ps1"
Execute-Script $installScript
Refresh-Path
}
function Refresh-Path {
$paths = @(
[System.Environment]::GetEnvironmentVariable("Path", "Machine"),
@@ -99,19 +111,15 @@ function Refresh-Path {
Where-Object { $_ -and (Test-Path $_) } |
Select-Object -Unique
$env:Path = ($uniquePaths -join ';').TrimEnd(';')
if ($env:ChocolateyInstall) {
Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 -ErrorAction SilentlyContinue
}
}
function Add-To-Path {
param (
[Parameter(Mandatory = $true, Position = 0)]
[string]$PathToAdd,
[Parameter(Mandatory = $false)]
[ValidateSet("Machine", "User")]
[string]$Scope = "Machine"
)
$absolutePath = Resolve-Path $PathToAdd
$currentPath = [Environment]::GetEnvironmentVariable("Path", $Scope)
$absolutePath = Resolve-Path $args[0]
$currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine")
if ($currentPath -like "*$absolutePath*") {
return
}
@@ -132,8 +140,8 @@ function Add-To-Path {
}
}
Write-Output "Adding $absolutePath to PATH ($Scope)..."
[Environment]::SetEnvironmentVariable("Path", "$newPath", $Scope)
Write-Output "Adding $absolutePath to PATH..."
[Environment]::SetEnvironmentVariable("Path", "$newPath", "Machine")
Refresh-Path
}
@@ -150,374 +158,104 @@ function Set-Env {
[System.Environment]::SetEnvironmentVariable("$Name", "$Value", "Process")
}
# ============================================================================
# Scoop — ARM64-native package manager
# ============================================================================
function Install-Scoop {
if (Which scoop) {
return
}
Write-Output "Installing Scoop..."
# Scoop blocks admin installs unless -RunAsAdmin is passed.
# Install to a known global location so all users can access it.
$env:SCOOP = "C:\Scoop"
[Environment]::SetEnvironmentVariable("SCOOP", $env:SCOOP, "Machine")
iex "& {$(irm get.scoop.sh)} -RunAsAdmin -ScoopDir C:\Scoop"
Add-To-Path "C:\Scoop\shims"
Refresh-Path
Write-Output "Scoop version: $(scoop --version)"
}
function Install-Scoop-Package {
function Install-Package {
param (
[Parameter(Mandatory = $true, Position = 0)]
[string]$Name,
[Parameter(Mandatory = $false)]
[string]$Command = $Name
[string]$Command = $Name,
[Parameter(Mandatory = $false)]
[string]$Version,
[Parameter(Mandatory = $false)]
[switch]$Force = $false,
[Parameter(Mandatory = $false)]
[string[]]$ExtraArgs = @()
)
if (Which $Command) {
if (-not $Force `
-and (Which $Command) `
-and (-not $Version -or (& $Command --version) -like "*$Version*")) {
return
}
Write-Output "Installing $Name (via Scoop)..."
# Scoop post_install scripts can have non-fatal Remove-Item errors
# (e.g. 7zip ARM64 7zr.exe locked, llvm-arm64 missing Uninstall.exe).
# Suppress all error streams so they don't kill the bootstrap or Packer.
$prevErrorPref = $ErrorActionPreference
$ErrorActionPreference = "SilentlyContinue"
scoop install $Name *>&1 | ForEach-Object { "$_" } | Write-Host
$ErrorActionPreference = $prevErrorPref
Write-Output "Installing $Name..."
$flags = @(
"--yes",
"--accept-license",
"--no-progress",
"--force"
)
if ($Version) {
$flags += "--version=$Version"
}
Execute-Command choco install $Name @flags @ExtraArgs
Refresh-Path
}
# ============================================================================
# Scoop packages (native ARM64 binaries)
# ============================================================================
function Install-Git {
Install-Scoop-Package git
# Git for Windows ships Unix tools (cat, head, tail, etc.) in usr\bin
$gitUsrBin = "C:\Scoop\apps\git\current\usr\bin"
if (Test-Path $gitUsrBin) {
Add-To-Path $gitUsrBin
function Install-Packages {
foreach ($package in $args) {
Install-Package $package
}
}
function Install-Common-Software {
Install-Chocolatey
Install-Pwsh
Install-Git
Install-Packages curl 7zip nssm
Install-NodeJs
Install-Bun
Install-Cygwin
if ($CI) {
# FIXME: Installing tailscale causes the AWS metadata server to become unreachable
# Install-Tailscale
Install-Buildkite
}
}
function Install-Pwsh {
Install-Package powershell-core -Command pwsh
if ($CI) {
git config --system --add safe.directory "*"
git config --system core.autocrlf false
git config --system core.eol lf
git config --system core.longpaths true
$shellPath = (Which pwsh -Required)
New-ItemProperty `
-Path "HKLM:\\SOFTWARE\\OpenSSH" `
-Name DefaultShell `
-Value $shellPath `
-PropertyType String `
-Force
}
}
function Install-Git {
Install-Packages git
if ($CI) {
Execute-Command git config --system --add safe.directory "*"
Execute-Command git config --system core.autocrlf false
Execute-Command git config --system core.eol lf
Execute-Command git config --system core.longpaths true
}
}
function Install-NodeJs {
# Pin to match the ABI version Bun expects (NODE_MODULE_VERSION 137).
# Latest Node (25.x) uses ABI 141 which breaks node-gyp tests.
Install-Scoop-Package "nodejs@24.3.0" -Command node
}
function Install-CMake {
Install-Scoop-Package cmake
}
function Install-Llvm {
$LLVM_VERSION = "21.1.8"
if (Which clang-cl) {
return
}
if ($script:IsARM64) {
Install-Scoop-Package "llvm-arm64@$LLVM_VERSION" -Command clang-cl
} else {
Install-Scoop-Package "llvm@$LLVM_VERSION" -Command clang-cl
}
}
function Install-Ninja {
Install-Scoop-Package ninja
}
function Install-Python {
Install-Scoop-Package python
}
function Install-Go {
Install-Scoop-Package go
}
function Install-Ruby {
Install-Scoop-Package ruby
}
function Install-7zip {
Install-Scoop-Package 7zip -Command 7z
}
function Install-Make {
Install-Scoop-Package make
}
function Install-Cygwin {
# Cygwin's default mirror (mirrors.kernel.org) can be unreachable from Azure.
# Make this non-fatal — the build will fail later if cygwin is actually needed.
try {
Install-Scoop-Package cygwin
# Cygwin binaries are at <scoop>/apps/cygwin/current/root/bin
$cygwinBin = "C:\Scoop\apps\cygwin\current\root\bin"
if (Test-Path $cygwinBin) {
Add-To-Path $cygwinBin # Machine scope (default) — survives Sysprep
}
} catch {
Write-Warning "Cygwin installation failed (non-fatal): $_"
}
}
# ============================================================================
# Manual installs (not available or not ideal via Scoop)
# ============================================================================
function Install-Pwsh {
if (Which pwsh) {
return
}
$pwshArch = if ($script:IsARM64) { "arm64" } else { "x64" }
Write-Output "Installing PowerShell Core ($pwshArch)..."
$msi = Download-File "https://github.com/PowerShell/PowerShell/releases/download/v7.5.2/PowerShell-7.5.2-win-$pwshArch.msi" -Name "pwsh-$pwshArch.msi"
$process = Start-Process msiexec -ArgumentList "/i `"$msi`" /quiet /norestart ADD_PATH=1" -Wait -PassThru -NoNewWindow
if ($process.ExitCode -ne 0) {
throw "Failed to install PowerShell: code $($process.ExitCode)"
}
Remove-Item $msi -ErrorAction SilentlyContinue
Refresh-Path
}
function Install-OpenSSH {
$sshdService = Get-Service -Name sshd -ErrorAction SilentlyContinue
if ($sshdService) {
return
}
Write-Output "Installing OpenSSH Server..."
# Add-WindowsCapability requires DISM elevation which isn't available in Packer's
# WinRM session. Download and install from GitHub releases instead.
$arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq "Arm64") { "Arm64" } else { "Win64" }
$url = "https://github.com/PowerShell/Win32-OpenSSH/releases/download/v9.8.1.0p1-Preview/OpenSSH-${arch}.zip"
$zip = "$env:TEMP\OpenSSH.zip"
$dest = "$env:ProgramFiles\OpenSSH"
Invoke-WebRequest -Uri $url -OutFile $zip -UseBasicParsing
Expand-Archive -Path $zip -DestinationPath "$env:TEMP\OpenSSH" -Force
New-Item -Path $dest -ItemType Directory -Force | Out-Null
$extractedDir = Get-ChildItem -Path "$env:TEMP\OpenSSH" -Directory | Select-Object -First 1
Get-ChildItem -Path $extractedDir.FullName -Recurse | Move-Item -Destination $dest -Force
& "$dest\install-sshd.ps1"
& "$dest\FixHostFilePermissions.ps1" -Confirm:$false
Remove-Item $zip, "$env:TEMP\OpenSSH" -Recurse -Force -ErrorAction SilentlyContinue
# Configure sshd to start on boot (don't start now — host keys may not exist yet during image build)
Set-Service -Name sshd -StartupType Automatic
# Set default shell to pwsh
$pwshPath = (Which pwsh -ErrorAction SilentlyContinue)
if (-not $pwshPath) { $pwshPath = (Which powershell) }
if ($pwshPath) {
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell `
-Value $pwshPath -PropertyType String -Force
}
# Firewall rule for port 22
$rule = Get-NetFirewallRule -Name "OpenSSH-Server" -ErrorAction SilentlyContinue
if (-not $rule) {
New-NetFirewallRule -Profile Any -Name "OpenSSH-Server" `
-DisplayName "OpenSSH Server (sshd)" -Enabled True `
-Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
}
# Configure sshd_config for key-based auth
$sshdConfigPath = "C:\ProgramData\ssh\sshd_config"
if (Test-Path $sshdConfigPath) {
$config = Get-Content $sshdConfigPath
$config = $config -replace '#PubkeyAuthentication yes', 'PubkeyAuthentication yes'
$config = $config -replace 'PasswordAuthentication yes', 'PasswordAuthentication no'
Set-Content -Path $sshdConfigPath -Value $config
}
Write-Output "OpenSSH Server installed and configured"
# Register a startup task that fetches oven-sh GitHub org members' SSH keys
# on every boot so any bun dev can SSH in.
$fetchScript = @'
try {
$members = Invoke-RestMethod -Uri "https://api.github.com/orgs/oven-sh/members" -Headers @{ "User-Agent" = "bun-ci" }
$keys = @()
foreach ($member in $members) {
if ($member.type -ne "User" -or -not $member.login) { continue }
try {
$userKeys = (Invoke-WebRequest -Uri "https://github.com/$($member.login).keys" -UseBasicParsing).Content
if ($userKeys) { $keys += $userKeys.Trim() }
} catch { }
}
if ($keys.Count -gt 0) {
$keysPath = "C:\ProgramData\ssh\administrators_authorized_keys"
Set-Content -Path $keysPath -Value ($keys -join "`n") -Force
icacls $keysPath /inheritance:r /grant "SYSTEM:(F)" /grant "Administrators:(R)" | Out-Null
}
} catch { }
'@
$scriptPath = "C:\ProgramData\ssh\fetch-ssh-keys.ps1"
Set-Content -Path $scriptPath -Value $fetchScript -Force
$action = New-ScheduledTaskAction -Execute "pwsh.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`""
$trigger = New-ScheduledTaskTrigger -AtStartup
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName "FetchSshKeys" -Action $action -Trigger $trigger `
-Settings $settings -User "SYSTEM" -RunLevel Highest -Force
Write-Output "Registered FetchSshKeys startup task"
}
function Install-Ccache {
if (Which ccache) {
return
}
$version = "4.12.2"
$archSuffix = if ($script:IsARM64) { "aarch64" } else { "x86_64" }
Write-Output "Installing ccache $version ($archSuffix)..."
$zip = Download-File "https://github.com/ccache/ccache/releases/download/v$version/ccache-$version-windows-$archSuffix.zip" -Name "ccache-$archSuffix.zip"
$extractDir = "$env:TEMP\ccache-extract"
Expand-Archive $zip $extractDir -Force
$installDir = "$env:ProgramFiles\ccache"
New-Item -Path $installDir -ItemType Directory -Force | Out-Null
Copy-Item "$extractDir\ccache-$version-windows-$archSuffix\*" $installDir -Recurse -Force
Remove-Item $zip -ErrorAction SilentlyContinue
Remove-Item $extractDir -Recurse -ErrorAction SilentlyContinue
Add-To-Path $installDir
Install-Package nodejs -Command node -Version "24.3.0"
}
function Install-Bun {
if (Which bun) {
return
}
if ($script:IsARM64) {
# No published ARM64 bun binary yet — download from our blob storage
Write-Output "Installing Bun (ARM64 from blob storage)..."
$zip = Download-File "https://buncistore.blob.core.windows.net/artifacts/bun-windows-aarch64.zip" -Name "bun-arm64.zip"
$extractDir = "$env:TEMP\bun-arm64"
Expand-Archive -Path $zip -DestinationPath $extractDir -Force
$bunExe = Get-ChildItem $extractDir -Recurse -Filter "*.exe" | Where-Object { $_.Name -match "bun" } | Select-Object -First 1
if ($bunExe) {
Copy-Item $bunExe.FullName "C:\Windows\System32\bun.exe" -Force
Write-Output "Bun ARM64 installed to C:\Windows\System32\bun.exe"
} else {
throw "Failed to find bun executable in ARM64 zip"
}
} else {
Write-Output "Installing Bun..."
$installScript = Download-File "https://bun.sh/install.ps1" -Name "bun-install.ps1"
$pwsh = Which pwsh powershell -Required
& $pwsh $installScript
Refresh-Path
# Copy to System32 so it survives Sysprep (user profile PATH is lost)
$bunPath = Which bun
if ($bunPath) {
Copy-Item $bunPath "C:\Windows\System32\bun.exe" -Force
Write-Output "Bun copied to C:\Windows\System32\bun.exe"
}
}
Install-Package bun -Version "1.3.1"
}
function Install-Rust {
if (Which rustc) {
return
}
$rustPath = Join-Path $env:ProgramFiles "Rust"
if (-not (Test-Path $rustPath)) {
New-Item -Path $rustPath -ItemType Directory | Out-Null
}
# Set install paths before running rustup so it installs directly
# to Program Files (avoids issues with SYSTEM user profile path)
$env:CARGO_HOME = "$rustPath\cargo"
$env:RUSTUP_HOME = "$rustPath\rustup"
Write-Output "Installing Rustup..."
$rustupInit = Download-File "https://win.rustup.rs/" -Name "rustup-init.exe"
Write-Output "Installing Rust..."
& $rustupInit -y
Write-Output "Setting environment variables for Rust..."
Set-Env "CARGO_HOME" "$rustPath\cargo"
Set-Env "RUSTUP_HOME" "$rustPath\rustup"
Add-To-Path "$rustPath\cargo\bin"
function Install-Cygwin {
Install-Package cygwin
Add-To-Path "C:\tools\cygwin\bin"
}
function Install-Visual-Studio {
param (
[Parameter(Mandatory = $false)]
[string]$Edition = "community"
)
Write-Output "Downloading Visual Studio installer..."
$vsInstaller = Download-File "https://aka.ms/vs/17/release/vs_$Edition.exe"
Write-Output "Installing Visual Studio..."
$vsInstallArgs = @(
"--passive",
"--norestart",
"--wait",
"--force",
"--locale en-US",
"--add Microsoft.VisualStudio.Workload.NativeDesktop",
"--includeRecommended"
)
$process = Start-Process $vsInstaller -ArgumentList ($vsInstallArgs -join ' ') -Wait -PassThru -NoNewWindow
# Exit code 3010 means "reboot required" which is not a real error
if ($process.ExitCode -ne 0 -and $process.ExitCode -ne 3010) {
throw "Failed to install Visual Studio: code $($process.ExitCode)"
}
function Install-Tailscale {
Install-Package tailscale
}
function Install-PdbAddr2line {
cargo install --examples "pdb-addr2line@0.11.2"
# Also copy to System32 so it's always on PATH (like bun.exe)
$src = Join-Path $env:CARGO_HOME "bin\pdb-addr2line.exe"
if (Test-Path $src) {
Copy-Item $src "C:\Windows\System32\pdb-addr2line.exe" -Force
Write-Output "pdb-addr2line copied to C:\Windows\System32"
}
}
function Install-Nssm {
if (Which nssm) {
return
}
# Try Scoop first, fall back to our mirror if nssm.cc is down (503 errors)
Install-Scoop-Package nssm
if (-not (Which nssm)) {
Write-Output "Scoop install of nssm failed, downloading from mirror..."
$zip = Download-File "https://buncistore.blob.core.windows.net/artifacts/nssm-2.24-103-gdee49fc.zip" -Name "nssm.zip"
Expand-Archive -Path $zip -DestinationPath "C:\Windows\Temp\nssm" -Force
$nssm = Get-ChildItem "C:\Windows\Temp\nssm" -Recurse -Filter "nssm.exe" | Where-Object { $_.DirectoryName -like "*win64*" } | Select-Object -First 1
if ($nssm) {
Copy-Item $nssm.FullName "C:\Windows\System32\nssm.exe" -Force
Write-Output "nssm installed to C:\Windows\System32\nssm.exe"
} else {
throw "Failed to install nssm"
}
}
}
# ============================================================================
# Buildkite
# ============================================================================
function Create-Buildkite-Environment-Hooks {
param (
[Parameter(Mandatory = $true)]
@@ -540,17 +278,6 @@ function Create-Buildkite-Environment-Hooks {
"@ | Set-Content -Path $environmentHook -Encoding UTF8
Write-Output "Environment hook created at $environmentHook"
# pre-exit hook: logout from Tailscale so ephemeral nodes are removed
# instantly instead of waiting 30-60 minutes. This runs after the job
# finishes, which is after the SSH user wait loop in runner.node.mjs.
$preExitHook = Join-Path $hooksDir "pre-exit.ps1"
@"
if (Test-Path "C:\Program Files\Tailscale\tailscale.exe") {
& "C:\Program Files\Tailscale\tailscale.exe" logout 2>`$null
}
"@ | Set-Content -Path $preExitHook -Encoding UTF8
Write-Output "Pre-exit hook created at $preExitHook"
}
function Install-Buildkite {
@@ -561,8 +288,7 @@ function Install-Buildkite {
Write-Output "Installing Buildkite agent..."
$env:buildkiteAgentToken = "xxx"
$installScript = Download-File "https://raw.githubusercontent.com/buildkite/agent/main/install.ps1"
$pwsh = Which pwsh powershell -Required
& $pwsh $installScript
Execute-Script $installScript
Refresh-Path
if ($CI) {
@@ -574,9 +300,96 @@ function Install-Buildkite {
}
}
# ============================================================================
# System optimization
# ============================================================================
function Install-Build-Essentials {
Install-Visual-Studio
Install-Packages `
cmake `
make `
ninja `
python `
golang `
nasm `
ruby `
strawberryperl `
mingw
Install-Rust
Install-Ccache
# Needed to remap stack traces
Install-PdbAddr2line
Install-Llvm
}
function Install-Visual-Studio {
param (
[Parameter(Mandatory = $false)]
[string]$Edition = "community"
)
Write-Output "Downloading Visual Studio installer..."
$vsInstaller = Download-File "https://aka.ms/vs/17/release/vs_$Edition.exe"
Write-Output "Installing Visual Studio..."
$vsInstallArgs = @(
"--passive",
"--norestart",
"--wait",
"--force",
"--locale en-US",
"--add Microsoft.VisualStudio.Workload.NativeDesktop",
"--includeRecommended"
)
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = $vsInstaller
$startInfo.Arguments = $vsInstallArgs -join ' '
$startInfo.CreateNoWindow = $true
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $startInfo
$process.Start()
$process.WaitForExit()
if ($process.ExitCode -ne 0) {
throw "Failed to install Visual Studio: code $($process.ExitCode)"
}
}
function Install-Rust {
if (Which rustc) {
return
}
Write-Output "Installing Rustup..."
$rustupInit = Download-File "https://win.rustup.rs/" -Name "rustup-init.exe"
Write-Output "Installing Rust..."
Execute-Command $rustupInit -y
Write-Output "Moving Rust to $env:ProgramFiles..."
$rustPath = Join-Path $env:ProgramFiles "Rust"
if (-not (Test-Path $rustPath)) {
New-Item -Path $rustPath -ItemType Directory
}
Move-Item "$env:UserProfile\.cargo" "$rustPath\cargo" -Force
Move-Item "$env:UserProfile\.rustup" "$rustPath\rustup" -Force
Write-Output "Setting environment variables for Rust..."
Set-Env "CARGO_HOME" "$rustPath\cargo"
Set-Env "RUSTUP_HOME" "$rustPath\rustup"
Add-To-Path "$rustPath\cargo\bin"
}
function Install-Ccache {
Install-Package ccache
}
function Install-PdbAddr2line {
Execute-Command cargo install --examples "pdb-addr2line@0.11.2"
}
function Install-Llvm {
Install-Package llvm `
-Command clang-cl `
-Version "19.1.7"
Add-To-Path "$env:ProgramFiles\LLVM\bin"
}
function Optimize-System {
Disable-Windows-Defender
@@ -604,11 +417,8 @@ function Disable-Windows-Threat-Protection {
}
function Uninstall-Windows-Defender {
# Requires a reboot — run before the windows-restart Packer provisioner.
if (Get-Command Uninstall-WindowsFeature -ErrorAction SilentlyContinue) {
Write-Output "Uninstalling Windows Defender..."
Uninstall-WindowsFeature -Name Windows-Defender
}
Write-Output "Uninstalling Windows Defender..."
Uninstall-WindowsFeature -Name Windows-Defender
}
function Disable-Windows-Services {
@@ -622,12 +432,8 @@ function Disable-Windows-Services {
)
foreach ($service in $services) {
try {
Stop-Service $service -Force -ErrorAction SilentlyContinue
Set-Service $service -StartupType Disabled -ErrorAction SilentlyContinue
} catch {
Write-Warning "Could not disable service: $service"
}
Stop-Service $service -Force
Set-Service $service -StartupType Disabled
}
}
@@ -642,98 +448,13 @@ function Disable-Power-Management {
powercfg /change hibernate-timeout-dc 0
}
# ============================================================================
# Main
# ============================================================================
if ($Optimize) {
Optimize-System
}
# Scoop package manager
Install-Scoop
# Packages via Scoop (native ARM64 or x64 depending on architecture)
# 7zip must be installed before git — git depends on 7zip via Scoop,
# and 7zip's post_install has a cleanup error on ARM64 SYSTEM context.
Install-7zip
Install-Git
Install-NodeJs
Install-CMake
Install-Ninja
Install-Python
Install-Go
Install-Ruby
Install-Make
Install-Llvm
Install-Cygwin
Install-Nssm
Install-Scoop-Package perl
# x64-only packages (not needed on ARM64)
if (-not $script:IsARM64) {
Install-Scoop-Package nasm
Install-Scoop-Package mingw -Command gcc
}
function Install-Tailscale {
if (Which tailscale -ErrorAction SilentlyContinue) {
return
}
Write-Output "Installing Tailscale..."
$msi = "$env:TEMP\tailscale-setup.msi"
$arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq "Arm64") { "arm64" } else { "amd64" }
Invoke-WebRequest -Uri "https://pkgs.tailscale.com/stable/tailscale-setup-latest-${arch}.msi" -OutFile $msi -UseBasicParsing
Start-Process msiexec.exe -ArgumentList "/i `"$msi`" /quiet /norestart" -Wait
Remove-Item $msi -ErrorAction SilentlyContinue
Refresh-Path
Write-Output "Tailscale installed"
# Register a startup task that reads the tailscale authkey from Azure IMDS
# tags and joins the tailnet. The key is set by robobun as a VM tag.
$joinScript = @'
try {
$headers = @{ "Metadata" = "true" }
$response = Invoke-RestMethod -Uri "http://169.254.169.254/metadata/instance/compute/tagsList?api-version=2021-02-01" -Headers $headers
$authkey = ($response | Where-Object { $_.name -eq "tailscale:authkey" }).value
if ($authkey) {
$stepKey = ($response | Where-Object { $_.name -eq "buildkite:step-key" }).value
$buildNumber = ($response | Where-Object { $_.name -eq "buildkite:build-number" }).value
if ($stepKey) {
$hostname = "azure-${stepKey}"
if ($buildNumber) { $hostname += "-${buildNumber}" }
} else {
$hostname = (Invoke-RestMethod -Uri "http://169.254.169.254/metadata/instance/compute/name?api-version=2021-02-01&format=text" -Headers $headers)
}
& "C:\Program Files\Tailscale\tailscale.exe" up --authkey=$authkey --hostname=$hostname --unattended
}
} catch { }
'@
$scriptPath = "C:\ProgramData\tailscale-join.ps1"
Set-Content -Path $scriptPath -Value $joinScript -Force
$action = New-ScheduledTaskAction -Execute "pwsh.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`""
$trigger = New-ScheduledTaskTrigger -AtStartup
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName "TailscaleJoin" -Action $action -Trigger $trigger `
-Settings $settings -User "SYSTEM" -RunLevel Highest -Force
Write-Output "Registered TailscaleJoin startup task"
}
# Manual installs (not in Scoop or need special handling)
Install-Pwsh
Install-OpenSSH
#Install-Tailscale # Disabled — Tailscale adapter interferes with IPv6 multicast tests (node-dgram)
Install-Bun
Install-Ccache
Install-Rust
Install-Visual-Studio
Install-PdbAddr2line
if ($CI) {
Install-Buildkite
}
Install-Common-Software
Install-Build-Essentials
if ($Optimize) {
Optimize-System-Needs-Reboot
}
}

View File

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

View File

@@ -77,10 +77,10 @@ const HAS_CCACHE = CCACHE !== null;
// On Windows, use clang-cl for MSVC compatibility
const CC_BASE = IS_WINDOWS
? findExecutable(["clang-cl.exe", "clang-cl"]) || "clang-cl"
: findExecutable(["clang-21", "clang"]) || "clang";
: findExecutable(["clang-19", "clang"]) || "clang";
const CXX_BASE = IS_WINDOWS
? findExecutable(["clang-cl.exe", "clang-cl"]) || "clang-cl"
: findExecutable(["clang++-21", "clang++"]) || "clang++";
: findExecutable(["clang++-19", "clang++"]) || "clang++";
const CC = HAS_CCACHE ? CCACHE : CC_BASE;
const CXX = HAS_CCACHE ? CCACHE : CXX_BASE;

View File

@@ -14,7 +14,14 @@ import {
startGroup,
} from "./utils.mjs";
const isWindowsARM64 = isWindows && process.arch === "arm64";
// Detect Windows ARM64 - bun may run under x64 emulation (WoW64), so check multiple indicators
const isWindowsARM64 =
isWindows &&
(process.env.PROCESSOR_ARCHITECTURE === "ARM64" ||
process.env.VSCMD_ARG_HOST_ARCH === "arm64" ||
process.env.MSYSTEM_CARCH === "aarch64" ||
(process.env.PROCESSOR_IDENTIFIER || "").includes("ARMv8") ||
process.arch === "arm64");
if (globalThis.Bun) {
await import("./glob-sources.mjs");
@@ -85,9 +92,21 @@ async function build(args) {
generateOptions["--toolchain"] = toolchainPath;
}
// Windows ARM64: log detection (compiler is selected by CMake/toolchain)
// Windows ARM64: automatically set required options
if (isWindowsARM64) {
console.log("Windows ARM64 detected");
// Use clang-cl instead of MSVC cl.exe for proper ARM64 flag support
if (!generateOptions["-DCMAKE_C_COMPILER"]) {
generateOptions["-DCMAKE_C_COMPILER"] = "clang-cl";
}
if (!generateOptions["-DCMAKE_CXX_COMPILER"]) {
generateOptions["-DCMAKE_CXX_COMPILER"] = "clang-cl";
}
// Skip codegen by default since x64 bun crashes under WoW64 emulation
// Can be overridden with -DSKIP_CODEGEN=OFF once ARM64 bun is available
if (!generateOptions["-DSKIP_CODEGEN"]) {
generateOptions["-DSKIP_CODEGEN"] = "ON";
}
console.log("Windows ARM64 detected: using clang-cl and SKIP_CODEGEN=ON");
}
const generateArgs = Object.entries(generateOptions).flatMap(([flag, value]) =>

View File

@@ -1,11 +1,9 @@
#!/usr/bin/env node
import { chmodSync, existsSync, mkdtempSync, readdirSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { existsSync, mkdtempSync, readdirSync } from "node:fs";
import { basename, extname, join, relative, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { inspect, parseArgs } from "node:util";
import { azure } from "./azure.mjs";
import { docker } from "./docker.mjs";
import { tart } from "./tart.mjs";
import {
@@ -37,6 +35,7 @@ import {
spawnSshSafe,
spawnSyncSafe,
startGroup,
tmpdir,
waitForPort,
which,
writeFile,
@@ -1048,14 +1047,16 @@ function getRdpFile(hostname, username) {
* @property {(options: MachineOptions) => Promise<Machine>} createMachine
*/
/**
* @param {string} name
* @returns {Cloud}
*/
function getCloud(name) {
switch (name) {
case "docker":
return docker;
case "aws":
return aws;
case "azure":
return azure;
case "tart":
return tart;
}
@@ -1126,173 +1127,6 @@ function getCloud(name) {
* @property {SshKey[]} sshKeys
*/
async function getAzureToken(tenantId, clientId, clientSecret) {
const response = await fetch(`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: `grant_type=client_credentials&client_id=${clientId}&client_secret=${encodeURIComponent(clientSecret)}&scope=https://management.azure.com/.default`,
});
if (!response.ok) throw new Error(`Azure auth failed: ${response.status}`);
const data = await response.json();
return data.access_token;
}
/**
* Build a Windows image using Packer (Azure only).
* Packer handles VM creation, bootstrap, sysprep, and gallery capture via WinRM.
* This eliminates all the Azure Run Command issues (output truncation, x64 emulation,
* PATH not refreshing, stderr false positives, quote escaping).
*/
async function buildWindowsImageWithPacker({ os, arch, release, command, ci, agentPath, bootstrapPath }) {
const { getSecret } = await import("./utils.mjs");
// Determine Packer template
const templateName = arch === "aarch64" ? "windows-arm64" : "windows-x64";
const templateDir = resolve(import.meta.dirname, "packer");
const templateFile = join(templateDir, `${templateName}.pkr.hcl`);
if (!existsSync(templateFile)) {
throw new Error(`Packer template not found: ${templateFile}`);
}
// Get Azure credentials from Buildkite secrets
const clientId = await getSecret("AZURE_CLIENT_ID");
const clientSecret = await getSecret("AZURE_CLIENT_SECRET");
const subscriptionId = await getSecret("AZURE_SUBSCRIPTION_ID");
const tenantId = await getSecret("AZURE_TENANT_ID");
const resourceGroup = await getSecret("AZURE_RESOURCE_GROUP");
const location = (await getSecret("AZURE_LOCATION")) || "eastus2";
const galleryName = (await getSecret("AZURE_GALLERY_NAME")) || "bunCIGallery2";
// Image naming must match getImageName() in ci.mjs:
// [publish images] / normal CI: "windows-x64-2019-v13"
// [build images]: "windows-x64-2019-build-37194"
const imageKey = arch === "aarch64" ? "windows-aarch64-11" : "windows-x64-2019";
const imageDefName =
command === "publish-image"
? `${imageKey}-v${getBootstrapVersion(os)}`
: ci
? `${imageKey}-build-${getBuildNumber()}`
: `${imageKey}-build-draft-${Date.now()}`;
const galleryArch = arch === "aarch64" ? "Arm64" : "x64";
console.log(`[packer] Ensuring gallery image definition: ${imageDefName}`);
const galleryPath = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.Compute/galleries/${galleryName}/images/${imageDefName}`;
const token = await getAzureToken(tenantId, clientId, clientSecret);
const defResponse = await fetch(`https://management.azure.com${galleryPath}?api-version=2024-03-03`, {
method: "PUT",
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
body: JSON.stringify({
location: location,
properties: {
osType: "Windows",
osState: "Generalized",
hyperVGeneration: "V2",
architecture: galleryArch,
identifier: { publisher: "bun", offer: `${os}-${arch}-ci`, sku: imageDefName },
features: [
{ name: "DiskControllerTypes", value: "SCSI, NVMe" },
{ name: "SecurityType", value: "TrustedLaunch" },
],
},
}),
});
if (!defResponse.ok && defResponse.status !== 409) {
throw new Error(`Failed to create gallery image definition: ${defResponse.status} ${await defResponse.text()}`);
}
// Install Packer if not available
const packerBin = await ensurePacker();
// Initialize plugins
console.log("[packer] Initializing plugins...");
await spawnSafe([packerBin, "init", templateDir], { stdio: "inherit" });
// Build the image
console.log(`[packer] Building ${templateName} image: ${imageDefName}`);
const packerArgs = [
packerBin,
"build",
"-only",
`azure-arm.${templateName}`,
"-var",
`client_id=${clientId}`,
"-var",
`client_secret=${clientSecret}`,
"-var",
`subscription_id=${subscriptionId}`,
"-var",
`tenant_id=${tenantId}`,
"-var",
`resource_group=${resourceGroup}-EASTUS2`,
"-var",
`gallery_resource_group=${resourceGroup}`,
"-var",
`location=${location}`,
"-var",
`gallery_name=${galleryName}`,
"-var",
`image_name=${imageDefName}`,
"-var",
`bootstrap_script=${bootstrapPath}`,
"-var",
`agent_script=${agentPath}`,
templateDir,
];
await spawnSafe(packerArgs, {
stdio: "inherit",
env: {
...process.env,
// Packer also reads these env vars
ARM_CLIENT_ID: clientId,
ARM_CLIENT_SECRET: clientSecret,
ARM_SUBSCRIPTION_ID: subscriptionId,
ARM_TENANT_ID: tenantId,
},
});
console.log(`[packer] Image built successfully: ${imageDefName}`);
}
/**
* Download and install Packer if not already available.
*/
async function ensurePacker() {
// Check if packer is already in PATH
const packerPath = which("packer");
if (packerPath) {
console.log("[packer] Found:", packerPath);
return packerPath;
}
// Check if we have a local copy
const localPacker = join(tmpdir(), "packer");
if (existsSync(localPacker)) {
return localPacker;
}
// Download Packer
const version = "1.15.0";
const platform = process.platform === "win32" ? "windows" : process.platform;
const packerArch = process.arch === "arm64" ? "arm64" : "amd64";
const url = `https://releases.hashicorp.com/packer/${version}/packer_${version}_${platform}_${packerArch}.zip`;
console.log(`[packer] Downloading Packer ${version}...`);
const zipPath = join(tmpdir(), "packer.zip");
const response = await fetch(url);
if (!response.ok) throw new Error(`Failed to download Packer: ${response.status}`);
const buffer = Buffer.from(await response.arrayBuffer());
writeFileSync(zipPath, buffer);
// Extract
await spawnSafe(["unzip", "-o", zipPath, "-d", tmpdir()], { stdio: "inherit" });
chmodSync(localPacker, 0o755);
console.log(`[packer] Installed Packer ${version}`);
return localPacker;
}
async function main() {
const { positionals } = parseArgs({
allowPositionals: true,
@@ -1435,13 +1269,6 @@ async function main() {
}
}
// Use Packer for Windows Azure image builds — it handles VM creation,
// bootstrap, sysprep, and gallery capture via WinRM (no Run Command hacks).
if (args["cloud"] === "azure" && os === "windows" && (command === "create-image" || command === "publish-image")) {
await buildWindowsImageWithPacker({ os, arch, release, command, ci, agentPath, bootstrapPath });
return;
}
/** @type {Machine} */
const machine = await startGroup("Creating machine...", async () => {
console.log("Creating machine:");
@@ -1515,7 +1342,7 @@ async function main() {
});
}
await startGroup(`Connecting${options.cloud === "azure" ? "" : " with SSH"}...`, async () => {
await startGroup("Connecting with SSH...", async () => {
const command = os === "windows" ? ["cmd", "/c", "ver"] : ["uname", "-a"];
await machine.spawnSafe(command, { stdio: "inherit" });
});
@@ -1565,12 +1392,7 @@ async function main() {
if (cloud.name === "docker" || features?.includes("docker")) {
return;
}
// Refresh PATH from registry before running agent.mjs — bootstrap added
// buildkite-agent to PATH but Azure Run Command sessions have stale PATH.
const cmd = `$env:PATH = [Environment]::GetEnvironmentVariable('PATH', 'Machine') + ';' + [Environment]::GetEnvironmentVariable('PATH', 'User'); C:\\Scoop\\apps\\nodejs\\current\\node.exe ${remotePath} install`;
await machine.spawnSafe(["powershell", "-NoProfile", "-Command", cmd], {
stdio: "inherit",
});
await machine.spawnSafe(["node", remotePath, "install"], { stdio: "inherit" });
});
} else {
const tmpPath = "/tmp/agent.mjs";

View File

@@ -1,74 +0,0 @@
packer {
required_plugins {
azure = {
source = "github.com/hashicorp/azure"
version = "= 2.5.0"
}
}
}
// Shared variables for all Windows image builds
variable "client_id" {
type = string
default = env("AZURE_CLIENT_ID")
}
variable "client_secret" {
type = string
sensitive = true
default = env("AZURE_CLIENT_SECRET")
}
variable "subscription_id" {
type = string
default = env("AZURE_SUBSCRIPTION_ID")
}
variable "tenant_id" {
type = string
default = env("AZURE_TENANT_ID")
}
variable "resource_group" {
type = string
default = env("AZURE_RESOURCE_GROUP")
}
variable "location" {
type = string
default = "eastus2"
}
variable "gallery_name" {
type = string
default = "bunCIGallery2"
}
variable "build_number" {
type = string
default = "0"
}
variable "image_name" {
type = string
default = ""
description = "Gallery image definition name. If empty, derived from build_number."
}
variable "bootstrap_script" {
type = string
default = "scripts/bootstrap.ps1"
}
variable "agent_script" {
type = string
default = ""
description = "Path to bundled agent.mjs. If empty, agent install is skipped."
}
variable "gallery_resource_group" {
type = string
default = "BUN-CI"
description = "Resource group containing the Compute Gallery (may differ from build RG)"
}

View File

@@ -1,143 +0,0 @@
source "azure-arm" "windows-arm64" {
// Authentication
client_id = var.client_id
client_secret = var.client_secret
subscription_id = var.subscription_id
tenant_id = var.tenant_id
// Source image Windows 11 ARM64 (no Windows Server ARM64 exists)
os_type = "Windows"
image_publisher = "MicrosoftWindowsDesktop"
image_offer = "windows11preview-arm64"
image_sku = "win11-24h2-pro"
image_version = "latest"
// Build VM only used during image creation, not for CI runners.
// CI runner VM sizes are set in ci.mjs (azureVmSizes).
vm_size = "Standard_D4ps_v6"
// Use existing resource group instead of creating a temp one
build_resource_group_name = var.resource_group
os_disk_size_gb = 150
// Security
security_type = "TrustedLaunch"
secure_boot_enabled = true
vtpm_enabled = true
// Networking Packer creates a temp VNet + public IP + NSG automatically.
// WinRM communicator
communicator = "winrm"
winrm_use_ssl = true
winrm_insecure = true
winrm_timeout = "15m"
winrm_username = "packer"
// CRITICAL: No managed_image_name ARM64 doesn't support Managed Images.
// Packer publishes directly from the VM to the gallery (PR #242 feature).
shared_image_gallery_destination {
subscription = var.subscription_id
resource_group = var.gallery_resource_group
gallery_name = var.gallery_name
image_name = var.image_name != "" ? var.image_name : "windows-aarch64-11-build-${var.build_number}"
image_version = "1.0.0"
storage_account_type = "Standard_LRS"
target_region { name = var.location }
target_region { name = "australiaeast" }
target_region { name = "brazilsouth" }
target_region { name = "canadacentral" }
target_region { name = "canadaeast" }
target_region { name = "centralindia" }
target_region { name = "centralus" }
target_region { name = "francecentral" }
target_region { name = "germanywestcentral" }
target_region { name = "italynorth" }
target_region { name = "japaneast" }
target_region { name = "japanwest" }
target_region { name = "koreacentral" }
target_region { name = "mexicocentral" }
target_region { name = "northcentralus" }
target_region { name = "northeurope" }
target_region { name = "southcentralus" }
target_region { name = "southeastasia" }
target_region { name = "spaincentral" }
target_region { name = "swedencentral" }
target_region { name = "switzerlandnorth" }
target_region { name = "uaenorth" }
target_region { name = "ukwest" }
target_region { name = "westeurope" }
target_region { name = "westus" }
target_region { name = "westus2" }
target_region { name = "westus3" }
}
azure_tags = {
os = "windows"
arch = "aarch64"
build = var.build_number
}
}
build {
sources = ["source.azure-arm.windows-arm64"]
// Step 1: Run bootstrap installs all build dependencies
provisioner "powershell" {
script = var.bootstrap_script
valid_exit_codes = [0, 3010]
environment_vars = ["CI=true"]
}
// Step 2: Upload agent.mjs
provisioner "file" {
source = var.agent_script
destination = "C:\\buildkite-agent\\agent.mjs"
}
// Step 3: Install agent service via nssm
provisioner "powershell" {
inline = [
"C:\\Scoop\\apps\\nodejs\\current\\node.exe C:\\buildkite-agent\\agent.mjs install"
]
valid_exit_codes = [0]
}
// Step 4: Reboot to clear pending updates (VS Build Tools, Windows Updates)
provisioner "windows-restart" {
restart_timeout = "10m"
}
// Step 5: Sysprep MUST be last provisioner
provisioner "powershell" {
inline = [
"Remove-Item -Recurse -Force C:\\Windows\\Panther -ErrorAction SilentlyContinue",
"Write-Output '>>> Clearing pending reboot flags...'",
"Remove-Item 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootPending' -Recurse -Force -ErrorAction SilentlyContinue",
"Remove-ItemProperty 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update' -Name 'RebootRequired' -Force -ErrorAction SilentlyContinue",
"Remove-Item 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update\\RebootRequired' -Recurse -Force -ErrorAction SilentlyContinue",
"Remove-ItemProperty 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Session Manager' -Name 'PendingFileRenameOperations' -Force -ErrorAction SilentlyContinue",
"Write-Output '>>> Waiting for Azure Guest Agent...'",
"while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }",
"while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }",
"Write-Output '>>> Running Sysprep...'",
"$global:LASTEXITCODE = 0",
"& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit /mode:vm",
"$timeout = 300; $elapsed = 0",
"while ($true) {",
" $imageState = (Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State).ImageState",
" Write-Output \"ImageState: $imageState ($${elapsed}s)\"",
" if ($imageState -eq 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { break }",
" if ($elapsed -ge $timeout) {",
" Write-Error \"Timed out after $${timeout}s -- stuck at $imageState\"",
" Get-Content \"$env:SystemRoot\\System32\\Sysprep\\Panther\\setupact.log\" -Tail 100 -ErrorAction SilentlyContinue",
" exit 1",
" }",
" Start-Sleep -s 10",
" $elapsed += 10",
"}",
"Write-Output '>>> Sysprep complete.'"
]
}
}

View File

@@ -1,144 +0,0 @@
source "azure-arm" "windows-x64" {
// Authentication (from env vars or -var flags)
client_id = var.client_id
client_secret = var.client_secret
subscription_id = var.subscription_id
tenant_id = var.tenant_id
// Source image Windows Server 2019 Gen2
os_type = "Windows"
image_publisher = "MicrosoftWindowsServer"
image_offer = "WindowsServer"
image_sku = "2019-datacenter-gensecond"
image_version = "latest"
// Build VM only used during image creation, not for CI runners.
// CI runner VM sizes are set in ci.mjs (azureVmSizes).
vm_size = "Standard_D4ds_v6"
// Use existing resource group instead of creating a temp one
build_resource_group_name = var.resource_group
os_disk_size_gb = 150
// Security
security_type = "TrustedLaunch"
secure_boot_enabled = true
vtpm_enabled = true
// Networking Packer creates a temp VNet + public IP + NSG automatically.
// WinRM needs the public IP to connect from CI runners.
// WinRM communicator Packer auto-configures via temp Key Vault
communicator = "winrm"
winrm_use_ssl = true
winrm_insecure = true
winrm_timeout = "15m"
winrm_username = "packer"
// Output Managed Image (x64 supports this)
// Also publish to Compute Gallery
shared_image_gallery_destination {
subscription = var.subscription_id
resource_group = var.gallery_resource_group
gallery_name = var.gallery_name
image_name = var.image_name != "" ? var.image_name : "windows-x64-2019-build-${var.build_number}"
image_version = "1.0.0"
storage_account_type = "Standard_LRS"
target_region { name = var.location }
target_region { name = "australiaeast" }
target_region { name = "brazilsouth" }
target_region { name = "canadacentral" }
target_region { name = "canadaeast" }
target_region { name = "centralindia" }
target_region { name = "centralus" }
target_region { name = "francecentral" }
target_region { name = "germanywestcentral" }
target_region { name = "italynorth" }
target_region { name = "japaneast" }
target_region { name = "japanwest" }
target_region { name = "koreacentral" }
target_region { name = "mexicocentral" }
target_region { name = "northcentralus" }
target_region { name = "northeurope" }
target_region { name = "southcentralus" }
target_region { name = "southeastasia" }
target_region { name = "spaincentral" }
target_region { name = "swedencentral" }
target_region { name = "switzerlandnorth" }
target_region { name = "uaenorth" }
target_region { name = "ukwest" }
target_region { name = "westeurope" }
target_region { name = "westus" }
target_region { name = "westus2" }
target_region { name = "westus3" }
}
azure_tags = {
os = "windows"
arch = "x64"
build = var.build_number
}
}
build {
sources = ["source.azure-arm.windows-x64"]
// Step 1: Run bootstrap installs all build dependencies
provisioner "powershell" {
script = var.bootstrap_script
valid_exit_codes = [0, 3010]
environment_vars = ["CI=true"]
}
// Step 2: Upload agent.mjs
provisioner "file" {
source = var.agent_script
destination = "C:\\buildkite-agent\\agent.mjs"
}
// Step 3: Install agent service via nssm
provisioner "powershell" {
inline = [
"C:\\Scoop\\apps\\nodejs\\current\\node.exe C:\\buildkite-agent\\agent.mjs install"
]
valid_exit_codes = [0]
}
// Step 4: Reboot to clear pending updates (VS Build Tools, Windows Updates)
provisioner "windows-restart" {
restart_timeout = "10m"
}
// Step 5: Sysprep MUST be last provisioner
provisioner "powershell" {
inline = [
"Remove-Item -Recurse -Force C:\\Windows\\Panther -ErrorAction SilentlyContinue",
"Write-Output '>>> Clearing pending reboot flags...'",
"Remove-Item 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootPending' -Recurse -Force -ErrorAction SilentlyContinue",
"Remove-ItemProperty 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update' -Name 'RebootRequired' -Force -ErrorAction SilentlyContinue",
"Remove-Item 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update\\RebootRequired' -Recurse -Force -ErrorAction SilentlyContinue",
"Remove-ItemProperty 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Session Manager' -Name 'PendingFileRenameOperations' -Force -ErrorAction SilentlyContinue",
"Write-Output '>>> Waiting for Azure Guest Agent...'",
"while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }",
"while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }",
"Write-Output '>>> Running Sysprep...'",
"$global:LASTEXITCODE = 0",
"& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit /mode:vm",
"$timeout = 300; $elapsed = 0",
"while ($true) {",
" $imageState = (Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State).ImageState",
" Write-Output \"ImageState: $imageState ($${elapsed}s)\"",
" if ($imageState -eq 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { break }",
" if ($elapsed -ge $timeout) {",
" Write-Error \"Timed out after $${timeout}s -- stuck at $imageState\"",
" Get-Content \"$env:SystemRoot\\System32\\Sysprep\\Panther\\setupact.log\" -Tail 100 -ErrorAction SilentlyContinue",
" exit 1",
" }",
" Start-Sleep -s 10",
" $elapsed += 10",
"}",
"Write-Output '>>> Sysprep complete.'"
]
}
}

View File

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

View File

@@ -1837,13 +1837,6 @@ export function getTailscale() {
}
}
if (isWindows) {
const tailscaleExe = "C:\\Program Files\\Tailscale\\tailscale.exe";
if (existsSync(tailscaleExe)) {
return tailscaleExe;
}
}
return "tailscale";
}
@@ -2050,7 +2043,7 @@ export function getShell() {
}
/**
* @typedef {"aws" | "google" | "azure"} Cloud
* @typedef {"aws" | "google"} Cloud
*/
/** @type {Cloud | undefined} */
@@ -2143,37 +2136,6 @@ export async function isGoogleCloud() {
}
}
/**
* @returns {Promise<boolean | undefined>}
*/
export async function isAzure() {
if (typeof detectedCloud === "string") {
return detectedCloud === "azure";
}
async function detectAzure() {
// Azure IMDS (Instance Metadata Service) — the official way to detect Azure VMs.
// https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service
const { error, body } = await curl("http://169.254.169.254/metadata/instance?api-version=2021-02-01", {
headers: { "Metadata": "true" },
retries: 1,
});
if (!error && body) {
try {
const metadata = JSON.parse(body);
if (metadata?.compute?.azEnvironment) {
return true;
}
} catch {}
}
}
if (await detectAzure()) {
detectedCloud = "azure";
return true;
}
}
/**
* @returns {Promise<Cloud | undefined>}
*/
@@ -2189,10 +2151,6 @@ export async function getCloud() {
if (await isGoogleCloud()) {
return "google";
}
if (await isAzure()) {
return "azure";
}
}
/**
@@ -2217,10 +2175,6 @@ export async function getCloudMetadata(name, cloud) {
} else if (cloud === "google") {
url = new URL(name, "http://metadata.google.internal/computeMetadata/v1/instance/");
headers = { "Metadata-Flavor": "Google" };
} else if (cloud === "azure") {
// Azure IMDS uses a single JSON endpoint; individual fields are extracted by the caller.
url = new URL("http://169.254.169.254/metadata/instance?api-version=2021-02-01");
headers = { "Metadata": "true" };
} else {
throw new Error(`Unsupported cloud: ${inspect(cloud)}`);
}
@@ -2239,25 +2193,7 @@ export async function getCloudMetadata(name, cloud) {
* @param {Cloud} [cloud]
* @returns {Promise<string | undefined>}
*/
export async function getCloudMetadataTag(tag, cloud) {
cloud ??= await getCloud();
if (cloud === "azure") {
// Azure IMDS returns all tags in a single JSON response.
// Tags are in compute.tagsList as [{name, value}, ...].
const body = await getCloudMetadata("", cloud);
if (!body) return;
try {
const metadata = JSON.parse(body);
const tags = metadata?.compute?.tagsList;
if (Array.isArray(tags)) {
const entry = tags.find(t => t.name === tag);
return entry?.value;
}
} catch {}
return;
}
export function getCloudMetadataTag(tag, cloud) {
const metadata = {
"aws": `tags/instance/${tag}`,
"google": `labels/${tag.replace(":", "-")}`,

View File

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

View File

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

View File

@@ -17,34 +17,17 @@ if($env:VSINSTALLDIR -eq $null) {
$vsDir = (& $vswhere -prerelease -latest -property installationPath)
if ($vsDir -eq $null) {
# Check common VS installation paths
$searchPaths = @(
"C:\Program Files\Microsoft Visual Studio\2022",
"C:\Program Files (x86)\Microsoft Visual Studio\2022"
)
foreach ($searchPath in $searchPaths) {
if (Test-Path $searchPath) {
$vsDir = (Get-ChildItem -Path $searchPath -Directory | Select-Object -First 1).FullName
if ($vsDir -ne $null) { break }
}
}
$vsDir = Get-ChildItem -Path "C:\Program Files\Microsoft Visual Studio\2022" -Directory
if ($vsDir -eq $null) {
throw "Visual Studio directory not found."
}
$vsDir = $vsDir.FullName
}
Push-Location $vsDir
try {
$vsShell = (Join-Path -Path $vsDir -ChildPath "Common7\Tools\Launch-VsDevShell.ps1")
# -HostArch only accepts "x86" or "amd64" — even on native ARM64, use "amd64"
$hostArch = if ($script:VsArch -eq "arm64") { "amd64" } else { $script:VsArch }
. $vsShell -Arch $script:VsArch -HostArch $hostArch
# VS dev shell with -HostArch amd64 sets PROCESSOR_ARCHITECTURE=AMD64,
# which causes CMake to misdetect the system as x64. Restore it on ARM64.
if ($script:IsARM64) {
$env:PROCESSOR_ARCHITECTURE = "ARM64"
}
. $vsShell -Arch $script:VsArch -HostArch $script:VsArch
} finally {
Pop-Location
}
@@ -78,7 +61,7 @@ if ($args.Count -gt 0) {
$displayArgs += $arg
}
}
Write-Host "$ $command $displayArgs"
& $command $commandArgs
exit $LASTEXITCODE

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -52,7 +52,7 @@ ts_enums: Ast.TsEnumsMap = .{},
flags: BundledAst.Flags = .{},
pub const Flags = packed struct(u16) {
pub const Flags = packed struct(u8) {
// This is a list of CommonJS features. When a file uses CommonJS features,
// it's not a candidate for "flat bundling" and must be wrapped in its own
// closure.
@@ -65,8 +65,6 @@ pub const Flags = packed struct(u16) {
has_lazy_export: bool = false,
commonjs_module_exports_assigned_deoptimized: bool = false,
has_explicit_use_strict_directive: bool = false,
has_import_meta: bool = false,
_padding: u7 = 0,
};
pub const empty = BundledAst.init(Ast.empty);
@@ -118,7 +116,6 @@ pub fn toAST(this: *const BundledAst) Ast {
.has_lazy_export = this.flags.has_lazy_export,
.commonjs_module_exports_assigned_deoptimized = this.flags.commonjs_module_exports_assigned_deoptimized,
.directive = if (this.flags.has_explicit_use_strict_directive) "use strict" else null,
.has_import_meta = this.flags.has_import_meta,
};
}
@@ -171,7 +168,6 @@ pub fn init(ast: Ast) BundledAst {
.has_lazy_export = ast.has_lazy_export,
.commonjs_module_exports_assigned_deoptimized = ast.commonjs_module_exports_assigned_deoptimized,
.has_explicit_use_strict_directive = strings.eqlComptime(ast.directive orelse "", "use strict"),
.has_import_meta = ast.has_import_meta,
},
};
}
@@ -183,14 +179,13 @@ pub fn addUrlForCss(
source: *const logger.Source,
mime_type_: ?[]const u8,
unique_key: ?[]const u8,
force_inline: bool,
) void {
{
const mime_type = if (mime_type_) |m| m else MimeType.byExtension(bun.strings.trimLeadingChar(std.fs.path.extension(source.path.text), '.')).value;
const contents = source.contents;
// TODO: make this configurable
const COPY_THRESHOLD = 128 * 1024; // 128kb
const should_copy = !force_inline and contents.len >= COPY_THRESHOLD and unique_key != null;
const should_copy = contents.len >= COPY_THRESHOLD and unique_key != null;
if (should_copy) return;
this.url_for_css = url_for_css: {

View File

@@ -32,7 +32,6 @@ pub const Class = struct {
close_brace_loc: logger.Loc = logger.Loc.Empty,
properties: []Property = &([_]Property{}),
has_decorators: bool = false,
should_lower_standard_decorators: bool = false,
pub fn canBeMoved(this: *const Class) bool {
if (this.extends != null)
@@ -135,7 +134,6 @@ pub const Property = struct {
declare,
abstract,
class_static_block,
auto_accessor,
pub fn jsonStringify(self: @This(), writer: anytype) !void {
return try writer.write(@tagName(self));

View File

@@ -99,7 +99,6 @@ pub fn NewParser_(
pub const parseStmtsUpTo = parse_zig.parseStmtsUpTo;
pub const parseAsyncPrefixExpr = parse_zig.parseAsyncPrefixExpr;
pub const parseTypeScriptDecorators = parse_zig.parseTypeScriptDecorators;
pub const parseStandardDecorator = parse_zig.parseStandardDecorator;
pub const parseTypeScriptNamespaceStmt = parse_zig.parseTypeScriptNamespaceStmt;
pub const parseTypeScriptImportEqualsStmt = parse_zig.parseTypeScriptImportEqualsStmt;
pub const parseTypescriptEnumStmt = parse_zig.parseTypescriptEnumStmt;
@@ -137,10 +136,6 @@ pub fn NewParser_(
pub const findSymbol = symbols_zig.findSymbol;
pub const findSymbolWithRecordUsage = symbols_zig.findSymbolWithRecordUsage;
const lowerDecorators_zig = @import("./lowerDecorators.zig").LowerDecorators(parser_feature__typescript, parser_feature__jsx, parser_feature__scan_only);
pub const lowerStandardDecoratorsStmt = lowerDecorators_zig.lowerStandardDecoratorsStmt;
pub const lowerStandardDecoratorsExpr = lowerDecorators_zig.lowerStandardDecoratorsExpr;
macro: MacroState = undefined,
allocator: Allocator,
options: Parser.Options,
@@ -491,10 +486,6 @@ pub fn NewParser_(
/// Used for react refresh, it must be able to insert `const _s = $RefreshSig$();`
nearest_stmt_list: ?*ListManaged(Stmt) = null,
/// Name from assignment context for anonymous decorated class expressions.
/// Set before visitExpr, consumed by lowerStandardDecoratorsImpl.
decorator_class_name: ?[]const u8 = null,
const RecentlyVisitedTSNamespace = struct {
expr: Expr.Data = Expr.empty.data,
map: ?*js_ast.TSNamespaceMemberMap = null,
@@ -3768,10 +3759,7 @@ pub fn NewParser_(
}
},
else => {
// Standard decorator lowering can produce non-class
// statements as the export default value; conservatively
// assume they have side effects.
return false;
Output.panic("Unexpected type in export default", .{});
},
}
},
@@ -4869,11 +4857,6 @@ pub fn NewParser_(
) []Stmt {
switch (stmtorexpr) {
.stmt => |stmt| {
// Standard decorator lowering path (for both JS and TS files)
if (stmt.data.s_class.class.should_lower_standard_decorators) {
return p.lowerStandardDecoratorsStmt(stmt);
}
if (comptime !is_typescript_enabled) {
if (!stmt.data.s_class.class.has_decorators) {
var stmts = p.allocator.alloc(Stmt, 1) catch unreachable;
@@ -5024,7 +5007,7 @@ pub fn NewParser_(
}
}
},
.spread, .declare, .auto_accessor => {}, // not allowed in a class (auto_accessor is standard decorators only)
.spread, .declare => {}, // not allowed in a class
.class_static_block => {}, // not allowed to decorate this
}
}
@@ -6608,7 +6591,6 @@ pub fn NewParser_(
.top_level_await_keyword = p.top_level_await_keyword,
.commonjs_named_exports = p.commonjs_named_exports,
.has_commonjs_export_names = p.has_commonjs_export_names,
.has_import_meta = p.has_import_meta,
.hashbang = hashbang,
// TODO: cross-module constant inlining

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,6 @@ pub fn Parse(
pub const parseImportClause = @import("./parseImportExport.zig").ParseImportExport(parser_feature__typescript, parser_feature__jsx, parser_feature__scan_only).parseImportClause;
pub const parseExportClause = @import("./parseImportExport.zig").ParseImportExport(parser_feature__typescript, parser_feature__jsx, parser_feature__scan_only).parseExportClause;
pub const parseTypeScriptDecorators = @import("./parseTypescript.zig").ParseTypescript(parser_feature__typescript, parser_feature__jsx, parser_feature__scan_only).parseTypeScriptDecorators;
pub const parseStandardDecorator = @import("./parseTypescript.zig").ParseTypescript(parser_feature__typescript, parser_feature__jsx, parser_feature__scan_only).parseStandardDecorator;
pub const parseTypeScriptNamespaceStmt = @import("./parseTypescript.zig").ParseTypescript(parser_feature__typescript, parser_feature__jsx, parser_feature__scan_only).parseTypeScriptNamespaceStmt;
pub const parseTypeScriptImportEqualsStmt = @import("./parseTypescript.zig").ParseTypescript(parser_feature__typescript, parser_feature__jsx, parser_feature__scan_only).parseTypeScriptImportEqualsStmt;
pub const parseTypescriptEnumStmt = @import("./parseTypescript.zig").ParseTypescript(parser_feature__typescript, parser_feature__jsx, parser_feature__scan_only).parseTypescriptEnumStmt;
@@ -103,7 +102,6 @@ pub fn Parse(
pub fn parseClass(p: *P, class_keyword: logger.Range, name: ?js_ast.LocRef, class_opts: ParseClassOptions) !G.Class {
var extends: ?Expr = null;
var has_decorators: bool = false;
var has_auto_accessor: bool = false;
if (p.lexer.token == .t_extends) {
try p.lexer.next();
@@ -170,7 +168,6 @@ pub fn Parse(
// This property may turn out to be a type in TypeScript, which should be ignored
if (try p.parseProperty(.normal, &opts, null)) |property| {
properties.append(property) catch unreachable;
has_auto_accessor = has_auto_accessor or property.kind == .auto_accessor;
// Forbid decorators on class constructors
if (opts.ts_decorators.len > 0) {
@@ -199,7 +196,6 @@ pub fn Parse(
const close_brace_loc = p.lexer.loc();
try p.lexer.expect(.t_close_brace);
const has_any_decorators = has_decorators or class_opts.ts_decorators.len > 0;
return G.Class{
.class_name = name,
.extends = extends,
@@ -208,8 +204,7 @@ pub fn Parse(
.class_keyword = class_keyword,
.body_loc = body_loc,
.properties = properties.items,
.has_decorators = has_any_decorators,
.should_lower_standard_decorators = p.options.features.standard_decorators and (has_any_decorators or has_auto_accessor),
.has_decorators = has_decorators or class_opts.ts_decorators.len > 0,
};
}

View File

@@ -390,58 +390,7 @@ pub fn ParsePrefix(
_ = try p.skipTypeScriptTypeParameters(.{ .allow_in_out_variance_annotations = true, .allow_const_modifier = true });
}
const class = try p.parseClass(classKeyword, name, ParseClassOptions{
.allow_ts_decorators = is_typescript_enabled or p.options.features.standard_decorators,
});
p.popScope();
return p.newExpr(class, loc);
}
fn t_at(noalias p: *P) anyerror!Expr {
// Parse decorators before a class expression: @dec class { ... }
const ts_decorators = try p.parseTypeScriptDecorators();
// Expect class keyword after decorators
if (p.lexer.token != .t_class) {
try p.lexer.expected(.t_class);
return error.SyntaxError;
}
const loc = p.lexer.loc();
const classKeyword = p.lexer.range();
try p.lexer.next();
var name: ?js_ast.LocRef = null;
_ = p.pushScopeForParsePass(.class_name, loc) catch unreachable;
// Parse an optional class name
if (p.lexer.token == .t_identifier) {
const name_text = p.lexer.identifier;
if (!is_typescript_enabled or !strings.eqlComptime(name_text, "implements")) {
if (p.fn_or_arrow_data_parse.allow_await != .allow_ident and strings.eqlComptime(name_text, "await")) {
p.log.addRangeError(p.source, p.lexer.range(), "Cannot use \"await\" as an identifier here") catch unreachable;
}
name = js_ast.LocRef{
.loc = p.lexer.loc(),
.ref = p.newSymbol(
.other,
name_text,
) catch unreachable,
};
try p.lexer.next();
}
}
// Even anonymous classes can have TypeScript type parameters
if (is_typescript_enabled) {
_ = try p.skipTypeScriptTypeParameters(.{ .allow_in_out_variance_annotations = true, .allow_const_modifier = true });
}
const class = try p.parseClass(classKeyword, name, ParseClassOptions{
.ts_decorators = ts_decorators,
.allow_ts_decorators = true,
});
const class = try p.parseClass(classKeyword, name, ParseClassOptions{});
p.popScope();
return p.newExpr(class, loc);
@@ -778,7 +727,6 @@ pub fn ParsePrefix(
.t_plus_plus => t_plus_plus(p),
.t_function => t_function(p),
.t_class => t_class(p),
.t_at => t_at(p),
.t_new => t_new(p, flags),
.t_super => t_super(p, level),
else => {

View File

@@ -158,7 +158,7 @@ pub fn ParseProperty(
try p.lexer.next();
},
.t_private_identifier => {
if (!opts.is_class or (opts.ts_decorators.len > 0 and !p.options.features.standard_decorators)) {
if (!opts.is_class or opts.ts_decorators.len > 0) {
try p.lexer.expected(.t_identifier);
}
@@ -299,16 +299,6 @@ pub fn ParseProperty(
return null;
}
},
.p_accessor => {
// "accessor" keyword for auto-accessor fields (TC39 standard decorators)
if (opts.is_class and p.options.features.standard_decorators and
(js_lexer.PropertyModifierKeyword.List.get(raw) orelse .p_static) == .p_accessor)
{
kind = .auto_accessor;
errors = null;
continue :restart;
}
},
.p_private, .p_protected, .p_public, .p_readonly, .p_override => {
// Skip over TypeScript keywords
if (opts.is_class and is_typescript_enabled and (js_lexer.PropertyModifierKeyword.List.get(raw) orelse .p_static) == keyword) {
@@ -421,7 +411,7 @@ pub fn ParseProperty(
try p.lexer.next();
} else if (p.lexer.token == .t_exclamation and
!p.lexer.has_newline_before and
(kind == .normal or kind == .auto_accessor) and
kind == .normal and
!opts.is_async and
!opts.is_generator)
{
@@ -440,7 +430,7 @@ pub fn ParseProperty(
// Parse a class field with an optional initial value
if (opts.is_class and
(kind == .normal or kind == .auto_accessor) and !opts.is_async and
kind == .normal and !opts.is_async and
!opts.is_generator and
p.lexer.token != .t_open_paren and
!has_type_parameters and
@@ -528,12 +518,6 @@ pub fn ParseProperty(
};
}
// Auto-accessor fields cannot be methods
if (kind == .auto_accessor and p.lexer.token == .t_open_paren) {
p.log.addRangeError(p.source, key_range, "auto-accessor properties cannot have a method body") catch unreachable;
return error.SyntaxError;
}
// Parse a method expression
if (p.lexer.token == .t_open_paren or kind != .normal or opts.is_class or opts.is_async or opts.is_generator) {
return parseMethodExpression(p, kind, opts, is_computed, &key, key_range);

View File

@@ -445,7 +445,7 @@ pub fn ParseStmt(
}
fn t_at(p: *P, opts: *ParseStatementOptions) anyerror!Stmt {
// Parse decorators before class statements, which are potentially exported
if (is_typescript_enabled or p.options.features.standard_decorators) {
if (is_typescript_enabled) {
const scope_index = p.scopes_in_order.items.len;
const ts_decorators = try p.parseTypeScriptDecorators();
@@ -473,10 +473,7 @@ pub fn ParseStmt(
// "@decorator export declare abstract class Foo {}"
// "@decorator export default class Foo {}"
// "@decorator export default abstract class Foo {}"
if (p.lexer.token != .t_class and p.lexer.token != .t_export and
!(is_typescript_enabled and p.lexer.isContextualKeyword("abstract")) and
!(is_typescript_enabled and p.lexer.isContextualKeyword("declare")))
{
if (p.lexer.token != .t_class and p.lexer.token != .t_export and !p.lexer.isContextualKeyword("abstract") and !p.lexer.isContextualKeyword("declare")) {
try p.lexer.expected(.t_class);
}

View File

@@ -8,7 +8,7 @@ pub fn ParseTypescript(
const is_typescript_enabled = P.is_typescript_enabled;
pub fn parseTypeScriptDecorators(p: *P) ![]ExprNodeIndex {
if (!is_typescript_enabled and !p.options.features.standard_decorators) {
if (!is_typescript_enabled) {
return &([_]ExprNodeIndex{});
}
@@ -16,106 +16,22 @@ pub fn ParseTypescript(
while (p.lexer.token == T.t_at) {
try p.lexer.next();
if (p.options.features.standard_decorators) {
// TC39 standard decorator grammar:
// @Identifier
// @Identifier.member
// @Identifier.member(args)
// @(Expression)
try decorators.ensureUnusedCapacity(1);
decorators.unusedCapacitySlice()[0] = try p.parseStandardDecorator();
decorators.items.len += 1;
} else {
// Parse a new/call expression with "exprFlagTSDecorator" so we ignore
// EIndex expressions, since they may be part of a computed property:
//
// class Foo {
// @foo ['computed']() {}
// }
//
// This matches the behavior of the TypeScript compiler.
try decorators.ensureUnusedCapacity(1);
try p.parseExprWithFlags(.new, Expr.EFlags.ts_decorator, &decorators.unusedCapacitySlice()[0]);
decorators.items.len += 1;
}
// Parse a new/call expression with "exprFlagTSDecorator" so we ignore
// EIndex expressions, since they may be part of a computed property:
//
// class Foo {
// @foo ['computed']() {}
// }
//
// This matches the behavior of the TypeScript compiler.
try decorators.ensureUnusedCapacity(1);
try p.parseExprWithFlags(.new, Expr.EFlags.ts_decorator, &decorators.unusedCapacitySlice()[0]);
decorators.items.len += 1;
}
return decorators.items;
}
/// Parse a standard (TC39) decorator expression following the `@` token.
///
/// DecoratorExpression:
/// @ IdentifierReference
/// @ DecoratorMemberExpression
/// @ DecoratorCallExpression
/// @ DecoratorParenthesizedExpression
pub fn parseStandardDecorator(p: *P) !ExprNodeIndex {
const loc = p.lexer.loc();
// @(Expression) — parenthesized, any expression allowed
if (p.lexer.token == .t_open_paren) {
try p.lexer.next();
const expr = try p.parseExpr(.lowest);
try p.lexer.expect(.t_close_paren);
return expr;
}
// Must start with an identifier
if (p.lexer.token != .t_identifier) {
try p.lexer.expect(.t_identifier);
return error.SyntaxError;
}
var expr = p.newExpr(E.Identifier{ .ref = try p.storeNameInRef(p.lexer.identifier) }, loc);
try p.lexer.next();
// Skip TypeScript type arguments after the identifier (e.g., @foo<T>)
if (is_typescript_enabled) {
_ = try p.skipTypeScriptTypeArguments(false);
}
// DecoratorMemberExpression: Identifier (.Identifier)*
while (p.lexer.token == .t_dot or p.lexer.token == .t_question_dot) {
// Forbid optional chaining in decorators
if (p.lexer.token == .t_question_dot) {
try p.log.addError(p.source, p.lexer.loc(), "Optional chaining is not allowed in decorator expressions");
return error.SyntaxError;
}
try p.lexer.next();
if (!p.lexer.isIdentifierOrKeyword()) {
try p.lexer.expect(.t_identifier);
return error.SyntaxError;
}
const name = p.lexer.identifier;
const name_loc = p.lexer.loc();
try p.lexer.next();
expr = p.newExpr(E.Dot{ .target = expr, .name = name, .name_loc = name_loc }, loc);
// Skip TypeScript type arguments after member access (e.g., @foo.bar<T>)
if (is_typescript_enabled) {
_ = try p.skipTypeScriptTypeArguments(false);
}
}
// DecoratorCallExpression: DecoratorMemberExpression Arguments
// Only a single call is allowed, no chaining after the call
if (p.lexer.token == .t_open_paren) {
const args = try p.parseCallArgs();
expr = p.newExpr(E.Call{
.target = expr,
.args = args.list,
.close_paren_loc = args.loc,
}, loc);
}
return expr;
}
pub fn parseTypeScriptNamespaceStmt(p: *P, loc: logger.Loc, opts: *ParseStatementOptions) anyerror!Stmt {
// "namespace foo {}";
const name_loc = p.lexer.loc();

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