Compare commits

..

1 Commits

Author SHA1 Message Date
Jarred Sumner
915677c946 Fix garbage 2024-04-05 10:56:07 -07:00
759 changed files with 19645 additions and 126257 deletions

View File

@@ -1,3 +0,0 @@
Index:
Background: Skip # Disable slow background indexing of these files.

View File

@@ -1,32 +0,0 @@
name: Prefilled crash report
description: Report a crash in Bun
labels:
- crash
body:
- type: markdown
attributes:
value: |
Thank you so much for submitting a crash report. You're helping us make Bun more reliable for everyone!
- type: textarea
attributes:
label: How can we reproduce the crash?
description: Please provide instructions on how to reproduce the crash.
- type: textarea
id: code
attributes:
label: JavaScript/TypeScript code that reproduces the crash?
description: If this crash happened in the Bun runtime, can you paste code we can run to reproduce the crash?
render: shell
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be
automatically formatted into code, so no need for backticks.
render: shell
- type: textarea
id: remapped_trace
attributes:
label: Stack Trace (bun.report)
validations:
required: true

View File

@@ -30,7 +30,7 @@ runs:
*) os=windows;;
esac
case "$(uname -m)" in
arm64 | aarch64) arch=aarch64;;
arm64 | aarch64) arch=arm64;;
*) arch=x64;;
esac
case "${{ inputs.baseline }}" in

View File

@@ -1,310 +0,0 @@
name: Build Darwin
permissions:
contents: read
actions: write
on:
workflow_call:
inputs:
runs-on:
type: string
default: macos-12-large
tag:
type: string
required: true
arch:
type: string
required: true
cpu:
type: string
required: true
assertions:
type: boolean
canary:
type: boolean
no-cache:
type: boolean
env:
LLVM_VERSION: 16
BUN_VERSION: 1.1.2
jobs:
build-submodules:
name: Build Submodules
runs-on: ${{ inputs.runs-on }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
sparse-checkout: |
.gitmodules
src/deps
scripts
- name: Hash Submodules
id: hash
run: |
print_versions() {
git submodule | grep -v WebKit
echo "LLVM_VERSION=${{ env.LLVM_VERSION }}"
cat $(echo scripts/build*.sh scripts/all-dependencies.sh | tr " " "\n" | sort)
}
echo "hash=$(print_versions | shasum)" >> $GITHUB_OUTPUT
- if: ${{ !inputs.no-cache }}
name: Restore Cache
id: cache
uses: actions/cache/restore@v4
with:
path: ${{ runner.temp }}/bun-deps
key: bun-${{ inputs.tag }}-deps-${{ steps.hash.outputs.hash }}
# TODO: Figure out how to cache homebrew dependencies
- if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
name: Install Dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install \
llvm@${{ env.LLVM_VERSION }} \
ccache \
rust \
pkg-config \
coreutils \
libtool \
cmake \
libiconv \
automake \
openssl@1.1 \
ninja \
golang \
gnu-sed --force --overwrite
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@$LLVM_VERSION
- if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
name: Clone Submodules
run: |
./scripts/update-submodules.sh
- name: Build Submodules
if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
env:
CPU_TARGET: ${{ inputs.cpu }}
BUN_DEPS_OUT_DIR: ${{ runner.temp }}/bun-deps
run: |
mkdir -p $BUN_DEPS_OUT_DIR
./scripts/all-dependencies.sh
- name: Save Cache
if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
uses: actions/cache/save@v4
with:
path: ${{ runner.temp }}/bun-deps
key: ${{ steps.cache.outputs.cache-primary-key }}
- name: Upload bun-${{ inputs.tag }}-deps
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}-deps
path: ${{ runner.temp }}/bun-deps
if-no-files-found: error
build-cpp:
name: Build C++
runs-on: ${{ inputs.runs-on }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
# TODO: Figure out how to cache homebrew dependencies
- name: Install Dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install \
llvm@${{ env.LLVM_VERSION }} \
ccache \
rust \
pkg-config \
coreutils \
libtool \
cmake \
libiconv \
automake \
openssl@1.1 \
ninja \
golang \
gnu-sed --force --overwrite
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@$LLVM_VERSION
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: ${{ env.BUN_VERSION }}
- if: ${{ !inputs.no-cache }}
name: Restore Cache
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/ccache
key: bun-${{ inputs.tag }}-cpp-${{ hashFiles('Dockerfile', 'Makefile', 'CMakeLists.txt', 'build.zig', 'scripts/**', 'src/**', 'packages/bun-usockets/src/**', 'packages/bun-uws/src/**') }}
restore-keys: |
bun-${{ inputs.tag }}-cpp-
- name: Compile
env:
CPU_TARGET: ${{ inputs.cpu }}
SOURCE_DIR: ${{ github.workspace }}
OBJ_DIR: ${{ runner.temp }}/bun-cpp-obj
BUN_DEPS_OUT_DIR: ${{ runner.temp }}/bun-deps
CCACHE_DIR: ${{ runner.temp }}/ccache
run: |
mkdir -p $OBJ_DIR
cd $OBJ_DIR
cmake -S $SOURCE_DIR -B $OBJ_DIR \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_LTO=ON \
-DBUN_CPP_ONLY=1 \
-DNO_CONFIGURE_DEPENDS=1
chmod +x compile-cpp-only.sh
./compile-cpp-only.sh -v
- name: Upload bun-${{ inputs.tag }}-cpp
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}-cpp
path: ${{ runner.temp }}/bun-cpp-obj/bun-cpp-objects.a
if-no-files-found: error
build-zig:
name: Build Zig
uses: ./.github/workflows/build-zig.yml
with:
os: darwin
only-zig: true
tag: ${{ inputs.tag }}
arch: ${{ inputs.arch }}
cpu: ${{ inputs.cpu }}
assertions: ${{ inputs.assertions }}
canary: ${{ inputs.canary }}
no-cache: ${{ inputs.no-cache }}
link:
name: Link
runs-on: ${{ inputs.runs-on }}
needs:
- build-submodules
- build-cpp
- build-zig
steps:
- uses: actions/checkout@v4
# TODO: Figure out how to cache homebrew dependencies
- name: Install Dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install \
llvm@${{ env.LLVM_VERSION }} \
ccache \
rust \
pkg-config \
coreutils \
libtool \
cmake \
libiconv \
automake \
openssl@1.1 \
ninja \
golang \
gnu-sed --force --overwrite
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@$LLVM_VERSION
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Download bun-${{ inputs.tag }}-deps
uses: actions/download-artifact@v4
with:
name: bun-${{ inputs.tag }}-deps
path: ${{ runner.temp }}/bun-deps
- name: Download bun-${{ inputs.tag }}-cpp
uses: actions/download-artifact@v4
with:
name: bun-${{ inputs.tag }}-cpp
path: ${{ runner.temp }}/bun-cpp-obj
- name: Download bun-${{ inputs.tag }}-zig
uses: actions/download-artifact@v4
with:
name: bun-${{ inputs.tag }}-zig
path: ${{ runner.temp }}/release
- if: ${{ !inputs.no-cache }}
name: Restore Cache
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/ccache
key: bun-${{ inputs.tag }}-cpp-${{ hashFiles('Dockerfile', 'Makefile', 'CMakeLists.txt', 'build.zig', 'scripts/**', 'src/**', 'packages/bun-usockets/src/**', 'packages/bun-uws/src/**') }}
restore-keys: |
bun-${{ inputs.tag }}-cpp-
- name: Link
env:
CPU_TARGET: ${{ inputs.cpu }}
CCACHE_DIR: ${{ runner.temp }}/ccache
run: |
SRC_DIR=$PWD
mkdir ${{ runner.temp }}/link-build
cd ${{ runner.temp }}/link-build
cmake $SRC_DIR \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_LTO=ON \
-DBUN_LINK_ONLY=1 \
-DBUN_ZIG_OBJ="${{ runner.temp }}/release/bun-zig.o" \
-DBUN_CPP_ARCHIVE="${{ runner.temp }}/bun-cpp-obj/bun-cpp-objects.a" \
-DBUN_DEPS_OUT_DIR="${{ runner.temp }}/bun-deps" \
-DNO_CONFIGURE_DEPENDS=1
ninja -v
- name: Prepare
run: |
cd ${{ runner.temp }}/link-build
chmod +x bun-profile bun
mkdir -p bun-${{ inputs.tag }}-profile/ bun-${{ inputs.tag }}/
mv bun-profile bun-${{ inputs.tag }}-profile/bun-profile
mv bun bun-${{ inputs.tag }}/bun
zip -r bun-${{ inputs.tag }}-profile.zip bun-${{ inputs.tag }}-profile
zip -r bun-${{ inputs.tag }}.zip bun-${{ inputs.tag }}
- name: Upload bun-${{ inputs.tag }}
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}
path: ${{ runner.temp }}/link-build/bun-${{ inputs.tag }}.zip
if-no-files-found: error
- name: Upload bun-${{ inputs.tag }}-profile
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}-profile
path: ${{ runner.temp }}/link-build/bun-${{ inputs.tag }}-profile.zip
if-no-files-found: error
on-failure:
if: ${{ github.repository_owner == 'oven-sh' && failure() }}
name: On Failure
needs: link
runs-on: ubuntu-latest
steps:
- name: Send Message
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
nodetail: true
color: "#FF0000"
title: ""
description: |
### ❌ [${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }})
@${{ github.actor }}, the build for bun-${{ inputs.tag }} failed.
**[View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**

View File

@@ -1,64 +0,0 @@
name: Build Linux
permissions:
contents: read
actions: write
on:
workflow_call:
inputs:
runs-on:
type: string
required: true
tag:
type: string
required: true
arch:
type: string
required: true
cpu:
type: string
required: true
assertions:
type: boolean
zig-optimize:
type: string
canary:
type: boolean
no-cache:
type: boolean
jobs:
build:
name: Build Linux
uses: ./.github/workflows/build-zig.yml
with:
os: linux
only-zig: false
runs-on: ${{ inputs.runs-on }}
tag: ${{ inputs.tag }}
arch: ${{ inputs.arch }}
cpu: ${{ inputs.cpu }}
assertions: ${{ inputs.assertions }}
zig-optimize: ${{ inputs.zig-optimize }}
canary: ${{ inputs.canary }}
no-cache: ${{ inputs.no-cache }}
on-failure:
if: ${{ github.repository_owner == 'oven-sh' && failure() }}
name: On Failure
needs: build
runs-on: ubuntu-latest
steps:
- name: Send Message
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
nodetail: true
color: "#FF0000"
title: ""
description: |
### ❌ [${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }})
@${{ github.actor }}, the build for bun-${{ inputs.tag }} failed.
**[View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**

View File

@@ -1,337 +0,0 @@
name: Build Windows
permissions:
contents: read
actions: write
on:
workflow_call:
inputs:
runs-on:
type: string
default: windows
tag:
type: string
required: true
arch:
type: string
required: true
cpu:
type: string
required: true
assertions:
type: boolean
canary:
type: boolean
no-cache:
type: boolean
env:
# Must specify exact version of LLVM for Windows
LLVM_VERSION: 16.0.6
BUN_VERSION: 1.1.2
jobs:
build-submodules:
name: Build Submodules
runs-on: ${{ inputs.runs-on }}
steps:
- name: Setup Git
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- name: Checkout
uses: actions/checkout@v4
with:
sparse-checkout: |
.gitmodules
src/deps
scripts
- name: Hash Submodules
id: hash
run: |
$data = "$(& {
git submodule | Where-Object { $_ -notmatch 'WebKit' }
echo "LLVM_VERSION=${{ env.LLVM_VERSION }}"
Get-Content -Path (Get-ChildItem -Path 'scripts/build*.ps1', 'scripts/all-dependencies.ps1', 'scripts/env.ps1' | Sort-Object -Property Name).FullName | Out-String
echo 1
})"
$hash = ( -join ((New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider).ComputeHash([System.Text.Encoding]::UTF8.GetBytes($data)) | ForEach-Object { $_.ToString("x2") } )).Substring(0, 10)
echo "hash=${hash}" >> $env:GITHUB_OUTPUT
- if: ${{ !inputs.no-cache }}
name: Restore Cache
id: cache
uses: actions/cache/restore@v4
with:
path: bun-deps
key: bun-${{ inputs.tag }}-deps-${{ steps.hash.outputs.hash }}
- if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
name: Install LLVM
uses: KyleMayes/install-llvm-action@8b37482c5a2997a3ab5dbf6561f8109e2eaa7d3b
with:
version: ${{ env.LLVM_VERSION }}
- if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
name: Install Ninja
run: |
choco install -y ninja
- if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
name: Clone Submodules
run: |
.\scripts\update-submodules.ps1
- if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
name: Build Dependencies
env:
CPU_TARGET: ${{ inputs.cpu }}
CCACHE_DIR: ccache
run: |
.\scripts\env.ps1 ${{ contains(inputs.tag, '-baseline') && '-Baseline' || '' }}
Invoke-WebRequest -Uri "https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/nasm-2.16.01-win64.zip" -OutFile nasm.zip
Expand-Archive nasm.zip (mkdir -Force "nasm")
$Nasm = (Get-ChildItem "nasm")
$env:Path += ";${Nasm}"
$env:BUN_DEPS_OUT_DIR = (mkdir -Force "./bun-deps")
.\scripts\all-dependencies.ps1
- name: Save Cache
if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
uses: actions/cache/save@v4
with:
path: bun-deps
key: ${{ steps.cache.outputs.cache-primary-key }}
- name: Upload bun-${{ inputs.tag }}-deps
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}-deps
path: bun-deps
if-no-files-found: error
codegen:
name: Codegen
runs-on: ubuntu-latest
steps:
- name: Setup Git
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Codegen
run: |
./scripts/cross-compile-codegen.sh win32 x64
- if: ${{ inputs.canary }}
name: Calculate Revision
run: |
echo "canary_revision=$(GITHUB_TOKEN="${{ github.token }}"
bash ./scripts/calculate-canary-revision.sh --raw)" > build-codegen-win32-x64/.canary_revision
- name: Upload bun-${{ inputs.tag }}-codegen
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}-codegen
path: build-codegen-win32-x64
if-no-files-found: error
build-cpp:
name: Build C++
needs: codegen
runs-on: ${{ inputs.runs-on }}
steps:
- name: Setup Git
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install LLVM
uses: KyleMayes/install-llvm-action@8b37482c5a2997a3ab5dbf6561f8109e2eaa7d3b
with:
version: ${{ env.LLVM_VERSION }}
- name: Install Ninja
run: |
choco install -y ninja
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: ${{ env.BUN_VERSION }}
- if: ${{ !inputs.no-cache }}
name: Restore Cache
uses: actions/cache@v4
with:
path: ccache
key: bun-${{ inputs.tag }}-cpp-${{ hashFiles('Dockerfile', 'Makefile', 'CMakeLists.txt', 'build.zig', 'scripts/**', 'src/**', 'packages/bun-usockets/src/**', 'packages/bun-uws/src/**') }}
restore-keys: |
bun-${{ inputs.tag }}-cpp-
- name: Download bun-${{ inputs.tag }}-codegen
uses: actions/download-artifact@v4
with:
name: bun-${{ inputs.tag }}-codegen
path: build
- name: Compile
env:
CPU_TARGET: ${{ inputs.cpu }}
CCACHE_DIR: ccache
run: |
# $CANARY_REVISION = if (Test-Path build/.canary_revision) { Get-Content build/.canary_revision } else { "0" }
$CANARY_REVISION = 0
.\scripts\env.ps1 ${{ contains(inputs.tag, '-baseline') && '-Baseline' || '' }}
.\scripts\update-submodules.ps1
.\scripts\build-libuv.ps1 -CloneOnly $True
cd build
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release `
-DNO_CODEGEN=1 `
-DNO_CONFIGURE_DEPENDS=1 `
"-DCANARY=${CANARY_REVISION}" `
-DBUN_CPP_ONLY=1 ${{ contains(inputs.tag, '-baseline') && '-DUSE_BASELINE_BUILD=1' || '' }}
if ($LASTEXITCODE -ne 0) { throw "CMake configuration failed" }
.\compile-cpp-only.ps1 -v
if ($LASTEXITCODE -ne 0) { throw "C++ compilation failed" }
- name: Upload bun-${{ inputs.tag }}-cpp
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}-cpp
path: build/bun-cpp-objects.a
if-no-files-found: error
build-zig:
name: Build Zig
uses: ./.github/workflows/build-zig.yml
with:
os: windows
zig-optimize: ReleaseSafe
only-zig: true
tag: ${{ inputs.tag }}
arch: ${{ inputs.arch }}
cpu: ${{ inputs.cpu }}
assertions: ${{ inputs.assertions }}
canary: ${{ inputs.canary }}
no-cache: ${{ inputs.no-cache }}
link:
name: Link
runs-on: ${{ inputs.runs-on }}
needs:
- build-submodules
- build-cpp
- build-zig
- codegen
steps:
- name: Setup Git
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install LLVM
uses: KyleMayes/install-llvm-action@8b37482c5a2997a3ab5dbf6561f8109e2eaa7d3b
with:
version: ${{ env.LLVM_VERSION }}
- name: Install Ninja
run: |
choco install -y ninja
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Download bun-${{ inputs.tag }}-deps
uses: actions/download-artifact@v4
with:
name: bun-${{ inputs.tag }}-deps
path: bun-deps
- name: Download bun-${{ inputs.tag }}-cpp
uses: actions/download-artifact@v4
with:
name: bun-${{ inputs.tag }}-cpp
path: bun-cpp
- name: Download bun-${{ inputs.tag }}-zig
uses: actions/download-artifact@v4
with:
name: bun-${{ inputs.tag }}-zig
path: bun-zig
- name: Download bun-${{ inputs.tag }}-codegen
uses: actions/download-artifact@v4
with:
name: bun-${{ inputs.tag }}-codegen
path: build
- if: ${{ !inputs.no-cache }}
name: Restore Cache
uses: actions/cache@v4
with:
path: ccache
key: bun-${{ inputs.tag }}-cpp-${{ hashFiles('Dockerfile', 'Makefile', 'CMakeLists.txt', 'build.zig', 'scripts/**', 'src/**', 'packages/bun-usockets/src/**', 'packages/bun-uws/src/**') }}
restore-keys: |
bun-${{ inputs.tag }}-cpp-
- name: Link
env:
CPU_TARGET: ${{ inputs.cpu }}
CCACHE_DIR: ccache
run: |
.\scripts\update-submodules.ps1
.\scripts\env.ps1 ${{ contains(inputs.tag, '-baseline') && '-Baseline' || '' }}
Set-Location build
# $CANARY_REVISION = if (Test-Path build/.canary_revision) { Get-Content build/.canary_revision } else { "0" }
$CANARY_REVISION = 0
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release `
-DNO_CODEGEN=1 `
-DNO_CONFIGURE_DEPENDS=1 `
"-DCANARY=${CANARY_REVISION}" `
-DBUN_LINK_ONLY=1 `
"-DBUN_DEPS_OUT_DIR=$(Resolve-Path ../bun-deps)" `
"-DBUN_CPP_ARCHIVE=$(Resolve-Path ../bun-cpp/bun-cpp-objects.a)" `
"-DBUN_ZIG_OBJ=$(Resolve-Path ../bun-zig/bun-zig.o)" `
${{ contains(inputs.tag, '-baseline') && '-DUSE_BASELINE_BUILD=1' || '' }}
if ($LASTEXITCODE -ne 0) { throw "CMake configuration failed" }
ninja -v
if ($LASTEXITCODE -ne 0) { throw "Link failed!" }
- name: Prepare
run: |
$Dist = mkdir -Force "bun-${{ inputs.tag }}"
cp -r build\bun.exe "$Dist\bun.exe"
Compress-Archive -Force "$Dist" "${Dist}.zip"
$Dist = "$Dist-profile"
MkDir -Force "$Dist"
cp -r build\bun.exe "$Dist\bun.exe"
cp -r build\bun.pdb "$Dist\bun.pdb"
Compress-Archive -Force "$Dist" "$Dist.zip"
$env:BUN_GARBAGE_COLLECTOR_LEVEL = "1"
$env:BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING = "1"
.\build\bun.exe --print "JSON.stringify(require('bun:internal-for-testing').crash_handler.getFeatureData())" > .\features.json
- name: Upload bun-${{ inputs.tag }}
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}
path: bun-${{ inputs.tag }}.zip
if-no-files-found: error
- name: Upload bun-${{ inputs.tag }}-profile
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}-profile
path: bun-${{ inputs.tag }}-profile.zip
if-no-files-found: error
- name: Upload bun-feature-data
uses: actions/upload-artifact@v4
with:
name: bun-feature-data
path: features.json
if-no-files-found: error
overwrite: true
on-failure:
if: ${{ github.repository_owner == 'oven-sh' && failure() }}
name: On Failure
needs: link
runs-on: ubuntu-latest
steps:
- name: Send Message
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
nodetail: true
color: "#FF0000"
title: ""
description: |
### ❌ [${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }})
@${{ github.actor }}, the build for bun-${{ inputs.tag }} failed.
**[View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**

View File

@@ -1,122 +0,0 @@
name: Build Zig
permissions:
contents: read
actions: write
on:
workflow_call:
inputs:
runs-on:
type: string
default: ${{ github.repository_owner != 'oven-sh' && 'ubuntu-latest' || inputs.only-zig && 'namespace-profile-bun-ci-linux-x64' || inputs.arch == 'x64' && 'namespace-profile-bun-ci-linux-x64' || 'namespace-profile-bun-ci-linux-aarch64' }}
tag:
type: string
required: true
os:
type: string
required: true
arch:
type: string
required: true
cpu:
type: string
required: true
assertions:
type: boolean
default: false
zig-optimize:
type: string # 'ReleaseSafe' or 'ReleaseFast'
default: ReleaseFast
canary:
type: boolean
default: ${{ github.ref == 'refs/heads/main' }}
only-zig:
type: boolean
default: true
no-cache:
type: boolean
default: false
jobs:
build-zig:
name: ${{ inputs.only-zig && 'Build Zig' || 'Build & Link' }}
runs-on: ${{ inputs.runs-on }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Calculate Cache Key
id: cache
run: |
echo "key=${{ hashFiles('Dockerfile', 'Makefile', 'CMakeLists.txt', 'build.zig', 'scripts/**', 'src/**', 'packages/bun-usockets/src/**', 'packages/bun-uws/src/**') }}" >> $GITHUB_OUTPUT
- if: ${{ !inputs.no-cache }}
name: Restore Cache
uses: actions/cache@v4
with:
key: bun-${{ inputs.tag }}-docker-${{ steps.cache.outputs.key }}
restore-keys: |
bun-${{ inputs.tag }}-docker-
path: |
${{ runner.temp }}/dockercache
- name: Setup Docker
uses: docker/setup-buildx-action@v3
with:
install: true
platforms: |
linux/${{ runner.arch == 'X64' && 'amd64' || 'arm64' }}
- name: Build
uses: docker/build-push-action@v5
with:
push: false
target: ${{ inputs.only-zig && 'build_release_obj' || 'artifact' }}
cache-from: |
type=local,src=${{ runner.temp }}/dockercache
cache-to: |
type=local,dest=${{ runner.temp }}/dockercache,mode=max
outputs: |
type=local,dest=${{ runner.temp }}/release
platforms: |
linux/${{ runner.arch == 'X64' && 'amd64' || 'arm64' }}
build-args: |
GIT_SHA=${{ github.event.workflow_run.head_sha || github.sha }}
TRIPLET=${{ inputs.os == 'darwin' && format('{0}-macos-none', inputs.arch == 'x64' && 'x86_64' || 'aarch64') || inputs.os == 'windows' && format('{0}-windows-msvc', inputs.arch == 'x64' && 'x86_64' || 'aarch64') || format('{0}-linux-gnu', inputs.arch == 'x64' && 'x86_64' || 'aarch64') }}
ARCH=${{ inputs.arch == 'x64' && 'x86_64' || 'aarch64' }}
BUILDARCH=${{ inputs.arch == 'x64' && 'amd64' || 'arm64' }}
BUILD_MACHINE_ARCH=${{ inputs.arch == 'x64' && 'x86_64' || 'aarch64' }}
CPU_TARGET=${{ inputs.arch == 'x64' && inputs.cpu || 'native' }}
ASSERTIONS=${{ inputs.assertions && 'ON' || 'OFF' }}
ZIG_OPTIMIZE=${{ inputs.zig-optimize }}
CANARY=${{ inputs.canary && '1' || '0' }}
- if: ${{ inputs.only-zig }}
name: Upload bun-${{ inputs.tag }}-zig
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}-zig
path: ${{ runner.temp }}/release/bun-zig.o
if-no-files-found: error
- if: ${{ !inputs.only-zig }}
name: Prepare
run: |
cd ${{ runner.temp }}/release
chmod +x bun-profile bun
mkdir bun-${{ inputs.tag }}-profile
mkdir bun-${{ inputs.tag }}
strip bun
mv bun-profile bun-${{ inputs.tag }}-profile/bun-profile
mv bun bun-${{ inputs.tag }}/bun
zip -r bun-${{ inputs.tag }}-profile.zip bun-${{ inputs.tag }}-profile
zip -r bun-${{ inputs.tag }}.zip bun-${{ inputs.tag }}
- if: ${{ !inputs.only-zig }}
name: Upload bun-${{ inputs.tag }}
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}
path: ${{ runner.temp }}/release/bun-${{ inputs.tag }}.zip
if-no-files-found: error
- if: ${{ !inputs.only-zig }}
name: Upload bun-${{ inputs.tag }}-profile
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}-profile
path: ${{ runner.temp }}/release/bun-${{ inputs.tag }}-profile.zip
if-no-files-found: error

18
.github/workflows/bun-deploy-site.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
# redeploy Vercel site when a file in `docs` changes
# using VERCEL_DEPLOY_HOOK environment variable
name: Deploy site
on:
push:
paths:
- "docs/**"
branches: [main]
jobs:
deploy:
name: Deploy site
runs-on: ubuntu-latest
if: github.repository_owner == 'oven-sh'
steps:
- name: Trigger Vercel build
run: curl ${{ secrets.VERCEL_DEPLOY_HOOK }}

142
.github/workflows/bun-linux-aarch64.yml vendored Normal file
View File

@@ -0,0 +1,142 @@
name: bun-linux
concurrency:
group: bun-linux-aarch64-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches:
- main
paths:
- ".github/workflows/bun-linux-aarch64.yml"
- "src/**/*"
- "test/**/*"
- "packages/bun-usockets/src/**/*"
- "packages/bun-uws/src/**/*"
- "CMakeLists.txt"
- "build.zig"
- "Makefile"
- "Dockerfile"
pull_request:
branches:
- main
paths:
- ".github/workflows/bun-linux-aarch64.yml"
- "src/**/*"
- "test/**/*"
- "packages/bun-usockets/src/**/*"
- "packages/bun-uws/src/**/*"
- "CMakeLists.txt"
- "build.zig"
- "Makefile"
- "Dockerfile"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
linux:
name: ${{matrix.tag}}
runs-on: ${{matrix.runner}}
if: github.repository_owner == 'oven-sh'
timeout-minutes: 90
permissions: write-all
strategy:
matrix:
include:
- cpu: native
tag: linux-aarch64
arch: aarch64
build_arch: arm64
runner: linux-arm64
build_machine_arch: aarch64
steps:
- uses: actions/checkout@v4
with:
submodules: false
ref: ${{github.sha}}
clean: true
- run: |
bash ./scripts/update-submodules.sh
- uses: docker/setup-buildx-action@v3
id: buildx
with:
install: true
- name: Run
run: |
rm -rf ${{runner.temp}}/release
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- run: |
mkdir -p /tmp/.buildx-cache-${{matrix.tag}}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: false
cache-from: type=local,src=/tmp/.buildx-cache-${{matrix.tag}}
cache-to: type=local,dest=/tmp/.buildx-cache-${{matrix.tag}}
build-args: |
ARCH=${{matrix.arch}}
BUILDARCH=${{matrix.build_arch}}
BUILD_MACHINE_ARCH=${{matrix.build_machine_arch}}
CPU_TARGET=${{matrix.cpu}}
GIT_SHA=${{github.sha}}
platforms: linux/${{matrix.build_arch}}
target: artifact
outputs: type=local,dest=${{runner.temp}}/release
- name: Zip
run: |
# if zip is not found
if [ ! -x "$(command -v zip)" ]; then
sudo apt-get update && sudo apt-get install -y zip --no-install-recommends
fi
if [ ! -x "$(command -v strip)" ]; then
sudo apt-get update && sudo apt-get install -y binutils --no-install-recommends
fi
cd ${{runner.temp}}/release
chmod +x bun-profile bun
mkdir bun-${{matrix.tag}}-profile
mkdir bun-${{matrix.tag}}
strip bun
mv bun-profile bun-${{matrix.tag}}-profile/bun-profile
mv bun bun-${{matrix.tag}}/bun
zip -r bun-${{matrix.tag}}-profile.zip bun-${{matrix.tag}}-profile
zip -r bun-${{matrix.tag}}.zip bun-${{matrix.tag}}
- uses: actions/upload-artifact@v4
with:
name: bun-${{matrix.tag}}-profile
path: ${{runner.temp}}/release/bun-${{matrix.tag}}-profile.zip
if-no-files-found: "error"
- uses: actions/upload-artifact@v4
with:
name: bun-${{matrix.tag}}
path: ${{runner.temp}}/release/bun-${{matrix.tag}}.zip
if-no-files-found: "error"
- name: Release
id: release
uses: ncipollo/release-action@v1
if: |
github.repository_owner == 'oven-sh'
&& github.ref == 'refs/heads/main'
with:
prerelease: true
body: "This canary release of Bun corresponds to the commit [${{ github.sha }}]"
allowUpdates: true
replacesArtifacts: true
generateReleaseNotes: true
artifactErrorsFailBuild: true
token: ${{ secrets.GITHUB_TOKEN }}
name: "Canary (${{github.sha}})"
tag: "canary"
artifacts: "${{runner.temp}}/release/bun-${{matrix.tag}}.zip,${{runner.temp}}/release/bun-${{matrix.tag}}-profile.zip"

319
.github/workflows/bun-linux-build.yml vendored Normal file
View File

@@ -0,0 +1,319 @@
name: bun-linux
concurrency:
group: bun-linux-build-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches:
- main
paths:
- ".github/workflows/bun-linux-build.yml"
- "src/**/*"
- "test/**/*"
- "packages/bun-usockets/src/**/*"
- "packages/bun-uws/src/**/*"
- "CMakeLists.txt"
- "build.zig"
- "Makefile"
- "Dockerfile"
pull_request:
branches:
- main
paths:
- ".github/workflows/bun-linux-build.yml"
- "src/**/*"
- "test/**/*"
- "packages/bun-usockets/src/**/*"
- "packages/bun-uws/src/**/*"
- "CMakeLists.txt"
- "build.zig"
- "Makefile"
- "Dockerfile"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
linux:
name: ${{matrix.tag}}
runs-on: ${{matrix.runner}}
if: github.repository_owner == 'oven-sh'
timeout-minutes: 90
permissions: write-all
strategy:
fail-fast: false
matrix:
include:
- cpu: haswell
tag: linux-x64
arch: x86_64
build_arch: amd64
runner: namespace-profile-bun-linux-x64
build_machine_arch: x86_64
assertions: "OFF"
zig_optimize: "ReleaseFast"
target: "artifact"
- cpu: nehalem
tag: linux-x64-baseline
arch: x86_64
build_arch: amd64
runner: namespace-profile-bun-linux-x64
build_machine_arch: x86_64
assertions: "OFF"
zig_optimize: "ReleaseFast"
target: "artifact"
# - cpu: haswell
# tag: linux-x64-assertions
# arch: x86_64
# build_arch: amd64
# runner: big-ubuntu
# build_machine_arch: x86_64
# assertions: "ON"
# zig_optimize: "ReleaseSafe"
# target: "artifact-assertions"
# - cpu: nehalem
# tag: linux-x64-baseline-assertions
# arch: x86_64
# build_arch: amd64
# runner: big-ubuntu
# build_machine_arch: x86_64
# assertions: "ON"
# zig_optimize: "ReleaseSafe"
# target: "artifact-assertions"
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
ref: ${{github.sha}}
clean: true
- name: Run
run: |
rm -rf ${{runner.temp}}/release
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: false
build-args: |
ARCH=${{matrix.arch}}
BUILDARCH=${{matrix.build_arch}}
BUILD_MACHINE_ARCH=${{matrix.build_machine_arch}}
CPU_TARGET=${{matrix.cpu}}
GIT_SHA=${{github.sha}}
ASSERTIONS=${{matrix.assertions}}
ZIG_OPTIMIZE=${{matrix.zig_optimize}}
platforms: linux/${{matrix.build_arch}}
target: ${{matrix.target}}
outputs: type=local,dest=${{runner.temp}}/release
- id: bun-version-check
name: Bun version check
run: |
# If this hangs, it means something is seriously wrong with the build
${{runner.temp}}/release/bun-profile --version
- name: Zip
run: |
# if zip is not found
if [ ! -x "$(command -v zip)" ]; then
sudo apt-get update && sudo apt-get install -y zip --no-install-recommends
fi
if [ ! -x "$(command -v strip)" ]; then
sudo apt-get update && sudo apt-get install -y binutils --no-install-recommends
fi
cd ${{runner.temp}}/release
chmod +x bun-profile bun
mkdir bun-${{matrix.tag}}-profile
mkdir bun-${{matrix.tag}}
strip bun
mv bun-profile bun-${{matrix.tag}}-profile/bun-profile
mv bun bun-${{matrix.tag}}/bun
zip -r bun-${{matrix.tag}}-profile.zip bun-${{matrix.tag}}-profile
zip -r bun-${{matrix.tag}}.zip bun-${{matrix.tag}}
- uses: actions/upload-artifact@v4
with:
name: bun-${{matrix.tag}}-profile
path: ${{runner.temp}}/release/bun-${{matrix.tag}}-profile.zip
if-no-files-found: "error"
- uses: actions/upload-artifact@v4
with:
name: bun-${{matrix.tag}}
path: ${{runner.temp}}/release/bun-${{matrix.tag}}.zip
if-no-files-found: "error"
- name: Release
id: release
uses: ncipollo/release-action@v1
if: |
github.repository_owner == 'oven-sh'
&& github.ref == 'refs/heads/main'
with:
prerelease: true
body: "This canary release of Bun corresponds to the commit [${{ github.sha }}]"
allowUpdates: true
replacesArtifacts: true
generateReleaseNotes: true
artifactErrorsFailBuild: true
token: ${{ secrets.GITHUB_TOKEN }}
name: "Canary (${{github.sha}})"
tag: "canary"
artifacts: "${{runner.temp}}/release/bun-${{matrix.tag}}.zip,${{runner.temp}}/release/bun-${{matrix.tag}}-profile.zip"
- uses: sarisia/actions-status-discord@v1
if: failure() && github.repository_owner == 'oven-sh' && github.event_name == 'pull_request'
with:
title: ""
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }}
noprefix: true
nocontext: true
description: |
Pull Request
### [${{github.event.pull_request.title}}](https://github.com/oven-sh/bun/pull/${{github.event.number}})
@${{ github.actor }}
Build failed on ${{ matrix.tag }}:
**[View build output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
[Commit ${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})
linux-test:
name: Tests ${{matrix.tag}}
runs-on: namespace-profile-bun-linux-x64
needs: [linux]
if: github.event_name == 'pull_request'
timeout-minutes: 20
permissions:
pull-requests: write
outputs:
failing_tests: ${{ steps.test.outputs.failing_tests }}
failing_tests_count: ${{ steps.test.outputs.failing_tests_count }}
strategy:
fail-fast: false
matrix:
include:
- tag: linux-x64
- tag: linux-x64-baseline
# - tag: linux-x64-assertions
# - tag: linux-x64-baseline-assertions
steps:
- id: checkout
name: Checkout
uses: actions/checkout@v4
with:
submodules: false
clean: true
- id: download
name: Download
uses: actions/download-artifact@v4
with:
name: bun-${{matrix.tag}}
path: ${{runner.temp}}/release
- id: install-bun
name: Install Bun
run: |
cd ${{runner.temp}}/release
unzip bun-${{matrix.tag}}.zip
cd bun-${{matrix.tag}}
chmod +x bun
pwd >> $GITHUB_PATH
- id: bun-version-check
name: Bun version check
run: |
# If this hangs, it means something is seriously wrong with the build
bun --version
# Split these into multiple steps to make it clear which one fails
- name: Install dependencies (apt-get)
run: sudo apt-get update && sudo apt-get install -y openssl
- name: Install dependencies (root)
run: bun install --verbose
- name: Install dependencies (test)
run: bun install --cwd=test --verbose
- name: Install dependencies (runner)
run: bun install --cwd=packages/bun-internal-test --verbose
- name: Install dependencies (prisma)
run: bun install --cwd=test/js/third_party/prisma --verbose
# This is disabled because the cores are ~5.5gb each
# so it is easy to hit 50gb coredump downloads. Only enable if you need to retrive one
# - name: Set core dumps to get stored in /cores
# run: |
# sudo mkdir /cores
# sudo chmod 777 /cores
# # Core filenames will be of the form executable.pid.timestamp:
# sudo bash -c 'echo "/cores/%e.%p.%t" > /proc/sys/kernel/core_pattern'
- id: test
name: Test (node runner)
env:
SMTP_SENDGRID_SENDER: ${{ secrets.SMTP_SENDGRID_SENDER }}
TMPDIR: ${{runner.temp}}
TLS_MONGODB_DATABASE_URL: ${{ secrets.TLS_MONGODB_DATABASE_URL }}
TLS_POSTGRES_DATABASE_URL: ${{ secrets.TLS_POSTGRES_DATABASE_URL }}
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "true"
# if: ${{github.event.inputs.use_bun == 'false'}}
run: |
node packages/bun-internal-test/src/runner.node.mjs || true
# - uses: actions/upload-artifact@v4
# if: steps.test.outputs.failing_tests != ''
# with:
# name: cores
# path: /cores
# if-no-files-found: "error"
- uses: sarisia/actions-status-discord@v1
if: always() && steps.test.outputs.failing_tests != '' && github.event_name == 'pull_request'
with:
title: ""
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: "failure"
noprefix: true
nocontext: true
description: |
Pull Request
### ❌ [${{github.event.pull_request.title}}](https://github.com/oven-sh/bun/pull/${{github.event.number}})
@${{ github.actor }}, there are ${{ steps.test.outputs.failing_tests_count }} files with test failures on ${{ matrix.tag }}:
${{ steps.test.outputs.failing_tests }}
**[View test output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
- name: Comment on PR
if: steps.test.outputs.failing_tests != '' && github.event_name == 'pull_request'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: test-failures-${{matrix.tag}}
message: |
❌ @${{ github.actor }} ${{ steps.test.outputs.failing_tests_count }} files with test failures on ${{ matrix.tag }}:
${{ steps.test.outputs.failing_tests }}
**[View test output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
<sup>[#${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})</sup>
- name: Uncomment on PR
if: steps.test.outputs.failing_tests == '' && github.event_name == 'pull_request'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: test-failures-${{matrix.tag}}
mode: upsert
create_if_not_exists: false
message: |
✅ test failures on ${{ matrix.tag }} have been resolved.
<sup>[#${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})</sup>
- id: fail
name: Fail the build
if: steps.test.outputs.failing_tests != ''
run: exit 1

481
.github/workflows/bun-mac-aarch64.yml vendored Normal file
View File

@@ -0,0 +1,481 @@
name: bun-macOS-aarch64
concurrency:
group: bun-macOS-aarch64-${{ github.ref }}
cancel-in-progress: true
env:
LLVM_VERSION: 16
BUN_DOWNLOAD_URL_BASE: https://pub-5e11e972747a44bf9aaf9394f185a982.r2.dev/releases/latest
on:
push:
branches: [main]
paths:
- "src/**/*"
- "test/**/*"
- "packages/bun-usockets/src/**/*"
- "packages/bun-uws/src/**/*"
- "CMakeLists.txt"
- "build.zig"
- "Makefile"
- "Dockerfile"
pull_request:
branches: [main]
paths:
- "src/**/*"
- "test/**/*"
- "packages/bun-usockets/src/**/*"
- "packages/bun-uws/src/**/*"
- "CMakeLists.txt"
- "build.zig"
- "Makefile"
- "Dockerfile"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
macOS-zig:
name: macOS Zig Object
runs-on: namespace-profile-zig-build
if: github.repository_owner == 'oven-sh'
strategy:
matrix:
include:
- cpu: native
arch: aarch64
tag: bun-obj-darwin-aarch64
steps:
- uses: actions/checkout@v4
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Compile Zig Object
uses: docker/build-push-action@v5
with:
context: .
push: false
# This doesnt seem to work
# cache-from: type=s3,endpoint_url=${{ secrets.CACHE_S3_ENDPOINT }},blobs_prefix=docker_blobs/,manifests_prefix=docker_manifests/,access_key_id=${{ secrets.CACHE_S3_ACCESS_KEY_ID }},secret_access_key=${{ secrets.CACHE_S3_SECRET_ACCESS_KEY }},bucket=bun,region=auto
# cache-to: type=s3,endpoint_url=${{ secrets.CACHE_S3_ENDPOINT }},blobs_prefix=docker_blobs/,manifests_prefix=docker_manifests/,access_key_id=${{ secrets.CACHE_S3_ACCESS_KEY_ID }},secret_access_key=${{ secrets.CACHE_S3_SECRET_ACCESS_KEY }},bucket=bun,region=auto
build-args: |
BUILDARCH=${{ runner.arch == 'X64' && 'amd64' || 'arm64' }}
BUILD_MACHINE_ARCH=${{ runner.arch == 'X64' && 'x86_64' || 'aarch64' }}
ARCH=${{ matrix.arch }}
CPU_TARGET=${{ matrix.cpu }}
TRIPLET=${{ matrix.arch }}-macos-none
GIT_SHA=${{ github.sha }}
platforms: linux/${{ runner.arch == 'X64' && 'amd64' || 'arm64' }}
target: build_release_obj
outputs: type=local,dest=${{runner.temp}}/release
- name: Upload Zig Object
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.tag }}
path: ${{runner.temp}}/release/bun-zig.o
if-no-files-found: "error"
macOS-dependencies:
name: macOS Dependencies
runs-on: ${{ matrix.runner }}
if: github.repository_owner == 'oven-sh'
timeout-minutes: 15
strategy:
matrix:
include:
- cpu: native
arch: aarch64
tag: bun-darwin-aarch64
obj: bun-obj-darwin-aarch64
artifact: bun-obj-darwin-aarch64
runner: macos-13-xlarge
steps:
- uses: actions/checkout@v4
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Install system dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install go sccache ccache rust llvm@$LLVM_VERSION pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config --force
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
# echo "$(brew --prefix sccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@$LLVM_VERSION
curl -LO "$BUN_DOWNLOAD_URL_BASE/bun-darwin-aarch64.zip"
unzip bun-darwin-aarch64.zip
mkdir -p ${{ runner.temp }}/.bun/bin
mv bun-darwin-aarch64/bun ${{ runner.temp }}/.bun/bin/bun
chmod +x ${{ runner.temp }}/.bun/bin/bun
echo "${{ runner.temp }}/.bun/bin" >> $GITHUB_PATH
- name: Hash submodule versions
run: |
print_data() {
git submodule | grep -v WebKit
llvm-config --version
rustc --version
cat $(echo scripts/build*.sh scripts/all-dependencies.sh | tr " " "\n" | sort)
}
echo "sha=$(print_data | sha1sum | cut -c 1-10)" >> $GITHUB_OUTPUT
id: submodule-versions
- name: Cache submodule dependencies
id: cache-deps-restore
uses: actions/cache/restore@v4
with:
path: ${{runner.temp}}/bun-deps
key: bun-deps-${{ matrix.tag }}-${{ steps.submodule-versions.outputs.sha }}
- name: Compile submodule dependencies
if: ${{ !steps.cache-deps-restore.outputs.cache-hit }}
env:
CPU_TARGET: ${{ matrix.cpu }}
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
run: |
mkdir -p $BUN_DEPS_OUT_DIR
bash ./scripts/clean-dependencies.sh
bash ./scripts/all-dependencies.sh
- name: Cache submodule dependencies
if: ${{ !steps.cache-deps-restore.outputs.cache-hit }}
id: cache-deps-save
uses: actions/cache/save@v4
with:
path: ${{runner.temp}}/bun-deps
key: ${{ steps.cache-deps-restore.outputs.cache-primary-key }}
- name: Upload submodule dependencies
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.tag }}-deps
path: ${{runner.temp}}/bun-deps
if-no-files-found: "error"
macOS-cpp:
name: macOS C++
runs-on: ${{ matrix.runner }}
if: github.repository_owner == 'oven-sh'
timeout-minutes: 90
strategy:
matrix:
include:
- cpu: native
arch: aarch64
tag: bun-darwin-aarch64
obj: bun-obj-darwin-aarch64
artifact: bun-obj-darwin-aarch64
runner: macos-13-xlarge
steps:
- uses: actions/checkout@v4
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Install system dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install go sccache ccache rust llvm@$LLVM_VERSION pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config --force
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
# echo "$(brew --prefix sccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@$LLVM_VERSION
curl -LO "$BUN_DOWNLOAD_URL_BASE/bun-darwin-aarch64.zip"
unzip bun-darwin-aarch64.zip
mkdir -p ${{ runner.temp }}/.bun/bin
mv bun-darwin-aarch64/bun ${{ runner.temp }}/.bun/bin/bun
chmod +x ${{ runner.temp }}/.bun/bin/bun
echo "${{ runner.temp }}/.bun/bin" >> $GITHUB_PATH
# TODO: replace with sccache
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-ccache-${{ matrix.tag }}
restore-keys: ${{ runner.os }}-ccache-${{ matrix.tag }}
- name: Compile C++
env:
CPU_TARGET: ${{ matrix.cpu }}
SOURCE_DIR: ${{ github.workspace }}
OBJ_DIR: ${{ runner.temp }}/bun-cpp-obj
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
run: |
mkdir -p $OBJ_DIR
cd $OBJ_DIR
cmake -S $SOURCE_DIR -B $OBJ_DIR \
-G Ninja \
-DUSE_LTO=ON \
-DCMAKE_BUILD_TYPE=Release \
-DBUN_CPP_ONLY=1 \
-DNO_CONFIGURE_DEPENDS=1
bash compile-cpp-only.sh -v
- name: Upload C++
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.tag }}-cpp
path: ${{ runner.temp }}/bun-cpp-obj/bun-cpp-objects.a
if-no-files-found: "error"
macOS-link:
name: macOS Link
runs-on: ${{ matrix.runner }}
if: github.repository_owner == 'oven-sh'
needs: [macOS-zig, macOS-cpp, macOS-dependencies]
timeout-minutes: 60
permissions: write-all
strategy:
matrix:
include:
- cpu: native
arch: aarch64
tag: bun-darwin-aarch64
obj: bun-obj-darwin-aarch64
package: bun-darwin-aarch64
artifact: bun-obj-darwin-aarch64
runner: macos-13-xlarge
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
ref: ${{github.sha}}
clean: true
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Install system dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install ccache llvm@$LLVM_VERSION pkg-config coreutils libtool cmake libiconv openssl@1.1 ninja --force
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@$LLVM_VERSION
curl -LO "$BUN_DOWNLOAD_URL_BASE/bun-darwin-${{matrix.arch}}.zip"
unzip bun-darwin-${{matrix.arch}}.zip
mkdir -p ${{ runner.temp }}/.bun/bin
mv bun-darwin-${{matrix.arch}}/bun ${{ runner.temp }}/.bun/bin/bun
chmod +x ${{ runner.temp }}/.bun/bin/bun
echo "${{ runner.temp }}/.bun/bin" >> $GITHUB_PATH
- name: Download C++
uses: actions/download-artifact@v4
with:
name: ${{ matrix.tag }}-cpp
path: ${{ runner.temp }}/bun-cpp-obj
- name: Download Zig Object
uses: actions/download-artifact@v4
with:
name: ${{ matrix.obj }}
path: ${{ runner.temp }}/release
- name: Downloaded submodule dependencies
uses: actions/download-artifact@v4
with:
name: ${{ matrix.tag }}-deps
path: ${{runner.temp}}/bun-deps
- name: Link
env:
CPU_TARGET: ${{ matrix.cpu }}
run: |
SRC_DIR=$PWD
mkdir ${{runner.temp}}/link-build
cd ${{runner.temp}}/link-build
cmake $SRC_DIR \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_LTO=ON \
-DBUN_LINK_ONLY=1 \
-DBUN_ZIG_OBJ="${{ runner.temp }}/release/bun-zig.o" \
-DBUN_CPP_ARCHIVE="${{ runner.temp }}/bun-cpp-obj/bun-cpp-objects.a" \
-DBUN_DEPS_OUT_DIR="${{runner.temp}}/bun-deps" \
-DNO_CONFIGURE_DEPENDS=1
ninja -v
- name: Zip
run: |
cd ${{runner.temp}}/link-build
chmod +x bun-profile bun
mkdir -p ${{matrix.tag}}-profile/ ${{matrix.tag}}/
mv bun-profile ${{matrix.tag}}-profile/bun-profile
mv bun ${{matrix.tag}}/bun
zip -r ${{matrix.tag}}-profile.zip ${{matrix.tag}}-profile
zip -r ${{matrix.tag}}.zip ${{matrix.tag}}
- uses: actions/upload-artifact@v4
with:
name: ${{matrix.tag}}-profile
path: ${{runner.temp}}/link-build/${{matrix.tag}}-profile.zip
if-no-files-found: "error"
- uses: actions/upload-artifact@v4
with:
name: ${{matrix.tag}}
path: ${{runner.temp}}/link-build/${{matrix.tag}}.zip
if-no-files-found: "error"
- name: Release
id: release
uses: ncipollo/release-action@v1
if: |
github.repository_owner == 'oven-sh'
&& github.ref == 'refs/heads/main'
with:
prerelease: true
body: "This canary release of Bun corresponds to the commit [${{ github.sha }}]"
allowUpdates: true
replacesArtifacts: true
generateReleaseNotes: true
artifactErrorsFailBuild: true
token: ${{ secrets.GITHUB_TOKEN }}
name: "Canary (${{github.sha}})"
tag: "canary"
artifacts: "${{runner.temp}}/link-build/${{matrix.tag}}.zip,${{runner.temp}}/link-build/${{matrix.tag}}-profile.zip"
- uses: sarisia/actions-status-discord@v1
if: failure() && github.repository_owner == 'oven-sh' && github.event_name == 'pull_request'
with:
title: ""
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }}
noprefix: true
nocontext: true
description: |
Pull Request
### [${{github.event.pull_request.title}}](https://github.com/oven-sh/bun/pull/${{github.event.number}})
@${{ github.actor }}
Build failed on ${{ matrix.tag }}:
**[View build output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
[Commit ${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})
macOS-test:
name: Tests ${{matrix.tag}}
runs-on: ${{ matrix.runner }}
needs: [macOS-link]
if: github.event_name == 'pull_request' && github.repository_owner == 'oven-sh'
permissions:
pull-requests: write
timeout-minutes: 30
outputs:
failing_tests: ${{ steps.test.outputs.failing_tests }}
failing_tests_count: ${{ steps.test.outputs.failing_tests_count }}
strategy:
fail-fast: false
matrix:
include:
- tag: bun-darwin-aarch64
runner: macos-13-xlarge
steps:
- id: checkout
name: Checkout
uses: actions/checkout@v4
with:
submodules: false
- id: download
name: Download
uses: actions/download-artifact@v4
with:
name: ${{matrix.tag}}
path: ${{runner.temp}}/release
- id: install-bun
name: Install Bun
run: |
cd ${{runner.temp}}/release
unzip ${{matrix.tag}}.zip
cd ${{matrix.tag}}
chmod +x bun
pwd >> $GITHUB_PATH
- id: bun-version-check
name: Bun version check
run: |
# If this hangs, it means something is seriously wrong with the build
bun --version
# Split these into multiple steps to make it clear which one fails
- name: "Install dependencies (root)"
run: bun install --verbose
- name: "Install dependencies (test)"
run: bun install --cwd=test --verbose
- name: "Install dependencies (runner)"
run: bun install --cwd=packages/bun-internal-test --verbose
- id: test
name: Test (node runner)
env:
SMTP_SENDGRID_SENDER: ${{ secrets.SMTP_SENDGRID_SENDER }}
TMPDIR: ${{runner.temp}}
TLS_MONGODB_DATABASE_URL: ${{ secrets.TLS_MONGODB_DATABASE_URL }}
TLS_POSTGRES_DATABASE_URL: ${{ secrets.TLS_POSTGRES_DATABASE_URL }}
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "true"
# if: ${{github.event.inputs.use_bun == 'false'}}
run: |
node packages/bun-internal-test/src/runner.node.mjs || true
- uses: sarisia/actions-status-discord@v1
if: always() && steps.test.outputs.failing_tests != '' && github.event_name == 'pull_request'
with:
title: ""
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: "failure"
noprefix: true
nocontext: true
description: |
Pull Request
### ❌ [${{github.event.pull_request.title}}](https://github.com/oven-sh/bun/pull/${{github.event.number}})
@${{ github.actor }}, there are ${{ steps.test.outputs.failing_tests_count }} files with test failures on ${{ matrix.tag }}:
${{ steps.test.outputs.failing_tests }}
**[View test output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
- name: Comment on PR
if: steps.test.outputs.failing_tests != '' && github.event_name == 'pull_request'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: test-failures-${{matrix.tag}}
message: |
❌ @${{ github.actor }} ${{ steps.test.outputs.failing_tests_count }} files with test failures on ${{ matrix.tag }}:
${{ steps.test.outputs.failing_tests }}
**[View test output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
<sup>[#${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})</sup>
- name: Uncomment on PR
if: steps.test.outputs.failing_tests == '' && github.event_name == 'pull_request'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: test-failures-${{matrix.tag}}
mode: upsert
create_if_not_exists: false
message: |
✅ test failures on ${{ matrix.tag }} have been resolved.
<sup>[#${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})</sup>
- id: fail
name: Fail the build
if: steps.test.outputs.failing_tests != ''
run: exit 1

View File

@@ -0,0 +1,472 @@
name: bun-macOS-x64-baseline
concurrency:
group: bun-macOS-x64-baseline-${{ github.ref }}
cancel-in-progress: true
env:
LLVM_VERSION: 16
BUN_DOWNLOAD_URL_BASE: https://pub-5e11e972747a44bf9aaf9394f185a982.r2.dev/releases/latest
on:
push:
branches: [main]
paths:
- "src/**/*"
- "test/**/*"
- "packages/bun-usockets/src/**/*"
- "packages/bun-uws/src/**/*"
- "CMakeLists.txt"
- "build.zig"
- "Makefile"
- "Dockerfile"
pull_request:
branches: [main]
paths:
- "src/**/*"
- "test/**/*"
- "packages/bun-usockets/src/**/*"
- "packages/bun-uws/src/**/*"
- "CMakeLists.txt"
- "build.zig"
- "Makefile"
- "Dockerfile"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
macos-object-files:
name: macOS Object
runs-on: namespace-profile-zig-build
if: github.repository_owner == 'oven-sh'
strategy:
matrix:
include:
- cpu: nehalem
arch: x86_64
tag: bun-obj-darwin-x64-baseline
# - cpu: haswell
# arch: x86_64
# tag: bun-obj-darwin-x64
# - cpu: native
# arch: aarch64
# tag: bun-obj-darwin-aarch64
steps:
- uses: actions/checkout@v4
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Compile Zig Object
uses: docker/build-push-action@v5
with:
context: .
push: false
build-args: |
BUILDARCH=${{ runner.arch == 'X64' && 'amd64' || 'arm64' }}
BUILD_MACHINE_ARCH=${{ runner.arch == 'X64' && 'x86_64' || 'aarch64' }}
ARCH=${{ matrix.arch }}
CPU_TARGET=${{ matrix.cpu }}
TRIPLET=${{ matrix.arch }}-macos-none
GIT_SHA=${{ github.sha }}
platforms: linux/${{ runner.arch == 'X64' && 'amd64' || 'arm64' }}
target: build_release_obj
outputs: type=local,dest=${{runner.temp}}/release
- name: Upload Zig Object
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.tag }}
path: ${{runner.temp}}/release/bun-zig.o
if-no-files-found: "error"
macOS-dependencies:
name: macOS Dependencies
runs-on: ${{ matrix.runner }}
if: github.repository_owner == 'oven-sh'
timeout-minutes: 15
strategy:
matrix:
include:
- cpu: nehalem
arch: x86_64
tag: bun-darwin-x64-baseline
obj: bun-obj-darwin-x64-baseline
runner: macos-12-large
artifact: bun-obj-darwin-x64-baseline
steps:
- uses: actions/checkout@v4
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Install system dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install sccache ccache rust llvm@$LLVM_VERSION pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config --force
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
# echo "$(brew --prefix sccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@$LLVM_VERSION
- name: Hash submodule versions
run: |
print_data() {
git submodule | grep -v WebKit
llvm-config --version
rustc --version
cat $(echo scripts/build*.sh scripts/all-dependencies.sh | tr " " "\n" | sort)
}
echo "sha=$(print_data | sha1sum | cut -c 1-10)" >> $GITHUB_OUTPUT
id: submodule-versions
- name: Cache submodule dependencies
id: cache-deps-restore
uses: actions/cache/restore@v4
with:
path: ${{runner.temp}}/bun-deps
key: bun-deps-${{ matrix.tag }}-${{ steps.submodule-versions.outputs.sha }}
- name: Compile submodule dependencies
if: ${{ !steps.cache-deps-restore.outputs.cache-hit }}
env:
CPU_TARGET: ${{ matrix.cpu }}
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
run: |
mkdir -p $BUN_DEPS_OUT_DIR
bash ./scripts/clean-dependencies.sh
bash ./scripts/all-dependencies.sh
- name: Cache submodule dependencies
if: ${{ !steps.cache-deps-restore.outputs.cache-hit }}
id: cache-deps-save
uses: actions/cache/save@v4
with:
path: ${{runner.temp}}/bun-deps
key: ${{ steps.cache-deps-restore.outputs.cache-primary-key }}
- name: Upload submodule dependencies
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.tag }}-deps
path: ${{runner.temp}}/bun-deps
if-no-files-found: "error"
macOS-cpp:
name: macOS C++
runs-on: ${{ matrix.runner }}
if: github.repository_owner == 'oven-sh'
timeout-minutes: 90
strategy:
matrix:
include:
- cpu: nehalem
arch: x86_64
tag: bun-darwin-x64-baseline
obj: bun-obj-darwin-x64-baseline
runner: macos-12-large
artifact: bun-obj-darwin-x64-baseline
steps:
- uses: actions/checkout@v4
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Install system dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install sccache ccache rust llvm@$LLVM_VERSION pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config --force
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
# echo "$(brew --prefix sccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@$LLVM_VERSION
curl -LO "$BUN_DOWNLOAD_URL_BASE/bun-darwin-x64-baseline.zip"
unzip bun-darwin-x64-baseline.zip
mkdir -p ${{ runner.temp }}/.bun/bin
mv bun-darwin-x64-baseline/bun ${{ runner.temp }}/.bun/bin/bun
chmod +x ${{ runner.temp }}/.bun/bin/bun
echo "${{ runner.temp }}/.bun/bin" >> $GITHUB_PATH
# TODO: replace with sccache
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-ccache-${{ matrix.tag }}
restore-keys: ${{ runner.os }}-ccache-${{ matrix.tag }}
- name: Compile C++
env:
CPU_TARGET: ${{ matrix.cpu }}
SOURCE_DIR: ${{ github.workspace }}
OBJ_DIR: ${{ runner.temp }}/bun-cpp-obj
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
run: |
mkdir -p $OBJ_DIR
cd $OBJ_DIR
cmake -S $SOURCE_DIR -B $OBJ_DIR \
-G Ninja \
-DUSE_LTO=ON \
-DCMAKE_BUILD_TYPE=Release \
-DBUN_CPP_ONLY=1 \
-DNO_CONFIGURE_DEPENDS=1
bash compile-cpp-only.sh -v
- name: Upload C++
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.tag }}-cpp
path: ${{ runner.temp }}/bun-cpp-obj/bun-cpp-objects.a
if-no-files-found: "error"
macOS:
name: macOS Link
runs-on: ${{ matrix.runner }}
if: github.repository_owner == 'oven-sh'
needs: [macOS-cpp, macos-object-files, macOS-dependencies]
timeout-minutes: 90
permissions: write-all
strategy:
matrix:
include:
- cpu: nehalem
arch: x86_64
tag: bun-darwin-x64-baseline
obj: bun-obj-darwin-x64-baseline
package: bun-darwin-x64
runner: macos-12-large
artifact: bun-obj-darwin-x64-baseline
steps:
- uses: actions/checkout@v4
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Install system dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install ccache llvm@$LLVM_VERSION pkg-config coreutils libtool cmake libiconv openssl@1.1 ninja --force
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@$LLVM_VERSION
curl -LO "$BUN_DOWNLOAD_URL_BASE/bun-darwin-x64-baseline.zip"
unzip bun-darwin-x64-baseline.zip
mkdir -p ${{ runner.temp }}/.bun/bin
mv bun-darwin-x64-baseline/bun ${{ runner.temp }}/.bun/bin/bun
chmod +x ${{ runner.temp }}/.bun/bin/bun
echo "${{ runner.temp }}/.bun/bin" >> $GITHUB_PATH
- name: Download C++
uses: actions/download-artifact@v4
with:
name: ${{ matrix.tag }}-cpp
path: ${{ runner.temp }}/bun-cpp-obj
- name: Download Zig Object
uses: actions/download-artifact@v4
with:
name: ${{ matrix.obj }}
path: ${{ runner.temp }}/release
- name: Downloaded submodule dependencies
uses: actions/download-artifact@v4
with:
name: ${{ matrix.tag }}-deps
path: ${{runner.temp}}/bun-deps
- name: Link
env:
CPU_TARGET: ${{ matrix.cpu }}
run: |
SRC_DIR=$PWD
mkdir ${{runner.temp}}/link-build
cd ${{runner.temp}}/link-build
cmake $SRC_DIR \
-G Ninja \
-DUSE_LTO=ON \
-DCMAKE_BUILD_TYPE=Release \
-DBUN_LINK_ONLY=1 \
-DBUN_ZIG_OBJ="${{ runner.temp }}/release/bun-zig.o" \
-DBUN_CPP_ARCHIVE="${{ runner.temp }}/bun-cpp-obj/bun-cpp-objects.a" \
-DBUN_DEPS_OUT_DIR="${{runner.temp}}/bun-deps" \
-DNO_CONFIGURE_DEPENDS=1
ninja -v
- name: Zip
run: |
cd ${{runner.temp}}/link-build
chmod +x bun-profile bun
mkdir -p ${{matrix.tag}}-profile/ ${{matrix.tag}}/
mv bun-profile ${{matrix.tag}}-profile/bun-profile
mv bun ${{matrix.tag}}/bun
zip -r ${{matrix.tag}}-profile.zip ${{matrix.tag}}-profile
zip -r ${{matrix.tag}}.zip ${{matrix.tag}}
- uses: actions/upload-artifact@v4
with:
name: ${{matrix.tag}}-profile
path: ${{runner.temp}}/link-build/${{matrix.tag}}-profile.zip
if-no-files-found: "error"
- uses: actions/upload-artifact@v4
with:
name: ${{matrix.tag}}
path: ${{runner.temp}}/link-build/${{matrix.tag}}.zip
if-no-files-found: "error"
- name: Release
id: release
uses: ncipollo/release-action@v1
if: |
github.repository_owner == 'oven-sh'
&& github.ref == 'refs/heads/main'
with:
prerelease: true
body: "This canary release of Bun corresponds to the commit [${{ github.sha }}]"
allowUpdates: true
replacesArtifacts: true
generateReleaseNotes: true
artifactErrorsFailBuild: true
token: ${{ secrets.GITHUB_TOKEN }}
name: "Canary (${{github.sha}})"
tag: "canary"
artifacts: "${{runner.temp}}/link-build/${{matrix.tag}}.zip,${{runner.temp}}/link-build/${{matrix.tag}}-profile.zip"
- uses: sarisia/actions-status-discord@v1
if: failure() && github.repository_owner == 'oven-sh' && github.event_name == 'pull_request'
with:
title: ""
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }}
noprefix: true
nocontext: true
description: |
Pull Request
### [${{github.event.pull_request.title}}](https://github.com/oven-sh/bun/pull/${{github.event.number}})
@${{ github.actor }}
Build failed on ${{ matrix.tag }}:
**[View build output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
[Commit ${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})
macOS-test:
name: macOS Test
runs-on: ${{ matrix.runner }}
needs: [macOS]
# if: github.event_name == 'pull_request' && github.repository_owner == 'oven-sh'
if: false
permissions:
pull-requests: write
timeout-minutes: 30
outputs:
failing_tests: ${{ steps.test.outputs.failing_tests }}
failing_tests_count: ${{ steps.test.outputs.failing_tests_count }}
strategy:
fail-fast: false
matrix:
include:
- tag: bun-darwin-x64-baseline
runner: macos-12-large
steps:
- id: checkout
name: Checkout
uses: actions/checkout@v4
with:
submodules: false
- id: download
name: Download
uses: actions/download-artifact@v4
with:
name: ${{matrix.tag}}
path: ${{runner.temp}}/release
- id: install-bun
name: Install Bun
run: |
cd ${{runner.temp}}/release
unzip ${{matrix.tag}}.zip
cd ${{matrix.tag}}
chmod +x bun
pwd >> $GITHUB_PATH
- id: bun-version-check
name: Bun version check
run: |
# If this hangs, it means something is seriously wrong with the build
bun --version
- id: install
name: Install dependencies
run: |
bun install --verbose
bun install --cwd=test --verbose
bun install --cwd=packages/bun-internal-test --verbose
- id: test
name: Test (node runner)
env:
SMTP_SENDGRID_SENDER: ${{ secrets.SMTP_SENDGRID_SENDER }}
TMPDIR: ${{runner.temp}}
TLS_MONGODB_DATABASE_URL: ${{ secrets.TLS_MONGODB_DATABASE_URL }}
TLS_POSTGRES_DATABASE_URL: ${{ secrets.TLS_POSTGRES_DATABASE_URL }}
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "true"
# if: ${{github.event.inputs.use_bun == 'false'}}
run: |
node packages/bun-internal-test/src/runner.node.mjs || true
- uses: sarisia/actions-status-discord@v1
if: always() && steps.test.outputs.failing_tests != '' && github.event_name == 'pull_request'
with:
title: ""
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: "failure"
noprefix: true
nocontext: true
description: |
Pull Request
### ❌ [${{github.event.pull_request.title}}](https://github.com/oven-sh/bun/pull/${{github.event.number}})
Hey @${{ github.actor }},
${{ steps.test.outputs.failing_tests_count }} files with test failures on ${{ matrix.tag }}:
${{ steps.test.outputs.failing_tests }}
**[View test output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
- name: Comment on PR
if: steps.test.outputs.failing_tests != '' && github.event_name == 'pull_request'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: test-failures-${{matrix.tag}}
message: |
❌ @${{ github.actor }} ${{ steps.test.outputs.failing_tests_count }} files with test failures on ${{ matrix.tag }}:
${{ steps.test.outputs.failing_tests }}
**[View test output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
<sup>[#${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})</sup>
- name: Uncomment on PR
if: steps.test.outputs.failing_tests == '' && github.event_name == 'pull_request'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: test-failures-${{matrix.tag}}
mode: upsert
create_if_not_exists: false
message: |
✅ test failures on ${{ matrix.tag }} have been resolved.
<sup>[#${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})</sup>
- id: fail
name: Fail the build
if: steps.test.outputs.failing_tests != ''
run: exit 1

467
.github/workflows/bun-mac-x64.yml vendored Normal file
View File

@@ -0,0 +1,467 @@
name: bun-macOS-x64
concurrency:
group: bun-macOS-x64-${{ github.ref }}
cancel-in-progress: true
env:
LLVM_VERSION: 16
BUN_DOWNLOAD_URL_BASE: https://pub-5e11e972747a44bf9aaf9394f185a982.r2.dev/releases/latest
on:
push:
branches: [main]
paths:
- "src/**/*"
- "test/**/*"
- "packages/bun-usockets/src/**/*"
- "packages/bun-uws/src/**/*"
- "CMakeLists.txt"
- "build.zig"
- "Makefile"
- "Dockerfile"
pull_request:
branches: [main]
paths:
- "src/**/*"
- "test/**/*"
- "packages/bun-usockets/src/**/*"
- "packages/bun-uws/src/**/*"
- "CMakeLists.txt"
- "build.zig"
- "Makefile"
- "Dockerfile"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
macOS-zig:
name: macOS Zig Object
runs-on: namespace-profile-zig-build
if: github.repository_owner == 'oven-sh'
strategy:
matrix:
include:
# - cpu: nehalem
# arch: x86_64
# tag: bun-obj-darwin-x64-baseline
- cpu: haswell
arch: x86_64
tag: bun-obj-darwin-x64
steps:
- uses: actions/checkout@v4
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Compile Zig Object
uses: docker/build-push-action@v5
with:
context: .
push: false
build-args: |
BUILDARCH=${{ runner.arch == 'X64' && 'amd64' || 'arm64' }}
BUILD_MACHINE_ARCH=${{ runner.arch == 'X64' && 'x86_64' || 'aarch64' }}
ARCH=${{ matrix.arch }}
CPU_TARGET=${{ matrix.cpu }}
TRIPLET=${{ matrix.arch }}-macos-none
GIT_SHA=${{ github.sha }}
platforms: linux/${{ runner.arch == 'X64' && 'amd64' || 'arm64' }}
target: build_release_obj
outputs: type=local,dest=${{runner.temp}}/release
- name: Upload Zig Object
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.tag }}
path: ${{runner.temp}}/release/bun-zig.o
if-no-files-found: "error"
macOS-dependencies:
name: macOS Dependencies
runs-on: ${{ matrix.runner }}
if: github.repository_owner == 'oven-sh'
timeout-minutes: 15
strategy:
matrix:
include:
- cpu: haswell
arch: x86_64
tag: bun-darwin-x64
obj: bun-obj-darwin-x64
runner: macos-12-large
artifact: bun-obj-darwin-x64
steps:
- uses: actions/checkout@v4
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Install system dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install sccache ccache rust llvm@$LLVM_VERSION pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config --force
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
# echo "$(brew --prefix sccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@$LLVM_VERSION
- name: Hash submodule versions
run: |
print_data() {
git submodule | grep -v WebKit
llvm-config --version
rustc --version
cat $(echo scripts/build*.sh scripts/all-dependencies.sh | tr " " "\n" | sort)
}
echo "sha=$(print_data | sha1sum | cut -c 1-10)" >> $GITHUB_OUTPUT
id: submodule-versions
- name: Cache submodule dependencies
id: cache-deps-restore
uses: actions/cache/restore@v4
with:
path: ${{runner.temp}}/bun-deps
key: bun-deps-${{ matrix.tag }}-${{ steps.submodule-versions.outputs.sha }}
- name: Compile submodule dependencies
if: ${{ !steps.cache-deps-restore.outputs.cache-hit }}
env:
CPU_TARGET: ${{ matrix.cpu }}
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
run: |
mkdir -p $BUN_DEPS_OUT_DIR
bash ./scripts/clean-dependencies.sh
bash ./scripts/all-dependencies.sh
- name: Cache submodule dependencies
if: ${{ !steps.cache-deps-restore.outputs.cache-hit }}
id: cache-deps-save
uses: actions/cache/save@v4
with:
path: ${{runner.temp}}/bun-deps
key: ${{ steps.cache-deps-restore.outputs.cache-primary-key }}
- name: Upload submodule dependencies
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.tag }}-deps
path: ${{runner.temp}}/bun-deps
if-no-files-found: "error"
macOS-cpp:
name: macOS C++
runs-on: ${{ matrix.runner }}
if: github.repository_owner == 'oven-sh'
timeout-minutes: 90
strategy:
matrix:
include:
- cpu: haswell
arch: x86_64
tag: bun-darwin-x64
obj: bun-obj-darwin-x64
runner: macos-12-large
artifact: bun-obj-darwin-x64
steps:
- uses: actions/checkout@v4
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Install system dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install sccache ccache rust llvm@$LLVM_VERSION pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config --force
# echo "$(brew --prefix sccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@$LLVM_VERSION
curl -LO "$BUN_DOWNLOAD_URL_BASE/bun-darwin-x64.zip"
unzip bun-darwin-x64.zip
mkdir -p ${{ runner.temp }}/.bun/bin
mv bun-darwin-x64/bun ${{ runner.temp }}/.bun/bin/bun
chmod +x ${{ runner.temp }}/.bun/bin/bun
echo "${{ runner.temp }}/.bun/bin" >> $GITHUB_PATH
# TODO: replace with sccache
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-ccache-${{ matrix.tag }}
restore-keys: ${{ runner.os }}-ccache-${{ matrix.tag }}
- name: Compile C++
env:
CPU_TARGET: ${{ matrix.cpu }}
SOURCE_DIR: ${{ github.workspace }}
OBJ_DIR: ${{ runner.temp }}/bun-cpp-obj
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
run: |
mkdir -p $OBJ_DIR
cd $OBJ_DIR
cmake -S $SOURCE_DIR -B $OBJ_DIR \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_LTO=ON \
-DBUN_CPP_ONLY=1 \
-DNO_CONFIGURE_DEPENDS=1
bash compile-cpp-only.sh -v
- name: Upload C++
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.tag }}-cpp
path: ${{ runner.temp }}/bun-cpp-obj/bun-cpp-objects.a
if-no-files-found: "error"
macOS:
name: macOS Link
runs-on: ${{ matrix.runner }}
if: github.repository_owner == 'oven-sh'
needs: [macOS-cpp, macOS-zig, macOS-dependencies]
timeout-minutes: 90
permissions: write-all
strategy:
matrix:
include:
- cpu: haswell
arch: x86_64
tag: bun-darwin-x64
obj: bun-obj-darwin-x64
package: bun-darwin-x64
runner: macos-12-large
artifact: bun-obj-darwin-x64
steps:
- uses: actions/checkout@v4
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Install system dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install ccache llvm@$LLVM_VERSION pkg-config coreutils libtool cmake libiconv openssl@1.1 ninja --force
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@$LLVM_VERSION
curl -LO "$BUN_DOWNLOAD_URL_BASE/bun-darwin-x64-baseline.zip"
unzip bun-darwin-x64-baseline.zip
mkdir -p ${{ runner.temp }}/.bun/bin
mv bun-darwin-x64-baseline/bun ${{ runner.temp }}/.bun/bin/bun
chmod +x ${{ runner.temp }}/.bun/bin/bun
echo "${{ runner.temp }}/.bun/bin" >> $GITHUB_PATH
- name: Download C++
uses: actions/download-artifact@v4
with:
name: ${{ matrix.tag }}-cpp
path: ${{ runner.temp }}/bun-cpp-obj
- name: Download Zig Object
uses: actions/download-artifact@v4
with:
name: ${{ matrix.obj }}
path: ${{ runner.temp }}/release
- name: Downloaded submodule dependencies
uses: actions/download-artifact@v4
with:
name: ${{ matrix.tag }}-deps
path: ${{runner.temp}}/bun-deps
- name: Link
env:
CPU_TARGET: ${{ matrix.cpu }}
run: |
SRC_DIR=$PWD
mkdir ${{runner.temp}}/link-build
cd ${{runner.temp}}/link-build
cmake $SRC_DIR \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_LTO=ON \
-DBUN_LINK_ONLY=1 \
-DBUN_ZIG_OBJ="${{ runner.temp }}/release/bun-zig.o" \
-DBUN_CPP_ARCHIVE="${{ runner.temp }}/bun-cpp-obj/bun-cpp-objects.a" \
-DBUN_DEPS_OUT_DIR="${{runner.temp}}/bun-deps" \
-DNO_CONFIGURE_DEPENDS=1
ninja -v
- name: Zip
run: |
cd ${{runner.temp}}/link-build
chmod +x bun-profile bun
mkdir -p ${{matrix.tag}}-profile/ ${{matrix.tag}}/
mv bun-profile ${{matrix.tag}}-profile/bun-profile
mv bun ${{matrix.tag}}/bun
zip -r ${{matrix.tag}}-profile.zip ${{matrix.tag}}-profile
zip -r ${{matrix.tag}}.zip ${{matrix.tag}}
- uses: actions/upload-artifact@v4
with:
name: ${{matrix.tag}}-profile
path: ${{runner.temp}}/link-build/${{matrix.tag}}-profile.zip
if-no-files-found: "error"
- uses: actions/upload-artifact@v4
with:
name: ${{matrix.tag}}
path: ${{runner.temp}}/link-build/${{matrix.tag}}.zip
if-no-files-found: "error"
- name: Release
id: release
uses: ncipollo/release-action@v1
if: |
github.repository_owner == 'oven-sh'
&& github.ref == 'refs/heads/main'
with:
prerelease: true
body: "This canary release of Bun corresponds to the commit [${{ github.sha }}]"
allowUpdates: true
replacesArtifacts: true
generateReleaseNotes: true
artifactErrorsFailBuild: true
token: ${{ secrets.GITHUB_TOKEN }}
name: "Canary (${{github.sha}})"
tag: "canary"
artifacts: "${{runner.temp}}/link-build/${{matrix.tag}}.zip,${{runner.temp}}/link-build/${{matrix.tag}}-profile.zip"
- uses: sarisia/actions-status-discord@v1
if: failure() && github.repository_owner == 'oven-sh' && github.event_name == 'pull_request'
with:
title: ""
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }}
noprefix: true
nocontext: true
description: |
Pull Request
### [${{github.event.pull_request.title}}](https://github.com/oven-sh/bun/pull/${{github.event.number}})
@${{ github.actor }}
Build failed on ${{ matrix.tag }}:
**[View build output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
[Commit ${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})
macOS-test:
name: Tests ${{matrix.tag}}
runs-on: ${{ matrix.runner }}
needs: [macOS]
if: github.event_name == 'pull_request' && github.repository_owner == 'oven-sh'
permissions:
pull-requests: write
timeout-minutes: 30
outputs:
failing_tests: ${{ steps.test.outputs.failing_tests }}
failing_tests_count: ${{ steps.test.outputs.failing_tests_count }}
strategy:
fail-fast: false
matrix:
include:
- tag: bun-darwin-x64
runner: macos-12-large
steps:
- id: checkout
name: Checkout
uses: actions/checkout@v4
with:
submodules: false
- id: download
name: Download
uses: actions/download-artifact@v4
with:
name: ${{matrix.tag}}
path: ${{runner.temp}}/release
- id: install-bun
name: Install Bun
run: |
cd ${{runner.temp}}/release
unzip ${{matrix.tag}}.zip
cd ${{matrix.tag}}
chmod +x bun
pwd >> $GITHUB_PATH
- id: bun-version-check
name: Bun version check
run: |
# If this hangs, it means something is seriously wrong with the build
bun --version
# Split these into multiple steps to make it clear which one fails
- name: "Install dependencies (root)"
run: bun install --verbose
- name: "Install dependencies (test)"
run: bun install --cwd=test --verbose
- name: "Install dependencies (runner)"
run: bun install --cwd=packages/bun-internal-test --verbose
- id: test
name: Test (node runner)
env:
SMTP_SENDGRID_SENDER: ${{ secrets.SMTP_SENDGRID_SENDER }}
TLS_MONGODB_DATABASE_URL: ${{ secrets.TLS_MONGODB_DATABASE_URL }}
TMPDIR: ${{runner.temp}}
TLS_POSTGRES_DATABASE_URL: ${{ secrets.TLS_POSTGRES_DATABASE_URL }}
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "true"
# if: ${{github.event.inputs.use_bun == 'false'}}
run: |
node packages/bun-internal-test/src/runner.node.mjs || true
- uses: sarisia/actions-status-discord@v1
if: always() && steps.test.outputs.failing_tests != '' && github.event_name == 'pull_request'
with:
title: ""
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: "failure"
noprefix: true
nocontext: true
description: |
Pull Request
### ❌ [${{github.event.pull_request.title}}](https://github.com/oven-sh/bun/pull/${{github.event.number}})
@${{ github.actor }}, there are ${{ steps.test.outputs.failing_tests_count }} files with test failures on ${{ matrix.tag }}:
${{ steps.test.outputs.failing_tests }}
**[View test output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
- name: Comment on PR
if: steps.test.outputs.failing_tests != '' && github.event_name == 'pull_request'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: test-failures-${{matrix.tag}}
message: |
❌ @${{ github.actor }} ${{ steps.test.outputs.failing_tests_count }} files with test failures on ${{ matrix.tag }}:
${{ steps.test.outputs.failing_tests }}
**[View test output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
<sup>[#${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})</sup>
- name: Uncomment on PR
if: steps.test.outputs.failing_tests == '' && github.event_name == 'pull_request'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: test-failures-${{matrix.tag}}
mode: upsert
create_if_not_exists: false
message: |
✅ test failures on ${{ matrix.tag }} have been resolved.
<sup>[#${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})</sup>
- id: fail
name: Fail the build
if: steps.test.outputs.failing_tests != ''
run: exit 1

44
.github/workflows/bun-release-test.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
# This workflow tests bun-release's code and the packages to ensure that npm,
# yarn, and pnpm can install bun on all platforms. This does not test that bun
# itself works as it hardcodes 1.1.0 as the version to package.
name: bun-release-test
concurrency: release-test
on:
pull_request:
paths:
- "packages/bun-release/**"
- ".github/workflows/bun-release-test.yml"
jobs:
test-release-script:
name: Test Release Script
strategy:
matrix:
machine: [namespace-profile-bun-linux-x64, linux-arm64, macos-arm64, macos-12-large, windows-latest]
fail-fast: false
runs-on: ${{ matrix.machine }}
permissions:
contents: read
defaults:
run:
working-directory: packages/bun-release
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: "1.1.0"
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install Dependencies
run: bun install && npm i -g pnpm yarn npm
- name: Release
run: bun upload-npm -- 1.1.0 test
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,10 +1,8 @@
name: Release
name: bun-release
concurrency: release
env:
BUN_VERSION: ${{ github.event.inputs.tag || github.event.release.tag_name || 'canary' }}
BUN_LATEST: ${{ (github.event.inputs.is-latest || github.event.release.tag_name) && 'true' || 'false' }}
on:
release:
types:
@@ -41,7 +39,6 @@ on:
description: Should types be released to npm?
type: boolean
default: false
jobs:
sign:
name: Sign Release
@@ -61,7 +58,7 @@ jobs:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
- name: Setup Bun
uses: ./.github/actions/setup-bun
uses: oven-sh/setup-bun@v1
with:
bun-version: "1.0.21"
- name: Install Dependencies
@@ -86,7 +83,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: ./.github/actions/setup-bun
uses: oven-sh/setup-bun@v1
with:
bun-version: "1.0.21"
- name: Install Dependencies
@@ -115,12 +112,12 @@ jobs:
node-version: latest
- name: Setup Bun
if: ${{ env.BUN_VERSION != 'canary' }}
uses: ./.github/actions/setup-bun
uses: oven-sh/setup-bun@v1
with:
bun-version: "1.0.21"
- name: Setup Bun
if: ${{ env.BUN_VERSION == 'canary' }}
uses: ./.github/actions/setup-bun
uses: oven-sh/setup-bun@v1
with:
bun-version: "canary" # Must be 'canary' so tag is correct
- name: Install Dependencies
@@ -257,7 +254,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: ./.github/actions/setup-bun
uses: oven-sh/setup-bun@v1
with:
bun-version: "1.0.21"
- name: Install Dependencies

41
.github/workflows/bun-types-tests.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: bun-types
on:
push:
paths:
- "packages/bun-types/**"
branches: [main]
pull_request:
paths:
- "packages/bun-types/**"
jobs:
tests:
name: type-tests
runs-on: ubuntu-latest
defaults:
run:
working-directory: packages/bun-types
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Install bun
uses: oven-sh/setup-bun@v1
with:
bun-version: canary
- name: Install node
uses: actions/setup-node@v3
with:
node-version: latest
- name: Install dependencies
run: |
bun install
- name: Generate package
run: bun run build
- name: Tests
run: bun run test

508
.github/workflows/bun-windows.yml vendored Normal file
View File

@@ -0,0 +1,508 @@
name: bun-windows
concurrency:
group: bun-windows-${{ github.ref }}
cancel-in-progress: true
env:
# note: in other files, this version is only the major version, but for windows it is the full version
LLVM_VERSION: 16.0.6
BUN_DOWNLOAD_URL_BASE: https://pub-5e11e972747a44bf9aaf9394f185a982.r2.dev/releases/latest
tag: bun-windows
# TODO: wire this up to workflow_dispatch.
# github's expression syntax makes this hard to set a default to true
canary: true
on:
push:
branches: [main]
paths:
- ".github/workflows/*.yml"
- "src/**/*"
- "test/**/*"
- "packages/bun-usockets/src/**/*"
- "packages/bun-uws/src/**/*"
- "CMakeLists.txt"
- "build.zig"
- "Makefile"
- "Dockerfile"
pull_request:
branches: [main]
paths:
- ".github/workflows/*.yml"
- "src/**/*"
- "test/**/*"
- "packages/bun-usockets/src/**/*"
- "packages/bun-uws/src/**/*"
- "CMakeLists.txt"
- "build.zig"
- "Makefile"
- "Dockerfile"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# inputs:
# is-canary:
# type: boolean
# description: Is Canary Build?
# default: true
jobs:
windows-zig:
strategy:
fail-fast: false
matrix:
cpu: [haswell, nehalem]
arch: [x86_64]
name: Zig Build
runs-on: namespace-profile-zig-build
timeout-minutes: 60
if: github.repository_owner == 'oven-sh'
steps:
- run: git config --global core.autocrlf false && git config --global core.eol lf
- uses: actions/checkout@v4
- name: Checkout submodules
run: git submodule update --init --recursive --depth=1 --progress --force
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Calculate Canary Revision
if: ${{ env.canary == 'true' }}
id: canary
run: |
echo "canary_revision=$(GITHUB_TOKEN="${{ secrets.GITHUB_TOKEN }}" bash ./scripts/calculate-canary-revision.sh --raw)" >> $GITHUB_OUTPUT
- name: Compile Zig Object
uses: docker/build-push-action@v5
with:
context: .
push: false
# This doesnt seem to work
# cache-from: type=s3,endpoint_url=${{ secrets.CACHE_S3_ENDPOINT }},blobs_prefix=docker_blobs/,manifests_prefix=docker_manifests/,access_key_id=${{ secrets.CACHE_S3_ACCESS_KEY_ID }},secret_access_key=${{ secrets.CACHE_S3_SECRET_ACCESS_KEY }},bucket=bun,region=auto
# cache-to: type=s3,endpoint_url=${{ secrets.CACHE_S3_ENDPOINT }},blobs_prefix=docker_blobs/,manifests_prefix=docker_manifests/,access_key_id=${{ secrets.CACHE_S3_ACCESS_KEY_ID }},secret_access_key=${{ secrets.CACHE_S3_SECRET_ACCESS_KEY }},bucket=bun,region=auto
build-args: |
BUILDARCH=${{ runner.arch == 'X64' && 'amd64' || 'arm64' }}
BUILD_MACHINE_ARCH=${{ runner.arch == 'X64' && 'x86_64' || 'aarch64' }}
ARCH=${{ matrix.arch }}
CPU_TARGET=${{ matrix.cpu }}
TRIPLET=${{ matrix.arch }}-windows-msvc
GIT_SHA=${{ github.sha }}
CANARY=0
ZIG_OPTIMIZE=ReleaseSafe
# TODO(@paperdave): enable ASSERTIONS=1
platforms: linux/${{ runner.arch == 'X64' && 'amd64' || 'arm64' }}
target: build_release_obj
outputs: type=local,dest=${{runner.temp}}/release
- name: Upload Zig Object
uses: actions/upload-artifact@v4
with:
name: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}-zig${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}
path: ${{runner.temp}}/release/bun-zig.o
if-no-files-found: "error"
windows-dependencies:
name: Dependencies
runs-on: windows
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
cpu: [haswell, nehalem]
arch: [x86_64]
steps:
- run: git config --global core.autocrlf false && git config --global core.eol lf
- name: Checkout
uses: actions/checkout@v4
- name: Clone Submodules
run: .\scripts\update-submodules.ps1
- name: Hash submodule versions
shell: pwsh
run: |
$data = "$(& {
git submodule | Where-Object { $_ -notmatch 'WebKit' }
clang --version
rustc --version
Get-Content -Path (Get-ChildItem -Path 'scripts/build*.ps1', 'scripts/all-dependencies.ps1', 'scripts/env.ps1' | Sort-Object -Property Name).FullName | Out-String
echo 1
})"
$hash = ( -join ((New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider).ComputeHash([System.Text.Encoding]::UTF8.GetBytes($data)) | ForEach-Object { $_.ToString("x2") } )).Substring(0, 10)
echo "sha=${hash}" >> $env:GITHUB_OUTPUT
id: submodule-versions
- name: Try fetch dependencies
id: cache-deps-restore
uses: actions/cache/restore@v4
with:
path: bun-deps
key: bun-deps-${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}-${{ steps.submodule-versions.outputs.sha }}
- name: Install LLVM ${{ env.LLVM_VERSION }}
if: ${{ !steps.cache-deps-restore.outputs.cache-hit }}
uses: KyleMayes/install-llvm-action@1a3da29f56261a1e1f937ec88f0856a9b8321d7e
with:
version: ${{ env.LLVM_VERSION }}
- name: Install Ninja
if: ${{ !steps.cache-deps-restore.outputs.cache-hit }}
run: choco install -y ninja
- name: Build Dependencies
if: ${{ !steps.cache-deps-restore.outputs.cache-hit }}
run: |
.\scripts\env.ps1 ${{ matrix.cpu == 'nehalem' && '-Baseline' || '' }}
Invoke-WebRequest -Uri "https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/nasm-2.16.01-win64.zip" -OutFile nasm.zip
Expand-Archive nasm.zip (mkdir -Force "nasm")
$Nasm = (Get-ChildItem "nasm")
$env:Path += ";${Nasm}"
$env:BUN_DEPS_OUT_DIR = (mkdir -Force "./bun-deps")
.\scripts\all-dependencies.ps1
- name: Upload Dependencies
uses: actions/upload-artifact@v4
with:
name: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}-deps${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}
path: bun-deps/
if-no-files-found: "error"
- name: Cache Dependencies
if: ${{ !steps.cache-deps-restore.outputs.cache-hit }}
id: cache-deps-save
uses: actions/cache/save@v4
with:
path: bun-deps
key: ${{ steps.cache-deps-restore.outputs.cache-primary-key }}
# TODO(@paperdave): stop relying on this and use bun.exe to build itself.
# we cant do that now because there isn't a tagged release to use.
#
# and at the time of writing, the minimum canary required to work is not
# yet released as it is the one *this* commit.
windows-codegen:
name: Codegen
runs-on: ubuntu-latest
timeout-minutes: 10
if: github.repository_owner == 'oven-sh'
strategy:
fail-fast: false
matrix:
arch: [x86_64]
steps:
- uses: actions/checkout@v4
- run: |
curl -fsSL $BUN_DOWNLOAD_URL_BASE/bun-linux-x64.zip > bun.zip
unzip bun.zip
export PATH="$PWD/bun-linux-x64:$PATH"
./scripts/cross-compile-codegen.sh win32 x64
# Sort of a hack to do this step in the codegen stage
- name: Calculate Canary Revision
if: ${{ env.canary == 'true' }}
run: |
echo "canary_revision=$(GITHUB_TOKEN="${{ secrets.GITHUB_TOKEN }}" bash ./scripts/calculate-canary-revision.sh --raw)" > build-codegen-win32-x64/.canary_revision
- uses: actions/upload-artifact@v4
with:
name: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}-codegen
path: build-codegen-win32-x64/
if-no-files-found: "error"
windows-cpp:
name: C++ Build
needs: [windows-codegen]
runs-on: windows
if: github.repository_owner == 'oven-sh'
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
cpu: [haswell, nehalem]
arch: [x86_64]
steps:
- run: git config --global core.autocrlf false && git config --global core.eol lf
- uses: actions/checkout@v4
- uses: KyleMayes/install-llvm-action@1a3da29f56261a1e1f937ec88f0856a9b8321d7e
with:
version: ${{ env.LLVM_VERSION }}
- run: choco install -y ninja
- name: Download Codegen
uses: actions/download-artifact@v4
with:
name: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}-codegen
path: build
- name: Build C++
run: |
# Using SCCache was blocked by an issue that is fixed in a newer version.
# TODO UPDATE
# $sczip = "sccache-v0.6.0-x86_64-pc-windows-msvc"
# Invoke-WebRequest -Uri "https://github.com/mozilla/sccache/releases/download/v0.6.0/${sczip}.zip" -OutFile "${sczip}.zip"
# Expand-Archive "${sczip}.zip"
# $env:SCCACHE_BUCKET="bun"
# $env:SCCACHE_REGION="auto"
# $env:SCCACHE_S3_USE_SSL="true"
# $env:SCCACHE_ENDPOINT="${{ secrets.CACHE_S3_ENDPOINT }}"
# $env:AWS_ACCESS_KEY_ID="${{ secrets.CACHE_S3_ACCESS_KEY_ID }}"
# $env:AWS_SECRET_ACCESS_KEY="${{ secrets.CACHE_S3_SECRET_ACCESS_KEY }}"
# $SCCACHE="$PWD/${sczip}/${sczip}/sccache.exe"
# $CANARY_REVISION = if (Test-Path build/.canary_revision) { Get-Content build/.canary_revision } else { "0" }
$CANARY_REVISION = 0
.\scripts\env.ps1 ${{ matrix.cpu == 'nehalem' && '-Baseline' || '' }}
.\scripts\update-submodules.ps1
.\scripts\build-libuv.ps1 -CloneOnly $True
cd build
# "-DCCACHE_PROGRAM=${SCCACHE}"
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release `
-DNO_CODEGEN=1 `
-DNO_CONFIGURE_DEPENDS=1 `
"-DCANARY=${CANARY_REVISION}" `
-DBUN_CPP_ONLY=1 ${{ matrix.cpu == 'nehalem' && '-DUSE_BASELINE_BUILD=1' || '' }}
if ($LASTEXITCODE -ne 0) { throw "CMake configuration failed" }
.\compile-cpp-only.ps1 -v
if ($LASTEXITCODE -ne 0) { throw "C++ compilation failed" }
- uses: actions/upload-artifact@v4
with:
name: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}-cpp${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}
path: build/bun-cpp-objects.a
if-no-files-found: "error"
windows-link:
strategy:
fail-fast: false
matrix:
cpu: [haswell, nehalem]
arch: [x86_64]
name: Link
needs: [windows-dependencies, windows-codegen, windows-cpp, windows-zig]
runs-on: windows-small
if: github.repository_owner == 'oven-sh'
timeout-minutes: 30
permissions: write-all
steps:
- run: git config --global core.autocrlf false && git config --global core.eol lf
- uses: actions/checkout@v4
- uses: KyleMayes/install-llvm-action@1a3da29f56261a1e1f937ec88f0856a9b8321d7e
with:
version: ${{ env.LLVM_VERSION }}
- run: choco install -y ninja
- name: Download Codegen
uses: actions/download-artifact@v4
with:
name: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}-codegen
path: build
- name: Download Dependencies
uses: actions/download-artifact@v4
with:
name: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}-deps${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}
path: bun-deps
- name: Download Zig Object
uses: actions/download-artifact@v4
with:
name: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}-zig${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}
path: bun-zig
- name: Download C++ Objects
uses: actions/download-artifact@v4
with:
name: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}-cpp${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}
path: bun-cpp
- name: Link
run: |
.\scripts\update-submodules.ps1
.\scripts\env.ps1 ${{ matrix.cpu == 'nehalem' && '-Baseline' || '' }}
Set-Location build
# $CANARY_REVISION = if (Test-Path build/.canary_revision) { Get-Content build/.canary_revision } else { "0" }
$CANARY_REVISION = 0
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release `
-DNO_CODEGEN=1 `
-DNO_CONFIGURE_DEPENDS=1 `
"-DCANARY=${CANARY_REVISION}" `
-DBUN_LINK_ONLY=1 `
"-DBUN_DEPS_OUT_DIR=$(Resolve-Path ../bun-deps)" `
"-DBUN_CPP_ARCHIVE=$(Resolve-Path ../bun-cpp/bun-cpp-objects.a)" `
"-DBUN_ZIG_OBJ=$(Resolve-Path ../bun-zig/bun-zig.o)" `
${{ matrix.cpu == 'nehalem' && '-DUSE_BASELINE_BUILD=1' || '' }}
if ($LASTEXITCODE -ne 0) { throw "CMake configuration failed" }
ninja -v
if ($LASTEXITCODE -ne 0) { throw "Link failed!" }
- name: Package
run: |
$Dist = mkdir -Force "${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}"
cp -r build\bun.exe "$Dist\bun.exe"
Compress-Archive "$Dist" "${Dist}.zip"
$Dist = "$Dist-profile"
MkDir -Force "$Dist"
cp -r build\bun.exe "$Dist\bun.exe"
cp -r build\bun.pdb "$Dist\bun.pdb"
Compress-Archive "$Dist" "$Dist.zip"
- uses: actions/upload-artifact@v4
with:
name: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}
path: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}.zip
if-no-files-found: "error"
- uses: actions/upload-artifact@v4
with:
name: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}-profile
path: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}-profile.zip
if-no-files-found: "error"
- name: Release
id: release
uses: ncipollo/release-action@v1
if: |
github.repository_owner == 'oven-sh'
&& github.ref == 'refs/heads/main'
with:
prerelease: true
body: "This canary release of Bun corresponds to the commit [${{ github.sha }}]"
allowUpdates: true
replacesArtifacts: true
generateReleaseNotes: true
artifactErrorsFailBuild: true
token: ${{ secrets.GITHUB_TOKEN }}
name: "Canary (${{github.sha}})"
tag: "canary"
artifacts: "${{env.tag}}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}.zip,${{env.tag}}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}-profile.zip"
- uses: sarisia/actions-status-discord@v1
if: failure() && github.repository_owner == 'oven-sh' && github.event_name == 'pull_request'
with:
title: ""
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }}
noprefix: true
nocontext: true
description: |
### [${{github.event.pull_request.title}}](https://github.com/oven-sh/bun/pull/${{github.event.number}})
@${{ github.actor }}
Build failed on Windows ${{ matrix.arch }}${{ matrix.cpu == 'nehalem' && ' Baseline' || '' }}
**[Build Output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})** | [Commit](https://github.com/oven-sh/bun/commits/${{github.sha}})
windows-test:
name: Test
runs-on: windows-small
needs: [windows-link]
if: github.event_name == 'pull_request' && github.repository_owner == 'oven-sh'
permissions:
pull-requests: write
timeout-minutes: 180
outputs:
failing_tests: ${{ steps.test.outputs.failing_tests }}
failing_tests_count: ${{ steps.test.outputs.failing_tests_count }}
strategy:
fail-fast: false
matrix:
# TODO: test baseline, disabled due to noise
cpu: [haswell]
arch: [x86_64]
steps:
- run: git config --global core.autocrlf false && git config --global core.eol lf
- id: checkout
name: Checkout
uses: actions/checkout@v4
with:
submodules: false
- id: download
name: Download Release
uses: actions/download-artifact@v4
with:
name: ${{ env.tag }}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}-profile
path: ${{runner.temp}}/release
- name: Install Bun
run: |
cd ${{runner.temp}}/release
unzip ${{env.tag}}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}-profile.zip
cd ${{env.tag}}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}-profile
pwd >> $env:GITHUB_PATH
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: 20
- uses: secondlife/setup-cygwin@v3
with:
packages: bash
# Split these into multiple steps to make it clear which one fails
- name: Install dependencies (root)
run: bun install --verbose
- name: Install dependencies (test)
run: bun install --cwd=test --verbose
- name: Install dependencies (runner)
run: bun install --cwd=packages/bun-internal-test --verbose
- id: test
name: Run tests
env:
SMTP_SENDGRID_SENDER: ${{ secrets.SMTP_SENDGRID_SENDER }}
TMPDIR: ${{runner.temp}}
TLS_MONGODB_DATABASE_URL: ${{ secrets.TLS_MONGODB_DATABASE_URL }}
TLS_POSTGRES_DATABASE_URL: ${{ secrets.TLS_POSTGRES_DATABASE_URL }}
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "true"
SHELLOPTS: igncr
BUN_PATH_BASE: ${{runner.temp}}
BUN_PATH: release/${{env.tag}}-${{ matrix.arch == 'x86_64' && 'x64' || 'aarch64' }}${{ matrix.cpu == 'nehalem' && '-baseline' || '' }}-profile/bun.exe
run: |
node packages/bun-internal-test/src/runner.node.mjs || true
shell: bash
- uses: sarisia/actions-status-discord@v1
if: always() && steps.test.outputs.failing_tests != '' && github.event_name == 'pull_request'
with:
title: ""
webhook: ${{ secrets.DISCORD_WEBHOOK_WINTEST }}
status: "failure"
noprefix: true
nocontext: true
description: |
### ❌🪟 [${{github.event.pull_request.title}}](https://github.com/oven-sh/bun/pull/${{github.event.number}})
@${{ github.actor }}, there are **${{ steps.test.outputs.failing_test_count }} failing tests** on Windows ${{ matrix.arch }}${{ matrix.cpu == 'nehalem' && ' Baseline' || '' }}
${{ steps.test.outputs.failing_tests }}
[Full Test Output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})
- uses: sarisia/actions-status-discord@v1
if: always() && steps.test.outputs.failing_tests != '' && github.event_name == 'pull_request'
with:
title: ""
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: "failure"
noprefix: true
nocontext: true
description: |
Pull Request
### ❌ [${{github.event.pull_request.title}}](https://github.com/oven-sh/bun/pull/${{github.event.number}})
@${{ github.actor }}, there are ${{ steps.test.outputs.failing_tests_count }} files with test failures on bun-windows-${{ matrix.arch }}-${{ matrix.cpu }}
${{ steps.test.outputs.failing_tests }}
**[View test output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
- name: Comment on PR
if: always() && steps.test.outputs.failing_tests != '' && github.event_name == 'pull_request'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: test-windows-${{ matrix.arch }}-${{ matrix.cpu }}
message: |
❌ @${{ github.actor }} ${{ steps.test.outputs.failing_tests_count }} files with test failures on bun-windows-${{ matrix.arch }}-${{ matrix.cpu }}
${{ steps.test.outputs.failing_tests }}
**[View test output](https://github.com/oven-sh/bun/actions/runs/${{github.run_id}})**
<sup>[#${{github.sha}}](https://github.com/oven-sh/bun/commits/${{github.sha}})</sup>
- name: Uncomment on PR
if: steps.test.outputs.failing_tests == '' && github.event_name == 'pull_request'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: test-windows-${{ matrix.arch }}-${{ matrix.cpu }}
mode: upsert
create_if_not_exists: false
message: |
✅🪟 Test regressions on Windows ${{ matrix.arch }}${{ matrix.cpu == 'nehalem' && ' Baseline' || '' }} have been resolved.
- id: fail
name: Fail the build
if: steps.test.outputs.failing_tests != ''
run: exit 1

View File

@@ -1,245 +0,0 @@
name: CI
permissions:
contents: read
actions: write
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && inputs.run-id || github.ref }}
cancel-in-progress: true
on:
workflow_dispatch:
inputs:
run-id:
type: string
description: The workflow ID to download artifacts (skips the build step)
pull_request:
paths-ignore:
- .vscode/**/*
- docs/**/*
- examples/**/*
push:
branches:
- main
paths-ignore:
- .vscode/**/*
- docs/**/*
- examples/**/*
jobs:
format:
if: ${{ !inputs.run-id }}
name: Format
uses: ./.github/workflows/run-format.yml
secrets: inherit
with:
zig-version: 0.12.0-dev.1828+225fe6ddb
permissions:
contents: write
lint:
if: ${{ !inputs.run-id }}
name: Lint
uses: ./.github/workflows/run-lint.yml
secrets: inherit
linux-x64:
if: ${{ !inputs.run-id }}
name: Build linux-x64
uses: ./.github/workflows/build-linux.yml
secrets: inherit
with:
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-linux-x64' || 'ubuntu-latest' }}
tag: linux-x64
arch: x64
cpu: haswell
canary: true
no-cache: true
linux-x64-baseline:
if: ${{ !inputs.run-id }}
name: Build linux-x64-baseline
uses: ./.github/workflows/build-linux.yml
secrets: inherit
with:
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-linux-x64' || 'ubuntu-latest' }}
tag: linux-x64-baseline
arch: x64
cpu: nehalem
canary: true
no-cache: true
linux-aarch64:
if: ${{ !inputs.run-id && github.repository_owner == 'oven-sh' }}
name: Build linux-aarch64
uses: ./.github/workflows/build-linux.yml
secrets: inherit
with:
runs-on: namespace-profile-bun-ci-linux-aarch64
tag: linux-aarch64
arch: aarch64
cpu: native
canary: true
no-cache: true
darwin-x64:
if: ${{ !inputs.run-id }}
name: Build darwin-x64
uses: ./.github/workflows/build-darwin.yml
secrets: inherit
with:
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-12-large' || 'macos-12' }}
tag: darwin-x64
arch: x64
cpu: haswell
canary: true
darwin-x64-baseline:
if: ${{ !inputs.run-id }}
name: Build darwin-x64-baseline
uses: ./.github/workflows/build-darwin.yml
secrets: inherit
with:
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-12-large' || 'macos-12' }}
tag: darwin-x64-baseline
arch: x64
cpu: nehalem
canary: true
darwin-aarch64:
if: ${{ !inputs.run-id }}
name: Build darwin-aarch64
uses: ./.github/workflows/build-darwin.yml
secrets: inherit
with:
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-darwin-aarch64' || 'macos-12' }}
tag: darwin-aarch64
arch: aarch64
cpu: native
canary: true
windows-x64:
if: ${{ !inputs.run-id }}
name: Build windows-x64
uses: ./.github/workflows/build-windows.yml
secrets: inherit
with:
runs-on: windows
tag: windows-x64
arch: x64
cpu: haswell
canary: true
windows-x64-baseline:
if: ${{ !inputs.run-id }}
name: Build windows-x64-baseline
uses: ./.github/workflows/build-windows.yml
secrets: inherit
with:
runs-on: windows
tag: windows-x64-baseline
arch: x64
cpu: nehalem
canary: true
linux-x64-test:
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
name: Test linux-x64
needs: linux-x64
uses: ./.github/workflows/run-test.yml
secrets: inherit
with:
run-id: ${{ inputs.run-id }}
pr-number: ${{ github.event.number }}
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-linux-x64' || 'ubuntu-latest' }}
tag: linux-x64
linux-x64-baseline-test:
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
name: Test linux-x64-baseline
needs: linux-x64-baseline
uses: ./.github/workflows/run-test.yml
secrets: inherit
with:
run-id: ${{ inputs.run-id }}
pr-number: ${{ github.event.number }}
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-linux-x64' || 'ubuntu-latest' }}
tag: linux-x64-baseline
linux-aarch64-test:
if: ${{ inputs.run-id || github.event_name == 'pull_request' && github.repository_owner == 'oven-sh'}}
name: Test linux-aarch64
needs: linux-aarch64
uses: ./.github/workflows/run-test.yml
secrets: inherit
with:
run-id: ${{ inputs.run-id }}
pr-number: ${{ github.event.number }}
runs-on: namespace-profile-bun-ci-linux-aarch64
tag: linux-aarch64
darwin-x64-test:
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
name: Test darwin-x64
needs: darwin-x64
uses: ./.github/workflows/run-test.yml
secrets: inherit
with:
run-id: ${{ inputs.run-id }}
pr-number: ${{ github.event.number }}
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-12-large' || 'macos-12' }}
tag: darwin-x64
darwin-x64-baseline-test:
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
name: Test darwin-x64-baseline
needs: darwin-x64-baseline
uses: ./.github/workflows/run-test.yml
secrets: inherit
with:
run-id: ${{ inputs.run-id }}
pr-number: ${{ github.event.number }}
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-12-large' || 'macos-12' }}
tag: darwin-x64-baseline
darwin-aarch64-test:
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
name: Test darwin-aarch64
needs: darwin-aarch64
uses: ./.github/workflows/run-test.yml
secrets: inherit
with:
run-id: ${{ inputs.run-id }}
pr-number: ${{ github.event.number }}
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-darwin-aarch64' || 'macos-12' }}
tag: darwin-aarch64
windows-x64-test:
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
name: Test windows-x64
needs: windows-x64
uses: ./.github/workflows/run-test.yml
secrets: inherit
with:
run-id: ${{ inputs.run-id }}
pr-number: ${{ github.event.number }}
runs-on: windows
tag: windows-x64
windows-x64-baseline-test:
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
name: Test windows-x64-baseline
needs: windows-x64-baseline
uses: ./.github/workflows/run-test.yml
secrets: inherit
with:
run-id: ${{ inputs.run-id }}
pr-number: ${{ github.event.number }}
runs-on: windows
tag: windows-x64-baseline
cleanup:
if: ${{ always() }}
name: Cleanup
needs:
- linux-x64
- linux-x64-baseline
- linux-aarch64
- darwin-x64
- darwin-x64-baseline
- darwin-aarch64
- windows-x64
- windows-x64-baseline
runs-on: ubuntu-latest
steps:
- name: Cleanup Artifacts
uses: geekyeggo/delete-artifact@v5
with:
name: |
bun-*-cpp
bun-*-zig
bun-*-deps
bun-*-codegen

View File

@@ -1,121 +0,0 @@
name: Comment
permissions:
actions: read
pull-requests: write
on:
workflow_run:
workflows:
- CI
types:
- completed
jobs:
comment:
if: ${{ github.repository_owner == 'oven-sh' }}
name: Comment
runs-on: ubuntu-latest
steps:
- name: Download Tests
uses: actions/download-artifact@v4
with:
path: bun
pattern: bun-*-tests
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}
- name: Setup Environment
id: env
shell: bash
run: |
echo "pr-number=$(<bun/bun-linux-x64-tests/pr-number.txt)" >> $GITHUB_OUTPUT
- name: Generate Comment
run: |
cat bun/bun-*-tests/comment.md > comment.md
if [ -s comment.md ]; then
echo -e "❌ @${{ github.actor }}, your commit has failing tests :(\n\n$(cat comment.md)" > comment.md
else
echo -e "✅ @${{ github.actor }}, all tests passed!" > comment.md
fi
echo -e "\n**[View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }})**" >> comment.md
echo -e "<!-- generated-comment workflow=${{ github.workflow }} -->" >> comment.md
- name: Find Comment
id: comment
uses: peter-evans/find-comment@v3
with:
issue-number: ${{ steps.env.outputs.pr-number }}
comment-author: github-actions[bot]
body-includes: <!-- generated-comment workflow=${{ github.workflow }} -->
- name: Write Comment
uses: peter-evans/create-or-update-comment@v4
with:
comment-id: ${{ steps.comment.outputs.comment-id }}
issue-number: ${{ steps.env.outputs.pr-number }}
body-path: comment.md
edit-mode: replace
comment-lint:
if: ${{ github.repository_owner == 'oven-sh' }}
name: Comment
runs-on: ubuntu-latest
steps:
- name: Download Comment
uses: actions/download-artifact@v4
with:
name: format.log
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}
- name: PR Number
uses: actions/download-artifact@v4
with:
name: pr-number.txt
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}
- name: PR Number
uses: actions/download-artifact@v4
with:
name: did_fail.txt
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}
- name: Setup Environment
id: env
shell: bash
run: |
# Copy to outputs
echo "pr-number=$(<pr-number.txt)" >> $GITHUB_OUTPUT
echo "text_output=$(<format.log)" >> $GITHUB_OUTPUT
echo "did_fail=$(<did_fail.txt)" >> $GITHUB_OUTPUT
- name: Find Comment
id: comment
uses: peter-evans/find-comment@v3
with:
issue-number: ${{ steps.env.outputs.pr-number }}
comment-author: github-actions[bot]
body-includes: <!-- generated-comment workflow=${{ github.workflow }} -->
- name: Update Comment
uses: peter-evans/create-or-update-comment@v4
if: steps.env.outputs.did_fail != '0'
with:
comment-id: ${{ steps.comment.outputs.comment-id }}
issue-number: ${{ steps.env.outputs.pr-number }}
body: |
@${{ github.actor }}, C++ linting failed!
Logs:
```cpp
${{ steps.env.outputs.text_output }}
```
<!-- generated-comment workflow=${{ github.workflow }} -->
edit-mode: replace
- name: Update Previous Comment
uses: peter-evans/create-or-update-comment@v4
if: steps.env.outputs.did_fail == '0' && steps.comment.outputs.comment-id != ''
with:
comment-id: ${{ steps.comment.outputs.comment-id }}
issue-number: ${{ steps.env.outputs.pr-number }}
body: |
@${{ github.actor }}, C++ lint errors fixed! Thank you.
<!-- generated-comment workflow=${{ github.workflow }} -->
edit-mode: replace

View File

@@ -1,183 +0,0 @@
name: Create Release Build
run-name: Compile Bun v${{ inputs.version }} by ${{ github.actor }}
concurrency:
group: release
cancel-in-progress: true
permissions:
contents: write
actions: write
on:
workflow_dispatch:
inputs:
version:
type: string
required: true
description: "Release version. Example: 1.1.4. Exclude the 'v' prefix."
tag:
type: string
required: true
description: "GitHub tag to use"
clobber:
type: boolean
required: false
default: false
description: "Overwrite existing release artifacts?"
release:
types:
- created
jobs:
notify-start:
if: ${{ github.repository_owner == 'oven-sh' }}
name: Notify Start
runs-on: ubuntu-latest
steps:
- name: Send Message
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_PUBLIC }}
nodetail: true
color: "#1F6FEB"
title: "Bun v${{ inputs.version }} is compiling"
description: |
### @${{ github.actor }} started compiling Bun v${{inputs.version}}
- name: Send Message
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.BUN_DISCORD_GITHUB_CHANNEL_WEBHOOK }}
nodetail: true
color: "#1F6FEB"
title: "Bun v${{ inputs.version }} is compiling"
description: |
### @${{ github.actor }} started compiling Bun v${{inputs.version}}
**[View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**
linux-x64:
name: Build linux-x64
uses: ./.github/workflows/build-linux.yml
secrets: inherit
with:
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-linux-x64' || 'ubuntu-latest' }}
tag: linux-x64
arch: x64
cpu: haswell
canary: false
linux-x64-baseline:
name: Build linux-x64-baseline
uses: ./.github/workflows/build-linux.yml
secrets: inherit
with:
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-linux-x64' || 'ubuntu-latest' }}
tag: linux-x64-baseline
arch: x64
cpu: nehalem
canary: false
linux-aarch64:
name: Build linux-aarch64
uses: ./.github/workflows/build-linux.yml
secrets: inherit
with:
runs-on: namespace-profile-bun-ci-linux-aarch64
tag: linux-aarch64
arch: aarch64
cpu: native
canary: false
darwin-x64:
name: Build darwin-x64
uses: ./.github/workflows/build-darwin.yml
secrets: inherit
with:
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-12-large' || 'macos-12' }}
tag: darwin-x64
arch: x64
cpu: haswell
canary: false
darwin-x64-baseline:
name: Build darwin-x64-baseline
uses: ./.github/workflows/build-darwin.yml
secrets: inherit
with:
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-12-large' || 'macos-12' }}
tag: darwin-x64-baseline
arch: x64
cpu: nehalem
canary: false
darwin-aarch64:
name: Build darwin-aarch64
uses: ./.github/workflows/build-darwin.yml
secrets: inherit
with:
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-darwin-aarch64' || 'macos-12' }}
tag: darwin-aarch64
arch: aarch64
cpu: native
canary: false
windows-x64:
name: Build windows-x64
uses: ./.github/workflows/build-windows.yml
secrets: inherit
with:
runs-on: windows
tag: windows-x64
arch: x64
cpu: haswell
canary: false
windows-x64-baseline:
name: Build windows-x64-baseline
uses: ./.github/workflows/build-windows.yml
secrets: inherit
with:
runs-on: windows
tag: windows-x64-baseline
arch: x64
cpu: nehalem
canary: false
upload-artifacts:
needs:
- linux-x64
- linux-x64-baseline
- linux-aarch64
- darwin-x64
- darwin-x64-baseline
- darwin-aarch64
- windows-x64
- windows-x64-baseline
runs-on: ubuntu-latest
steps:
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: bun-releases
pattern: bun-*
merge-multiple: true
github-token: ${{ github.token }}
- name: Check for Artifacts
run: |
if [ ! -d "bun-releases" ] || [ -z "$(ls -A bun-releases)" ]; then
echo "Error: No artifacts were downloaded or 'bun-releases' directory does not exist."
exit 1 # Fail the job if the condition is met
else
echo "Artifacts downloaded successfully."
fi
- name: Send Message
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
nodetail: true
color: "#FF0000"
title: "Bun v${{ inputs.version }} release artifacts uploaded"
- name: "Upload Artifacts"
env:
GH_TOKEN: ${{ github.token }}
run: |
# Unzip one level deep each artifact
cd bun-releases
for f in *.zip; do
unzip -o $f
done
cd ..
gh release upload --repo=${{ github.repository }} ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.event.release.id }} ${{ inputs.clobber && '--clobber' || '' }} bun-releases/*.zip

View File

@@ -1,21 +0,0 @@
name: Docs
on:
push:
paths:
- "docs/**"
- "CONTRIBUTING.md"
branches:
- main
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'oven-sh' }}
steps:
# redeploy Vercel site when a file in `docs` changes
# using VERCEL_DEPLOY_HOOK environment variable
- name: Trigger Webhook
run: |
curl -v ${{ secrets.VERCEL_DEPLOY_HOOK }}

View File

@@ -1,19 +1,22 @@
name: Format
name: autofix.ci # Must be named this for autofix.ci to work
permissions:
contents: write
contents: read
on:
workflow_call:
inputs:
zig-version:
type: string
required: true
workflow_dispatch:
pull_request:
push:
branches:
- main
env:
ZIG_VERSION: 0.12.0-dev.1828+225fe6ddb
jobs:
format:
name: Format
runs-on: ubuntu-latest
name: format
runs-on: ${{ vars.RUNNER_LINUX_X64 || 'ubuntu-latest' }}
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -31,17 +34,13 @@ jobs:
- name: Setup Zig
uses: goto-bus-stop/setup-zig@c7b6cdd3adba8f8b96984640ff172c37c93f73ee
with:
version: ${{ inputs.zig-version }}
version: ${{ env.ZIG_VERSION }}
- name: Install Dependencies
run: |
bun install
- name: Format
run: |
bun fmt
- name: Format Zig
run: |
bun fmt:zig
- name: Commit
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: Apply formatting changes
- name: Commit # https://autofix.ci/
uses: autofix-ci/action@d3e591514b99d0fca6779455ff8338516663f7cc

View File

@@ -1,30 +0,0 @@
name: Lint
permissions:
contents: read
on:
workflow_call:
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
outputs:
text_output: ${{ steps.lint.outputs.text_output }}
json_output: ${{ steps.lint.outputs.json_output }}
count: ${{ steps.lint.outputs.count }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: "1.1.3"
- name: Install Dependencies
run: |
bun --cwd=packages/bun-internal-test install
- name: Lint
id: lint
run: |
bun packages/bun-internal-test/src/linter.ts

View File

@@ -1,211 +0,0 @@
name: Test
permissions:
contents: read
actions: read
on:
workflow_call:
inputs:
runs-on:
type: string
required: true
tag:
type: string
required: true
pr-number:
type: string
required: true
run-id:
type: string
default: ${{ github.run_id }}
jobs:
test:
name: Tests
runs-on: ${{ inputs.runs-on }}
steps:
- if: ${{ runner.os == 'Windows' }}
name: Setup Git
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- name: Checkout
uses: actions/checkout@v4
with:
sparse-checkout: |
package.json
bun.lockb
test
packages/bun-internal-test
- name: Setup Environment
shell: bash
run: |
echo "${{ inputs.pr-number }}" > pr-number.txt
- name: Download Bun
uses: actions/download-artifact@v4
with:
name: bun-${{ inputs.tag }}
path: bun
github-token: ${{ github.token }}
run-id: ${{ inputs.run-id || github.run_id }}
- if: ${{ runner.os != 'Windows' }}
name: Setup Bun
shell: bash
run: |
unzip bun/bun-*.zip
cd bun-*
pwd >> $GITHUB_PATH
- if: ${{ runner.os == 'Windows' }}
name: Setup Cygwin
uses: secondlife/setup-cygwin@v3
with:
packages: bash
- if: ${{ runner.os == 'Windows' }}
name: Setup Bun (Windows)
run: |
unzip bun/bun-*.zip
cd bun-*
pwd >> $env:GITHUB_PATH
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install Dependencies
timeout-minutes: 5
run: |
bun install
- name: Install Dependencies (test)
timeout-minutes: 5
run: |
bun install --cwd test
- name: Install Dependencies (runner)
timeout-minutes: 5
run: |
bun install --cwd packages/bun-internal-test
- name: Run Tests
id: test
timeout-minutes: 90
shell: bash
env:
TMPDIR: ${{ runner.temp }}
BUN_TAG: ${{ inputs.tag }}
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "true"
SMTP_SENDGRID_SENDER: ${{ secrets.SMTP_SENDGRID_SENDER }}
TLS_MONGODB_DATABASE_URL: ${{ secrets.TLS_MONGODB_DATABASE_URL }}
TLS_POSTGRES_DATABASE_URL: ${{ secrets.TLS_POSTGRES_DATABASE_URL }}
TEST_INFO_STRIPE: ${{ secrets.TEST_INFO_STRIPE }}
TEST_INFO_AZURE_SERVICE_BUS: ${{ secrets.TEST_INFO_AZURE_SERVICE_BUS }}
SHELLOPTS: igncr
run: |
node packages/bun-internal-test/src/runner.node.mjs $(which bun)
- if: ${{ always() }}
name: Upload Results
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}-tests
path: |
test-report.*
comment.md
pr-number.txt
if-no-files-found: error
overwrite: true
- if: ${{ always() && steps.test.outputs.failing_tests != '' && github.event.pull_request && github.repository_owner == 'oven-sh' }}
name: Send Message
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
nodetail: true
color: "#FF0000"
title: ""
description: |
### ❌ [${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }})
@${{ github.actor }}, there are ${{ steps.test.outputs.failing_tests_count || 'some' }} failing tests on bun-${{ inputs.tag }}.
${{ steps.test.outputs.failing_tests }}
**[View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**
- name: Fail
if: ${{ failure() || always() && steps.test.outputs.failing_tests != '' }}
run: |
echo "There are ${{ steps.test.outputs.failing_tests_count || 'some' }} failing tests on bun-${{ inputs.tag }}."
exit 1
test-node:
name: Node.js Tests
# TODO: enable when we start paying attention to the results. In the meantime, this causes CI to queue jobs wasting developer time.
if: 0
runs-on: ${{ inputs.runs-on }}
steps:
- if: ${{ runner.os == 'Windows' }}
name: Setup Git
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- name: Checkout
uses: actions/checkout@v4
with:
sparse-checkout: |
test/node.js
- name: Setup Environment
shell: bash
run: |
echo "${{ inputs.pr-number }}" > pr-number.txt
- name: Download Bun
uses: actions/download-artifact@v4
with:
name: bun-${{ inputs.tag }}
path: bun
github-token: ${{ github.token }}
run-id: ${{ inputs.run-id || github.run_id }}
- if: ${{ runner.os != 'Windows' }}
name: Setup Bun
shell: bash
run: |
unzip bun/bun-*.zip
cd bun-*
pwd >> $GITHUB_PATH
- if: ${{ runner.os == 'Windows' }}
name: Setup Cygwin
uses: secondlife/setup-cygwin@v3
with:
packages: bash
- if: ${{ runner.os == 'Windows' }}
name: Setup Bun (Windows)
run: |
unzip bun/bun-*.zip
cd bun-*
pwd >> $env:GITHUB_PATH
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Checkout Tests
shell: bash
working-directory: test/node.js
run: |
node runner.mjs --pull
- name: Install Dependencies
timeout-minutes: 5
shell: bash
working-directory: test/node.js
run: |
bun install
- name: Run Tests
timeout-minutes: 10 # Increase when more tests are added
shell: bash
working-directory: test/node.js
env:
TMPDIR: ${{ runner.temp }}
BUN_GARBAGE_COLLECTOR_LEVEL: "0"
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "true"
run: |
node runner.mjs
- name: Upload Results
uses: actions/upload-artifact@v4
with:
name: bun-${{ inputs.tag }}-node-tests
path: |
test/node.js/summary/*.json
if-no-files-found: error
overwrite: true

View File

@@ -1,82 +0,0 @@
name: Upload Artifacts
run-name: Canary release ${{github.sha}} upload
permissions:
contents: write
on:
workflow_run:
workflows:
- CI
types:
- completed
branches:
- main
jobs:
upload:
if: ${{ github.repository_owner == 'oven-sh' }}
name: Upload Artifacts
runs-on: ubuntu-latest
steps:
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: bun
pattern: bun-*
merge-multiple: true
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}
- name: Check for Artifacts
run: |
if [ ! -d "bun" ] || [ -z "$(ls -A bun)" ]; then
echo "Error: No artifacts were downloaded or 'bun' directory does not exist."
exit 1 # Fail the job if the condition is met
else
echo "Artifacts downloaded successfully."
fi
- name: Upload to GitHub Releases
uses: ncipollo/release-action@v1
with:
tag: canary
name: Canary (${{ github.sha }})
prerelease: true
body: This canary release of Bun corresponds to the commit [${{ github.sha }}]
allowUpdates: true
replacesArtifacts: true
generateReleaseNotes: true
artifactErrorsFailBuild: true
artifacts: bun/**/bun-*.zip
token: ${{ github.token }}
- name: Upload to S3 (using SHA)
uses: shallwefootball/s3-upload-action@4350529f410221787ccf424e50133cbc1b52704e
with:
endpoint: ${{ secrets.AWS_ENDPOINT }}
aws_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY}}
aws_bucket: ${{ secrets.AWS_BUCKET }}
source_dir: bun
destination_dir: releases/${{ github.event.workflow_run.head_sha || github.sha }}
- name: Upload to S3 (using tag)
uses: shallwefootball/s3-upload-action@4350529f410221787ccf424e50133cbc1b52704e
with:
endpoint: ${{ secrets.AWS_ENDPOINT }}
aws_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY}}
aws_bucket: ${{ secrets.AWS_BUCKET }}
source_dir: bun
destination_dir: releases/canary
- name: Announce on Discord
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.BUN_DISCORD_GITHUB_CHANNEL_WEBHOOK }}
nodetail: true
color: "#1F6FEB"
title: "New Bun Canary available"
url: https://github.com/oven-sh/bun/commit/${{ github.sha }}
description: |
A new canary build of Bun has been automatically uploaded. To upgrade, run:
```sh
bun upgrade --canary
# bun upgrade --stable <- to downgrade
```

3
.gitignore vendored
View File

@@ -140,5 +140,4 @@ txt.js
x64
yarn.lock
zig-cache
zig-out
test/node.js/upstream
zig-out

12
.gitmodules vendored
View File

@@ -84,9 +84,9 @@ depth = 1
shallow = true
fetchRecurseSubmodules = false
[submodule "zig"]
path = src/deps/zig
url = https://github.com/oven-sh/zig
branch = bun
depth = 1
shallow = true
fetchRecurseSubmodules = false
path = src/deps/zig
url = https://github.com/oven-sh/zig
branch = bun
depth = 1
shallow = true
fetchRecurseSubmodules = false

View File

@@ -2,6 +2,5 @@ src/bun.js/WebKit
src/deps
test/snapshots
test/js/deno
test/node.js
src/react-refresh.js
*.min.js

View File

@@ -5,15 +5,6 @@
"useTabs": false,
"quoteProps": "preserve",
"overrides": [
{
"files": [".vscode/*.json"],
"options": {
"parser": "jsonc",
"quoteProps": "preserve",
"singleQuote": false,
"trailingComma": "all"
}
},
{
"files": ["*.md"],
"options": {

View File

@@ -17,7 +17,7 @@
"${workspaceFolder}/src/deps",
"${workspaceFolder}/src/napi/*",
"${workspaceFolder}/packages/bun-usockets/src",
"${workspaceFolder}/packages/",
"${workspaceFolder}/packages/"
],
"browse": {
"path": [
@@ -30,10 +30,10 @@
"${workspaceFolder}/src/deps/boringssl/include/*",
"${workspaceFolder}/packages/bun-usockets/*",
"${workspaceFolder}/packages/bun-uws/*",
"${workspaceFolder}/src/napi/*",
"${workspaceFolder}/src/napi/*"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ".vscode/cppdb",
"databaseFilename": ".vscode/cppdb"
},
"defines": [
"STATICALLY_LINKED_WITH_JavaScriptCore=1",
@@ -44,12 +44,12 @@
"BUILDING_JSCONLY__",
"USE_FOUNDATION=1",
"ASSERT_ENABLED=1",
"DU_DISABLE_RENAMING=1",
"DU_DISABLE_RENAMING=1"
],
"macFrameworkPath": [],
"compilerPath": "${workspaceFolder}/.vscode/clang++",
"cStandard": "c17",
"cppStandard": "c++20",
"cppStandard": "c++20"
},
{
"name": "BunWithJSCDebug",
@@ -72,7 +72,7 @@
"${workspaceFolder}/src/deps",
"${workspaceFolder}/src/napi/*",
"${workspaceFolder}/packages/bun-usockets/src",
"${workspaceFolder}/packages/",
"${workspaceFolder}/packages/"
],
"browse": {
"path": [
@@ -94,10 +94,10 @@
"${workspaceFolder}/src/deps/boringssl/include/",
"${workspaceFolder}/packages/bun-usockets/",
"${workspaceFolder}/packages/bun-uws/",
"${workspaceFolder}/src/napi",
"${workspaceFolder}/src/napi"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ".vscode/cppdb_debug",
"databaseFilename": ".vscode/cppdb_debug"
},
"defines": [
"STATICALLY_LINKED_WITH_JavaScriptCore=1",
@@ -108,13 +108,13 @@
"BUILDING_JSCONLY__",
"USE_FOUNDATION=1",
"ASSERT_ENABLED=1",
"DU_DISABLE_RENAMING=1",
"DU_DISABLE_RENAMING=1"
],
"macFrameworkPath": [],
"compilerPath": "${workspaceFolder}/.vscode/clang++",
"cStandard": "c17",
"cppStandard": "c++20",
},
"cppStandard": "c++20"
}
],
"version": 4,
"version": 4
}

View File

@@ -28,6 +28,6 @@
"tamasfe.even-better-toml",
// Other
"bierner.comment-tagged-templates",
],
"bierner.comment-tagged-templates"
]
}

416
.vscode/launch.json generated vendored
View File

@@ -18,9 +18,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -33,9 +33,9 @@
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "1",
"BUN_DEBUG_FileReader": "1",
"BUN_DEBUG_FileReader": "1"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -47,9 +47,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "0",
"BUN_GARBAGE_COLLECTOR_LEVEL": "0"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -61,9 +61,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "0",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -75,9 +75,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -89,9 +89,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -104,14 +104,14 @@
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_INSPECT": "ws://localhost:0/?wait=1",
"BUN_INSPECT": "ws://localhost:0/?wait=1"
},
"console": "internalConsole",
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
"action": "openExternally"
}
},
{
"type": "lldb",
@@ -124,14 +124,14 @@
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_INSPECT": "ws://localhost:0/?break=1",
"BUN_INSPECT": "ws://localhost:0/?break=1"
},
"console": "internalConsole",
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
"action": "openExternally"
}
},
// bun run [file]
{
@@ -144,9 +144,9 @@
"env": {
"FORCE_COLOR": "0",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -158,9 +158,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "0",
"BUN_GARBAGE_COLLECTOR_LEVEL": "0"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -172,9 +172,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "0",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -186,9 +186,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -200,9 +200,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -215,14 +215,14 @@
"FORCE_COLOR": "0",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_INSPECT": "ws://localhost:0/?wait=1",
"BUN_INSPECT": "ws://localhost:0/?wait=1"
},
"console": "internalConsole",
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
"action": "openExternally"
}
},
{
"type": "lldb",
@@ -235,14 +235,14 @@
"FORCE_COLOR": "0",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_INSPECT": "ws://localhost:0/?break=1",
"BUN_INSPECT": "ws://localhost:0/?break=1"
},
"console": "internalConsole",
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
"action": "openExternally"
}
},
// bun test [...]
{
@@ -255,9 +255,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -269,9 +269,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "0",
"BUN_GARBAGE_COLLECTOR_LEVEL": "0"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -283,9 +283,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "0",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -297,9 +297,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -311,9 +311,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -326,14 +326,14 @@
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_INSPECT": "ws://localhost:0/?wait=1",
"BUN_INSPECT": "ws://localhost:0/?wait=1"
},
"console": "internalConsole",
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
"action": "openExternally"
}
},
{
"type": "lldb",
@@ -346,29 +346,14 @@
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_INSPECT": "ws://localhost:0/?break=1",
"BUN_INSPECT": "ws://localhost:0/?break=1"
},
"console": "internalConsole",
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
},
// bun exec [...]
{
"type": "lldb",
"request": "launch",
"name": "bun exec [...]",
"program": "${workspaceFolder}/build/bun-debug",
"args": ["exec", "${input:testName}"],
"cwd": "${workspaceFolder}",
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
},
"console": "internalConsole",
"action": "openExternally"
}
},
// bun test [*]
{
@@ -381,9 +366,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -395,9 +380,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "0",
"BUN_GARBAGE_COLLECTOR_LEVEL": "0"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -410,14 +395,14 @@
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_INSPECT": "ws://localhost:0/",
"BUN_INSPECT": "ws://localhost:0/"
},
"console": "internalConsole",
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
"action": "openExternally"
}
},
{
"type": "lldb",
@@ -429,9 +414,9 @@
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
"BUN_GARBAGE_COLLECTOR_LEVEL": "2"
},
"console": "internalConsole",
"console": "internalConsole"
},
{
"type": "lldb",
@@ -440,7 +425,7 @@
"program": "node",
"args": ["src/runner.node.mjs"],
"cwd": "${workspaceFolder}/packages/bun-internal-test",
"console": "internalConsole",
"console": "internalConsole"
},
// Windows: bun test [file]
{
@@ -453,22 +438,22 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_jest",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "1",
},
],
"value": "1"
}
]
},
{
"type": "cppvsdbg",
@@ -480,33 +465,33 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_EventLoop",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_uv",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_SYS",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_PipeWriter",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
},
],
"value": "2"
}
]
},
{
"type": "cppvsdbg",
@@ -518,17 +503,17 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "0",
},
],
"value": "0"
}
]
},
{
"type": "cppvsdbg",
@@ -540,17 +525,17 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "0",
"value": "0"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
},
],
"value": "2"
}
]
},
{
"type": "cppvsdbg",
@@ -562,26 +547,26 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
"value": "2"
},
{
"name": "BUN_INSPECT",
"value": "ws://localhost:0/?wait=1",
},
"value": "ws://localhost:0/?wait=1"
}
],
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
"action": "openExternally"
}
},
{
"type": "cppvsdbg",
@@ -593,26 +578,26 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
"value": "2"
},
{
"name": "BUN_INSPECT",
"value": "ws://localhost:0/?break=1",
},
"value": "ws://localhost:0/?break=1"
}
],
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
"action": "openExternally"
}
},
// Windows: bun run [file]
{
@@ -625,17 +610,17 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
},
],
"value": "2"
}
]
},
{
"type": "cppvsdbg",
@@ -647,14 +632,14 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "0",
},
],
"value": "0"
}
]
},
{
"type": "cppvsdbg",
@@ -666,17 +651,17 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "0",
"value": "0"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
},
],
"value": "2"
}
]
},
{
"type": "cppvsdbg",
@@ -688,26 +673,26 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
"value": "2"
},
{
"name": "BUN_INSPECT",
"value": "ws://localhost:0/?wait=1",
},
"value": "ws://localhost:0/?wait=1"
}
],
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
"action": "openExternally"
}
},
{
"type": "cppvsdbg",
@@ -719,26 +704,26 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
"value": "2"
},
{
"name": "BUN_INSPECT",
"value": "ws://localhost:0/?break=1",
},
"value": "ws://localhost:0/?break=1"
}
],
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
"action": "openExternally"
}
},
// Windows: bun test [...]
{
@@ -751,17 +736,17 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
},
],
"value": "2"
}
]
},
{
"type": "cppvsdbg",
@@ -773,17 +758,17 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "0",
},
],
"value": "0"
}
]
},
{
"type": "cppvsdbg",
@@ -795,17 +780,17 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "0",
"value": "0"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
},
],
"value": "2"
}
]
},
{
"type": "cppvsdbg",
@@ -817,17 +802,17 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
},
],
"value": "2"
}
]
},
{
"type": "cppvsdbg",
@@ -839,17 +824,17 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
},
],
"value": "2"
}
]
},
{
"type": "cppvsdbg",
@@ -861,26 +846,26 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
"value": "2"
},
{
"name": "BUN_INSPECT",
"value": "ws://localhost:0/?wait=1",
},
"value": "ws://localhost:0/?wait=1"
}
],
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
"action": "openExternally"
}
},
{
"type": "cppvsdbg",
@@ -892,49 +877,26 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
"value": "2"
},
{
"name": "BUN_INSPECT",
"value": "ws://localhost:0/?break=1",
},
"value": "ws://localhost:0/?break=1"
}
],
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
},
// Windows: bun exec [...]
{
"type": "cppvsdbg",
"request": "launch",
"name": "Windows: bun exec [...]",
"program": "${workspaceFolder}/build/bun-debug.exe",
"args": ["exec", "${input:testName}"],
"cwd": "${workspaceFolder}",
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
},
],
"action": "openExternally"
}
},
// Windows: bun test [*]
{
@@ -947,17 +909,17 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
},
],
"value": "2"
}
]
},
{
"type": "cppvsdbg",
@@ -969,17 +931,17 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "1",
"value": "1"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "0",
},
],
"value": "0"
}
]
},
{
"type": "cppvsdbg",
@@ -991,26 +953,26 @@
"environment": [
{
"name": "FORCE_COLOR",
"value": "1",
"value": "1"
},
{
"name": "BUN_DEBUG_QUIET_LOGS",
"value": "0",
"value": "0"
},
{
"name": "BUN_GARBAGE_COLLECTOR_LEVEL",
"value": "2",
"value": "2"
},
{
"name": "BUN_INSPECT",
"value": "ws://localhost:0/",
},
"value": "ws://localhost:0/"
}
],
"serverReadyAction": {
"pattern": "https://debug.bun.sh/#localhost:([0-9]+)/",
"uriFormat": "https://debug.bun.sh/#ws://localhost:%s/",
"action": "openExternally",
},
"action": "openExternally"
}
},
{
"type": "cppvsdbg",
@@ -1019,19 +981,19 @@
"program": "node",
"args": ["src/runner.node.mjs"],
"cwd": "${workspaceFolder}/packages/bun-internal-test",
"console": "internalConsole",
},
"console": "internalConsole"
}
],
"inputs": [
{
"id": "commandLine",
"type": "promptString",
"description": "Usage: bun [...]",
"description": "Usage: bun [...]"
},
{
"id": "testName",
"type": "promptString",
"description": "Usage: bun test [...]",
},
],
"description": "Usage: bun test [...]"
}
]
}

56
.vscode/settings.json vendored
View File

@@ -13,8 +13,7 @@
"node_modules": true,
".git": true,
"src/bun.js/WebKit": true,
"src/deps/*/**": true,
"test/node.js/upstream": true,
"src/deps/*/**": true
},
"search.followSymlinks": false,
"search.useIgnoreFiles": true,
@@ -35,7 +34,7 @@
"[zig]": {
"editor.tabSize": 4,
"editor.useTabStops": false,
"editor.defaultFormatter": "ziglang.vscode-zig",
"editor.defaultFormatter": "ziglang.vscode-zig"
},
// C++
@@ -43,41 +42,40 @@
"cmake.configureOnOpen": false,
"C_Cpp.errorSquiggles": "enabled",
"[cpp]": {
"editor.defaultFormatter": "xaver.clang-format",
"editor.defaultFormatter": "xaver.clang-format"
},
"[c]": {
"editor.defaultFormatter": "xaver.clang-format",
"editor.defaultFormatter": "xaver.clang-format"
},
"[h]": {
"editor.defaultFormatter": "xaver.clang-format",
"editor.defaultFormatter": "xaver.clang-format"
},
// JavaScript
"prettier.enable": true,
"prettier.configPath": ".prettierrc",
"eslint.workingDirectories": ["${workspaceFolder}/packages/bun-types"],
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// TypeScript
"typescript.tsdk": "${workspaceFolder}/node_modules/typescript/lib",
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// JSON
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// Markdown
@@ -90,23 +88,23 @@
"editor.quickSuggestions": {
"comments": "off",
"strings": "off",
"other": "off",
},
"other": "off"
}
},
// TOML
"[toml]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// YAML
"[yaml]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// Docker
"[dockerfile]": {
"editor.formatOnSave": false,
"editor.formatOnSave": false
},
// Files
@@ -120,13 +118,23 @@
"**/*.xcworkspacedata": true,
"**/*.xcscheme": true,
"**/*.xcodeproj": true,
"src/bun.js/WebKit": true,
"src/deps/libarchive": true,
"src/deps/mimalloc": true,
"src/deps/s2n-tls": true,
"src/deps/boringssl": true,
"src/deps/openssl": true,
"src/deps/uws": true,
"src/deps/zlib": true,
"src/deps/lol-html": true,
"src/deps/c-ares": true,
"src/deps/tinycc": true,
"src/deps/zstd": true,
"**/*.i": true,
// uws WebSocket.cpp conflicts with webcore WebSocket.cpp
"packages/bun-uws/fuzzing": true,
"packages/bun-uws/fuzzing/seed-corpus": true
},
"files.associations": {
"*.idl": "cpp",
"*.idl": "cpp"
},
"C_Cpp.files.exclude": {
"**/.vscode": true,
@@ -144,6 +152,6 @@
"WebKit/WebCore": true,
"WebKit/WebDriver": true,
"WebKit/WebKitBuild": true,
"WebKit/WebInspectorUI": true,
},
"WebKit/WebInspectorUI": true
}
}

18
.vscode/tasks.json vendored
View File

@@ -6,13 +6,13 @@
"label": "Install Dependencies",
"command": "scripts/all-dependencies.sh",
"windows": {
"command": "scripts/all-dependencies.ps1",
"command": "scripts/all-dependencies.ps1"
},
"icon": {
"id": "arrow-down",
"id": "arrow-down"
},
"options": {
"cwd": "${workspaceFolder}",
"cwd": "${workspaceFolder}"
},
},
{
@@ -21,13 +21,13 @@
"dependsOn": ["Install Dependencies"],
"command": "scripts/setup.sh",
"windows": {
"command": "scripts/setup.ps1",
"command": "scripts/setup.ps1"
},
"icon": {
"id": "check",
"id": "check"
},
"options": {
"cwd": "${workspaceFolder}",
"cwd": "${workspaceFolder}"
},
},
{
@@ -37,10 +37,10 @@
"command": "bun",
"args": ["run", "build"],
"icon": {
"id": "gear",
"id": "gear"
},
"options": {
"cwd": "${workspaceFolder}",
"cwd": "${workspaceFolder}"
},
"isBuildCommand": true,
"runOptions": {
@@ -48,5 +48,5 @@
"reevaluateOnRerun": true,
},
},
],
]
}

View File

@@ -2,24 +2,12 @@ cmake_minimum_required(VERSION 3.22)
cmake_policy(SET CMP0091 NEW)
cmake_policy(SET CMP0067 NEW)
set(Bun_VERSION "1.1.8")
set(WEBKIT_TAG 413f6fc119cfca98d5063049ce444cc4eb56f0a4)
set(Bun_VERSION "1.1.1")
set(WEBKIT_TAG 2475726ed0329ab2d2a92daf73e12ee1e485d575)
set(BUN_WORKDIR "${CMAKE_CURRENT_BINARY_DIR}")
message(STATUS "Configuring Bun ${Bun_VERSION} in ${BUN_WORKDIR}")
set(CMAKE_COLOR_DIAGNOSTICS ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_STANDARD_REQUIRED ON)
# WebKit uses -std=gnu++20 on non-macOS non-Windows
# If we do not set this, it will crash at startup on the first memory allocation.
if(NOT WIN32 AND NOT APPLE)
set(CMAKE_CXX_EXTENSIONS ON)
endif()
# --- Build Type ---
if(NOT CMAKE_BUILD_TYPE)
message(WARNING "No CMAKE_BUILD_TYPE value specified, defaulting to Debug.\nSet a build type with -DCMAKE_BUILD_TYPE=<Debug|Release>")
@@ -63,7 +51,11 @@ endif()
# --- MacOS SDK ---
if(APPLE AND DEFINED ENV{CI})
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0")
if(ARCH STREQUAL "x86_64")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14")
else()
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0")
endif()
endif()
if(APPLE AND NOT CMAKE_OSX_DEPLOYMENT_TARGET)
@@ -101,7 +93,7 @@ endif()
# any case possible. Sorry for the complexity...
#
# Bun and WebKit must be compiled with the same compiler, so we do as much as we can to ensure that
# the compiler used for the prebuilt WebKit is the same as we install as a dependency.
# the compiler used for the prebuilt WebKit, LLVM 16, is the one that we detect in this process.
#
# It has to be done before project() is called, so that CMake doesnt pick a compiler for us, but even then
# we do some extra work afterwards to double-check, and we will rerun BUN_FIND_LLVM if the compiler did not match.
@@ -222,6 +214,12 @@ else()
)
endif()
set(CMAKE_COLOR_DIAGNOSTICS ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_STANDARD_REQUIRED ON)
project(Bun VERSION "${Bun_VERSION}")
# if(MSVC)
@@ -557,8 +555,6 @@ else()
add_compile_definitions("BUN_DEBUG=1")
set(ASSERT_ENABLED "1")
endif()
message(STATUS "Using WebKit from ${WEBKIT_DIR}")
else()
if(NOT EXISTS "${WEBKIT_DIR}/lib/${libWTF}.${STATIC_LIB_EXT}" OR NOT EXISTS "${WEBKIT_DIR}/lib/${libJavaScriptCore}.${STATIC_LIB_EXT}")
if(WEBKIT_DIR MATCHES "src/bun.js/WebKit$")
@@ -740,7 +736,7 @@ if(NOT NO_CODEGEN)
OUTPUT ${BUN_IDENTIFIER_CACHE_OUT}
MAIN_DEPENDENCY "${BUN_SRC}/js_lexer/identifier_data.zig"
DEPENDS "${BUN_SRC}/js_lexer/identifier_cache.zig"
COMMAND ${ZIG_COMPILER} run "--zig-lib-dir" "${ZIG_LIB_DIR}" "${BUN_SRC}/js_lexer/identifier_data.zig"
COMMAND ${ZIG_COMPILER} run "${BUN_SRC}/js_lexer/identifier_data.zig"
VERBATIM
COMMENT "Building Identifier Cache"
)
@@ -765,7 +761,6 @@ if(NOT NO_CODEGEN)
"${BUN_SRC}/js/node/*.ts"
"${BUN_SRC}/js/thirdparty/*.js"
"${BUN_SRC}/js/thirdparty/*.ts"
"${BUN_SRC}/js/internal-for-testing.ts"
)
file(GLOB CODEGEN_FILES ${CONFIGURE_DEPENDS} "${BUN_CODEGEN_SRC}/*.ts")
@@ -1017,7 +1012,7 @@ endif()
# --- clang and linker flags ---
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
if(NOT WIN32)
target_compile_options(${bun} PUBLIC -O0 -g -g3 -ggdb -gdwarf-4
target_compile_options(${bun} PUBLIC -g3 -O0 -gdwarf-4
-Werror=return-type
-Werror=return-stack-address
-Werror=implicit-function-declaration
@@ -1064,8 +1059,8 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
list(APPEND LTO_LINK_FLAG "/LTCG")
endif()
target_compile_options(${bun} PUBLIC /O2 ${LTO_FLAG} /DEBUG:FULL)
target_link_options(${bun} PUBLIC ${LTO_LINK_FLAG} /DEBUG:FULL)
target_compile_options(${bun} PUBLIC /O2 ${LTO_FLAG} /DEBUG /Z7)
target_link_options(${bun} PUBLIC ${LTO_LINK_FLAG} /DEBUG)
endif()
endif()
@@ -1105,15 +1100,15 @@ else()
target_compile_options(${bun} PUBLIC
-fPIC
-mtune=${CPU_TARGET}
-fconstexpr-steps=2542484
-fconstexpr-depth=54
-fconstexpr-steps=1271242
-fconstexpr-depth=27
-fno-exceptions
-fvisibility=hidden
-fvisibility-inlines-hidden
-fno-rtti
-fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer
)
string(APPEND CMAKE_CXX_FLAGS " -std=c++2a")
endif()
if(APPLE)
@@ -1132,6 +1127,7 @@ if(UNIX AND NOT APPLE)
"-fuse-ld=lld"
"-static-libstdc++"
"-static-libgcc"
"-fuse-ld=lld"
"-Wl,-z,now"
"-Wl,--as-needed"
"-Wl,--gc-sections"
@@ -1141,21 +1137,19 @@ if(UNIX AND NOT APPLE)
"-Wl,--wrap=stat64"
"-Wl,--wrap=pow"
"-Wl,--wrap=exp"
"-Wl,--wrap=expf"
"-Wl,--wrap=log"
"-Wl,--wrap=log2"
"-Wl,--wrap=lstat"
"-Wl,--wrap=stat64"
"-Wl,--wrap=stat"
"-Wl,--wrap=fstat"
"-Wl,--wrap=fstatat"
"-Wl,--wrap=lstat64"
"-Wl,--wrap=stat64"
"-Wl,--wrap=fstat64"
"-Wl,--wrap=fstatat64"
"-Wl,--wrap=mknod"
"-Wl,--wrap=mknodat"
"-Wl,--wrap=statx"
"-Wl,--wrap=fmod"
"-Wl,--compress-debug-sections=zlib"
"-Bsymbolics-functions"
"-rdynamic"

View File

@@ -1,313 +1,76 @@
Configuring a development environment for Bun can take 10-30 minutes depending on your internet connection and computer speed. You will need ~10GB of free disk space for the repository and build artifacts.
# Contributing to Bun
If you are using Windows, please refer to [this guide](/docs/project/building-windows)
> **Important:** All contributions need test coverage. If you are adding a new feature, please add a test. If you are fixing a bug, please add a test that fails before your fix and passes after your fix.
## Install Dependencies
## Bun's codebase
Using your system's package manager, install Bun's dependencies:
Bun is written mostly in Zig, but WebKit & JavaScriptCore (the JavaScript engine) is written in C++.
{% codetabs %}
Today (February 2023), Bun's codebase has five distinct parts:
```bash#macOS (Homebrew)
$ brew install automake ccache cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rust ruby
```
- JavaScript, JSX, & TypeScript transpiler, module resolver, and related code
- JavaScript runtime ([`src/bun.js/`](src/bun.js/))
- JavaScript runtime bindings ([`src/bun.js/bindings/**/*.cpp`](src/bun.js/bindings/))
- Package manager ([`src/install/`](src/install/))
- Shared utilities ([`src/string_immutable.zig`](src/string_immutable.zig))
```bash#Ubuntu/Debian
$ sudo apt install curl wget lsb-release software-properties-common cargo ccache cmake git golang libtool ninja-build pkg-config rustc ruby-full xz-utils
```
The JavaScript transpiler & module resolver is mostly independent from the runtime. It predates the runtime and is entirely in Zig. The JavaScript parser is mostly in [`src/js_parser.zig`](src/js_parser.zig). The JavaScript AST data structures are mostly in [`src/js_ast.zig`](src/js_ast.zig). The JavaScript lexer is in [`src/js_lexer.zig`](src/js_lexer.zig). A lot of this code started as a port of esbuild's equivalent code from Go to Zig, but has had many small changes since then.
```bash#Arch
$ sudo pacman -S base-devel ccache cmake git go libiconv libtool make ninja pkg-config python rust sed unzip ruby
```
## Getting started
```bash#Fedora
$ sudo dnf install cargo ccache cmake git golang libtool ninja-build pkg-config rustc ruby libatomic-static libstdc++-static sed unzip which libicu-devel 'perl(Math::BigInt)'
```
Please refer to [Bun's Development Guide](https://bun.sh/docs/project/contributing) to get your dev environment setup!
```bash#openSUSE Tumbleweed
$ sudo zypper install go cmake ninja automake git rustup && rustup toolchain install stable
```
## Memory management in Bun
{% /codetabs %}
For the Zig code, please:
> **Note**: The Zig compiler is automatically installed and updated by the build scripts. Manual installation is not required.
1. Do your best to avoid dynamically allocating memory.
2. If we need to allocate memory, carefully consider the owner of that memory. If it's a JavaScript object, it will need a finalizer. If it's in Zig, it will need to be freed either via an arena or manually.
3. Prefer arenas over manual memory management. Manually freeing memory is leak & crash prone.
4. If the memory needs to be accessed across threads, use `bun.default_allocator`. Mimalloc threadlocal heaps are not safe to free across threads.
Before starting, you will need to already have a release build of Bun installed, as we use our bundler to transpile and minify our code, as well as for code generation scripts.
The JavaScript transpiler has special-handling for memory management. The parser allocates into a single arena and the memory is recycled after each parse.
{% codetabs %}
## JavaScript runtime
```bash#Native
$ curl -fsSL https://bun.sh/install | bash
```
Most of Bun's JavaScript runtime code lives in [`src/bun.js`](src/bun.js).
```bash#npm
$ npm install -g bun
```
### Calling C++ from Zig & Zig from C++
```bash#Homebrew
$ brew tap oven-sh/bun
$ brew install bun
```
TODO: document this (see [`bindings.zig`](src/bun.js/bindings/bindings.zig) and [`bindings.cpp`](src/bun.js/bindings/bindings.cpp) for now)
{% /codetabs %}
### Adding a new JavaScript class
## Install LLVM
1. Add a new file in [`src/bun.js/*.classes.ts`](src/bun.js) to define the instance and static methods for the class.
2. Add a new file in [`src/bun.js/**/*.zig`](src/bun.js) and expose the struct in [`src/bun.js/generated_classes_list.zig`](src/bun.js/generated_classes_list.zig)
3. Run `make codegen`
Bun requires LLVM 16 (`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:
Copy from examples like `Subprocess` or `Response`.
{% codetabs %}
### ESM Modules and Builtins JS
```bash#macOS (Homebrew)
$ brew install llvm@16
```
Bun implements ESM modules in a mix of native code and JavaScript.
```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 -- 16 all
```
Several Node.js modules are implemented in JavaScript and loosely based on browserify polyfills.
```bash#Arch
$ sudo pacman -S llvm clang lld
```
Builtin modules in Bun are located in [`src/js`](src/js/). These files are transpiled and support a JavaScriptCore-only syntax for internal slots, which is explained further in [`src/js/README.md`](src/js/README.md).
```bash#Fedora
$ sudo dnf install 'dnf-command(copr)'
$ sudo dnf copr enable -y @fedora-llvm-team/llvm-snapshots
$ sudo dnf install llvm clang lld
```
Native C++ modules are in `src/bun.js/modules/`.
```bash#openSUSE Tumbleweed
$ sudo zypper install clang16 lld16 llvm16
```
The module loader is in [`src/bun.js/module_loader.zig`](src/bun.js/module_loader.zig).
{% /codetabs %}
### Memory management in Bun's JavaScript runtime
If none of the above solutions apply, you will have to install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-16.0.6).
TODO: fill this out (for now, use `JSC.Strong` in most cases)
Make sure Clang/LLVM 16 is in your path:
### Strings
```bash
$ which clang-16
```
TODO: fill this out (for now, use `JSValue.toSlice()` in most cases)
If not, run this to manually add it:
#### JavaScriptCore C API
{% codetabs %}
Do not copy from examples leveraging the JavaScriptCore C API. Please do not use this in new code. We will not accept PRs that add new code that uses the JavaScriptCore C API.
```bash#macOS (Homebrew)
# use fish_add_path if you're using fish
# use path+="$(brew --prefix llvm@16)/bin" if you are using zsh
$ export PATH="$(brew --prefix llvm@16)/bin:$PATH"
```
## Testing
```bash#Arch
# use fish_add_path if you're using fish
$ export PATH="$PATH:/usr/lib/llvm16/bin"
```
{% /codetabs %}
> ⚠️ Ubuntu distributions may require installation of the C++ standard library independently. See the [troubleshooting section](#span-file-not-found-on-ubuntu) for more information.
## Building Bun
After cloning the repository, run the following command to run the first build. This may take a while as it will clone submodules and build dependencies.
```bash
$ bun setup
```
The binary will be located at `./build/bun-debug`. It is recommended to add this to your `$PATH`. To verify the build worked, let's print the version number on the development build of Bun.
```bash
$ build/bun-debug --version
x.y.z_debug
```
To rebuild, you can invoke `bun run build`
```bash
$ bun run build
```
These two scripts, `setup` and `build`, are aliases to do roughly the following:
```bash
$ ./scripts/setup.sh
$ cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
$ ninja -C build # 'bun run build' runs just this
```
Advanced users can pass CMake flags to customize the build.
## VSCode
VSCode is the recommended IDE for working on Bun, as it has been configured. Once opening, you can run `Extensions: Show Recommended Extensions` to install the recommended extensions for Zig and C++. ZLS is automatically configured.
If you use a different editor, make sure that you tell ZLS to use the automatically installed Zig compiler, which is located at `./.cache/zig/zig.exe`. The filename is `zig.exe` so that it works as expected on Windows, but it still works on macOS/Linux (it just has a surprising file extension).
We recommend adding `./build` to your `$PATH` so that you can run `bun-debug` in your terminal:
```sh
$ bun-debug
```
## Code generation scripts
Several code generation scripts are used during Bun's build process. These are run automatically when changes are made to certain files.
In particular, these are:
- `./src/codegen/generate-jssink.ts` -- Generates `build/codegen/JSSink.cpp`, `build/codegen/JSSink.h` which implement various classes for interfacing with `ReadableStream`. This is internally how `FileSink`, `ArrayBufferSink`, `"type": "direct"` streams and other code related to streams works.
- `./src/codegen/generate-classes.ts` -- Generates `build/codegen/ZigGeneratedClasses*`, which generates Zig & C++ bindings for JavaScriptCore classes implemented in Zig. In `**/*.classes.ts` files, we define the interfaces for various classes, methods, prototypes, getters/setters etc which the code generator reads to generate boilerplate code implementing the JavaScript objects in C++ and wiring them up to Zig
- `./src/codegen/bundle-modules.ts` -- Bundles built-in modules like `node:fs`, `bun:ffi` into files we can include in the final binary. In development, these can be reloaded without rebuilding Zig (you still need to run `bun run build`, but it re-reads the transpiled files from disk afterwards). In release builds, these are embedded into the binary.
- `./src/codegen/bundle-functions.ts` -- Bundles globally-accessible functions implemented in JavaScript/TypeScript like `ReadableStream`, `WritableStream`, and a handful more. These are used similarly to the builtin modules, but the output more closely aligns with what WebKit/Safari does for Safari's built-in functions so that we can copy-paste the implementations from WebKit as a starting point.
## Modifying ESM modules
Certain modules like `node:fs`, `node:stream`, `bun:sqlite`, and `ws` are implemented in JavaScript. These live in `src/js/{node,bun,thirdparty}` files and are pre-bundled using Bun.
## Release build
To compile a release build of Bun, run:
```bash
$ bun run build:release
```
The binary will be located at `./build-release/bun` and `./build-release/bun-profile`.
### Download release build from pull requests
To save you time spent building a release build locally, we provide a way to run release builds from pull requests. This is useful for manully testing changes in a release build before they are merged.
To run a release build from a pull request, you can use the `bun-pr` npm package:
```sh
bunx bun-pr pr-number
bunx bun-pr branch/branch-name
bunx bun-pr "https://github.com/oven-sh/bun/pull/1234566"
```
This will download the release build from the pull request and add it to `$PATH` as `bun-${pr-number}`. You can then run the build with `bun-${pr-number}`.
```sh
bun-1234566 --version
```
This works by downloading the release build from the GitHub Actions artifacts on the linked pull request. You may need the `gh` CLI installed to authenticate with GitHub.
## Valgrind
On Linux, valgrind can help find memory issues.
Keep in mind:
- JavaScriptCore doesn't support valgrind. It will report spurious errors.
- Valgrind is slow
- Mimalloc will sometimes cause spurious errors when debug build is enabled
You'll need a very recent version of Valgrind due to DWARF 5 debug symbols. You may need to manually compile Valgrind instead of using it from your Linux package manager.
`--fair-sched=try` is necessary if running multithreaded code in Bun (such as the bundler). Otherwise it will hang.
```bash
$ valgrind --fair-sched=try --track-origins=yes bun-debug <args>
```
## Building WebKit locally + Debug mode of JSC
{% callout %}
**TODO**: This is out of date. TLDR is pass `-DUSE_DEBUG_JSC=1` or `-DWEBKIT_DIR=...` to CMake. it will probably need more fiddling. ask @paperdave if you need this.
{% /callout %}
WebKit is not cloned by default (to save time and disk space). To clone and build WebKit locally, run:
```bash
# once you run this, `make submodule` can be used to automatically
# update WebKit and the other submodules
$ git submodule update --init --depth 1 --checkout src/bun.js/WebKit
# to make a jsc release build
$ make jsc
# JSC debug build does not work perfectly with Bun yet, this is actively being
# worked on and will eventually become the default.
$ make jsc-build-linux-compile-debug cpp
$ make jsc-build-mac-compile-debug cpp
```
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.
## Troubleshooting
### 'span' file not found on Ubuntu
> ⚠️ Please note that the instructions below are specific to issues occurring on Ubuntu. It is unlikely that the same issues will occur on other Linux distributions.
The Clang compiler typically uses the `libstdc++` C++ standard library by default. `libstdc++` is the default C++ Standard Library implementation provided by the GNU Compiler Collection (GCC). While Clang may link against the `libc++` library, this requires explicitly providing the `-stdlib` flag when running Clang.
Bun relies on C++20 features like `std::span`, which are not available in GCC versions lower than 11. GCC 10 doesn't have all of the C++20 features implemented. As a result, running `make setup` may fail with the following error:
```
fatal error: 'span' file not found
#include <span>
^~~~~~
```
The issue may manifest when initially running `bun setup` as Clang being unable to compile a simple program:
```
The C++ compiler
"/usr/bin/clang++-16"
is not able to compile a simple test program.
```
To fix the error, we need to update the GCC version to 11. To do this, we'll need to check if the latest version is available in the distribution's official repositories or use a third-party repository that provides GCC 11 packages. Here are general steps:
```bash
$ sudo apt update
$ sudo apt install gcc-11 g++-11
# If the above command fails with `Unable to locate package gcc-11` we need
# to add the APT repository
$ sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
# Now run `apt install` again
$ sudo apt install gcc-11 g++-11
```
Now, we need to set GCC 11 as the default compiler:
```bash
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 100
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 100
```
### libarchive
If you see an error on macOS when compiling `libarchive`, run:
```bash
$ brew install pkg-config
```
### macOS `library not found for -lSystem`
If you see this error when compiling, run:
```bash
$ xcode-select --install
```
## Cannot find `libatomic.a`
Bun defaults to linking `libatomic` statically, as not all systems have it. If you are building on a distro that does not have a static libatomic available, you can run the following command to enable dynamic linking:
```bash
$ bun setup -DUSE_STATIC_LIBATOMIC=OFF
```
The built version of Bun may not work on other systems if compiled this way.
See [`test/README.md`](test/README.md) for information on how to run tests.

View File

@@ -16,7 +16,7 @@ ARG BUILD_MACHINE_ARCH=x86_64
ARG BUILDARCH=amd64
ARG TRIPLET=${ARCH}-linux-gnu
ARG GIT_SHA=""
ARG BUN_VERSION="bun-v1.1.4"
ARG BUN_VERSION="bun-v1.0.30"
ARG BUN_DOWNLOAD_URL_BASE="https://pub-5e11e972747a44bf9aaf9394f185a982.r2.dev/releases/${BUN_VERSION}"
ARG CANARY=0
ARG ASSERTIONS=OFF
@@ -51,10 +51,10 @@ ENV CPU_TARGET=${CPU_TARGET}
ENV BUILDARCH=${BUILDARCH}
ENV BUN_DEPS_OUT_DIR=${BUN_DEPS_OUT_DIR}
ENV CXX=clang++-${LLVM_VERSION}
ENV CC=clang-${LLVM_VERSION}
ENV AR=/usr/bin/llvm-ar-${LLVM_VERSION}
ENV LD=lld-${LLVM_VERSION}
ENV CXX=clang++-16
ENV CC=clang-16
ENV AR=/usr/bin/llvm-ar-16
ENV LD=lld-16
ENV SCCACHE_BUCKET=${SCCACHE_BUCKET}
ENV SCCACHE_REGION=${SCCACHE_REGION}
@@ -63,7 +63,8 @@ ENV SCCACHE_ENDPOINT=${SCCACHE_ENDPOINT}
ENV AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
ENV AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
RUN install_packages \
RUN apt-get update -y \
&& install_packages \
ca-certificates \
curl \
gnupg \
@@ -87,8 +88,6 @@ RUN install_packages \
lld-${LLVM_VERSION} \
lldb-${LLVM_VERSION} \
clangd-${LLVM_VERSION} \
libc++-${LLVM_VERSION}-dev \
libc++abi-${LLVM_VERSION}-dev \
make \
cmake \
ninja-build \
@@ -105,16 +104,14 @@ RUN install_packages \
perl \
python3 \
ruby \
ruby-dev \
golang \
nodejs && \
for f in /usr/lib/llvm-${LLVM_VERSION}/bin/*; do ln -sf "$f" /usr/bin; done \
&& ln -sf /usr/bin/clang-${LLVM_VERSION} /usr/bin/clang \
&& ln -sf /usr/bin/clang++-${LLVM_VERSION} /usr/bin/clang++ \
&& ln -sf /usr/bin/lld-${LLVM_VERSION} /usr/bin/lld \
&& ln -sf /usr/bin/lldb-${LLVM_VERSION} /usr/bin/lldb \
&& ln -sf /usr/bin/clangd-${LLVM_VERSION} /usr/bin/clangd \
&& ln -sf /usr/bin/llvm-ar-${LLVM_VERSION} /usr/bin/llvm-ar \
nodejs \
&& ln -s /usr/bin/clang-${LLVM_VERSION} /usr/bin/clang \
&& ln -s /usr/bin/clang++-${LLVM_VERSION} /usr/bin/clang++ \
&& ln -s /usr/bin/lld-${LLVM_VERSION} /usr/bin/lld \
&& ln -s /usr/bin/lldb-${LLVM_VERSION} /usr/bin/lldb \
&& ln -s /usr/bin/clangd-${LLVM_VERSION} /usr/bin/clangd \
&& ln -s /usr/bin/llvm-ar-${LLVM_VERSION} /usr/bin/llvm-ar \
&& arch="$(dpkg --print-architecture)" \
&& case "${arch##*-}" in \
amd64) variant="x64";; \
@@ -141,8 +138,6 @@ ARG BUILD_MACHINE_ARCH
ARG ZIG_FOLDERNAME=zig-linux-${BUILD_MACHINE_ARCH}-${ZIG_VERSION}
ARG ZIG_FILENAME=${ZIG_FOLDERNAME}.tar.xz
ARG ZIG_URL="https://ziglang.org/builds/${ZIG_FILENAME}"
ARG ZIG_LOCAL_CACHE_DIR=/zig-cache
ENV ZIG_LOCAL_CACHE_DIR=${ZIG_LOCAL_CACHE_DIR}
WORKDIR $GITHUB_WORKSPACE
@@ -157,18 +152,14 @@ FROM bun-base as c-ares
ARG BUN_DIR
ARG CPU_TARGET
ENV CPU_TARGET=${CPU_TARGET}
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
ENV CCACHE_DIR=/ccache
COPY Makefile ${BUN_DIR}/Makefile
COPY src/deps/c-ares ${BUN_DIR}/src/deps/c-ares
WORKDIR $BUN_DIR
RUN --mount=type=cache,target=${CCACHE_DIR} \
cd $BUN_DIR \
&& make c-ares \
&& rm -rf ${BUN_DIR}/src/deps/c-ares ${BUN_DIR}/Makefile
RUN --mount=type=cache,target=/ccache cd $BUN_DIR && make c-ares && rm -rf ${BUN_DIR}/src/deps/c-ares ${BUN_DIR}/Makefile
FROM bun-base as lolhtml
@@ -181,14 +172,10 @@ ENV CPU_TARGET=${CPU_TARGET}
COPY Makefile ${BUN_DIR}/Makefile
COPY src/deps/lol-html ${BUN_DIR}/src/deps/lol-html
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
ENV CCACHE_DIR=/ccache
RUN --mount=type=cache,target=${CCACHE_DIR} \
export PATH=$PATH:$HOME/.cargo/bin \
&& cd ${BUN_DIR} \
&& make lolhtml \
&& rm -rf src/deps/lol-html Makefile
RUN --mount=type=cache,target=/ccache export PATH=$PATH:$HOME/.cargo/bin && cd ${BUN_DIR} && \
make lolhtml && rm -rf src/deps/lol-html Makefile
FROM bun-base as mimalloc
@@ -200,13 +187,10 @@ ENV CPU_TARGET=${CPU_TARGET}
COPY Makefile ${BUN_DIR}/Makefile
COPY src/deps/mimalloc ${BUN_DIR}/src/deps/mimalloc
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
ENV CCACHE_DIR=/ccache
RUN --mount=type=cache,target=${CCACHE_DIR} \
cd ${BUN_DIR} \
&& make mimalloc \
&& rm -rf src/deps/mimalloc Makefile
RUN --mount=type=cache,target=/ccache cd ${BUN_DIR} && \
make mimalloc && rm -rf src/deps/mimalloc Makefile;
FROM bun-base as mimalloc-debug
@@ -218,39 +202,32 @@ ENV CPU_TARGET=${CPU_TARGET}
COPY Makefile ${BUN_DIR}/Makefile
COPY src/deps/mimalloc ${BUN_DIR}/src/deps/mimalloc
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
ENV CCACHE_DIR=/ccache
RUN --mount=type=cache,target=${CCACHE_DIR} \
cd ${BUN_DIR} \
&& make mimalloc-debug \
&& rm -rf src/deps/mimalloc Makefile
RUN --mount=type=cache,target=/ccache cd ${BUN_DIR} && \
make mimalloc-debug && rm -rf src/deps/mimalloc Makefile;
FROM bun-base as zlib
ARG BUN_DIR
ARG CPU_TARGET
ENV CPU_TARGET=${CPU_TARGET}
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
ENV CCACHE_DIR=/ccache
COPY Makefile ${BUN_DIR}/Makefile
COPY src/deps/zlib ${BUN_DIR}/src/deps/zlib
WORKDIR $BUN_DIR
RUN --mount=type=cache,target=${CCACHE_DIR} \
cd $BUN_DIR \
&& make zlib \
&& rm -rf src/deps/zlib Makefile
RUN --mount=type=cache,target=/ccache cd $BUN_DIR && \
make zlib && rm -rf src/deps/zlib Makefile
FROM bun-base as libarchive
ARG BUN_DIR
ARG CPU_TARGET
ENV CPU_TARGET=${CPU_TARGET}
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
ENV CCACHE_DIR=/ccache
RUN install_packages autoconf automake libtool pkg-config
@@ -259,10 +236,8 @@ COPY src/deps/libarchive ${BUN_DIR}/src/deps/libarchive
WORKDIR $BUN_DIR
RUN --mount=type=cache,target=${CCACHE_DIR} \
cd $BUN_DIR \
&& make libarchive \
&& rm -rf src/deps/libarchive Makefile
RUN --mount=type=cache,target=/ccache cd $BUN_DIR && \
make libarchive && rm -rf src/deps/libarchive Makefile
FROM bun-base as tinycc
@@ -286,13 +261,9 @@ COPY src/deps/boringssl ${BUN_DIR}/src/deps/boringssl
WORKDIR $BUN_DIR
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
ENV CCACHE_DIR=/ccache
RUN --mount=type=cache,target=${CCACHE_DIR} \
cd ${BUN_DIR} \
&& make boringssl \
&& rm -rf src/deps/boringssl Makefile
RUN --mount=type=cache,target=/ccache cd ${BUN_DIR} && make boringssl && rm -rf src/deps/boringssl Makefile
FROM bun-base as base64
@@ -315,17 +286,14 @@ ARG BUN_DIR
ARG CPU_TARGET
ENV CPU_TARGET=${CPU_TARGET}
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
ENV CCACHE_DIR=/ccache
COPY Makefile ${BUN_DIR}/Makefile
COPY src/deps/zstd ${BUN_DIR}/src/deps/zstd
WORKDIR $BUN_DIR
RUN --mount=type=cache,target=${CCACHE_DIR} \
cd $BUN_DIR \
&& make zstd
RUN --mount=type=cache,target=/ccache cd $BUN_DIR && make zstd
FROM bun-base as ls-hpack
@@ -334,17 +302,14 @@ ARG BUN_DIR
ARG CPU_TARGET
ENV CPU_TARGET=${CPU_TARGET}
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
ENV CCACHE_DIR=/ccache
COPY Makefile ${BUN_DIR}/Makefile
COPY src/deps/ls-hpack ${BUN_DIR}/src/deps/ls-hpack
WORKDIR $BUN_DIR
RUN --mount=type=cache,target=${CCACHE_DIR} \
cd $BUN_DIR \
&& make lshpack
RUN --mount=type=cache,target=/ccache cd $BUN_DIR && make lshpack
FROM bun-base-with-zig as bun-identifier-cache
@@ -359,9 +324,9 @@ WORKDIR $BUN_DIR
COPY src/js_lexer/identifier_data.zig ${BUN_DIR}/src/js_lexer/identifier_data.zig
COPY src/js_lexer/identifier_cache.zig ${BUN_DIR}/src/js_lexer/identifier_cache.zig
RUN --mount=type=cache,target=${ZIG_LOCAL_CACHE_DIR} \
cd $BUN_DIR \
&& zig run src/js_lexer/identifier_data.zig
RUN cd $BUN_DIR \
&& zig run src/js_lexer/identifier_data.zig \
&& rm -rf zig-cache
FROM bun-base as bun-node-fallbacks
@@ -402,10 +367,9 @@ COPY src ${BUN_DIR}/src
COPY CMakeLists.txt ${BUN_DIR}/CMakeLists.txt
COPY src/deps/boringssl/include ${BUN_DIR}/src/deps/boringssl/include
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
ENV CCACHE_DIR=/ccache
RUN --mount=type=cache,target=${CCACHE_DIR} mkdir ${BUN_DIR}/build \
RUN --mount=type=cache,target=/ccache mkdir ${BUN_DIR}/build \
&& cd ${BUN_DIR}/build \
&& mkdir -p tmp_modules tmp_functions js codegen \
&& cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DUSE_LTO=ON -DUSE_DEBUG_JSC=${ASSERTIONS} -DBUN_CPP_ONLY=1 -DWEBKIT_DIR=/build/bun/bun-webkit -DCANARY=${CANARY} -DZIG_COMPILER=system \
@@ -423,8 +387,7 @@ COPY src/api ${BUN_DIR}/src/api
WORKDIR $BUN_DIR
# TODO: move away from Makefile entirely
RUN --mount=type=cache,target=${ZIG_LOCAL_CACHE_DIR} \
bun install --frozen-lockfile \
RUN bun install --frozen-lockfile \
&& make runtime_js fallback_decoder bun_error \
&& rm -rf src/runtime src/fallback.ts node_modules bun.lockb package.json Makefile
@@ -438,9 +401,6 @@ ARG CANARY=0
ARG ASSERTIONS=OFF
ARG ZIG_OPTIMIZE=ReleaseFast
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
COPY *.zig package.json CMakeLists.txt ${BUN_DIR}/
COPY completions ${BUN_DIR}/completions
COPY packages ${BUN_DIR}/packages
@@ -453,9 +413,7 @@ COPY --from=bun-codegen-for-zig ${BUN_DIR}/packages/bun-error/dist ${BUN_DIR}/pa
WORKDIR $BUN_DIR
RUN --mount=type=cache,target=${CCACHE_DIR} \
--mount=type=cache,target=${ZIG_LOCAL_CACHE_DIR} \
mkdir -p build \
RUN mkdir -p build \
&& bun run $BUN_DIR/src/codegen/bundle-modules.ts --debug=OFF $BUN_DIR/build \
&& cd build \
&& cmake .. \
@@ -488,10 +446,6 @@ ARG CANARY
ARG ASSERTIONS
ENV CPU_TARGET=${CPU_TARGET}
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
ARG ZIG_LOCAL_CACHE_DIR=/zig-cache
ENV ZIG_LOCAL_CACHE_DIR=${ZIG_LOCAL_CACHE_DIR}
WORKDIR $BUN_DIR
@@ -519,9 +473,7 @@ COPY --from=bun-cpp-objects ${BUN_DIR}/bun-webkit/lib ${BUN_DIR}/bun-webkit/lib
WORKDIR $BUN_DIR/build
RUN --mount=type=cache,target=${CCACHE_DIR} \
--mount=type=cache,target=${ZIG_LOCAL_CACHE_DIR} \
cmake .. \
RUN cmake .. \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DBUN_LINK_ONLY=1 \
@@ -552,10 +504,6 @@ ARG CANARY
ARG ASSERTIONS
ENV CPU_TARGET=${CPU_TARGET}
ARG CCACHE_DIR=/ccache
ENV CCACHE_DIR=${CCACHE_DIR}
ARG ZIG_LOCAL_CACHE_DIR=/zig-cache
ENV ZIG_LOCAL_CACHE_DIR=${ZIG_LOCAL_CACHE_DIR}
WORKDIR $BUN_DIR
@@ -582,9 +530,7 @@ COPY --from=bun-cpp-objects ${BUN_DIR}/bun-webkit/lib ${BUN_DIR}/bun-webkit/lib
WORKDIR $BUN_DIR/build
RUN --mount=type=cache,target=${CCACHE_DIR} \
--mount=type=cache,target=${ZIG_LOCAL_CACHE_DIR} \
cmake .. \
RUN cmake .. \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DBUN_LINK_ONLY=1 \

View File

@@ -1266,8 +1266,7 @@ jsc-build-linux-compile-config:
cmake \
-DPORT="JSCOnly" \
-DENABLE_STATIC_JSC=ON \
-DCMAKE_BUILD_TYPE=Debug \
-DENABLE_BUN_SKIP_FAILING_ASSERTIONS=ON \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_THIN_ARCHIVES=OFF \
-DUSE_BUN_JSC_ADDITIONS=ON \
-DENABLE_FTL_JIT=ON \

284
README.md
View File

@@ -90,286 +90,42 @@ bun upgrade --canary
- [What is Bun?](https://bun.sh/docs/index)
- [Installation](https://bun.sh/docs/installation)
- [Quickstart](https://bun.sh/docs/quickstart)
- [TypeScript](https://bun.sh/docs/typescript)
- Templating
- CLI
- [`bun run`](https://bun.sh/docs/cli/run)
- [`bun install`](https://bun.sh/docs/cli/install)
- [`bun test`](https://bun.sh/docs/cli/test)
- [`bun init`](https://bun.sh/docs/cli/init)
- [`bun create`](https://bun.sh/docs/cli/bun-create)
- Runtime
- [`bun run`](https://bun.sh/docs/cli/run)
- [File types](https://bun.sh/docs/runtime/loaders)
- [TypeScript](https://bun.sh/docs/runtime/typescript)
- [JSX](https://bun.sh/docs/runtime/jsx)
- [Environment variables](https://bun.sh/docs/runtime/env)
- [Bun APIs](https://bun.sh/docs/runtime/bun-apis)
- [Web APIs](https://bun.sh/docs/runtime/web-apis)
- [Node.js compatibility](https://bun.sh/docs/runtime/nodejs-apis)
- [Single-file executable](https://bun.sh/docs/bundler/executables)
- [Plugins](https://bun.sh/docs/runtime/plugins)
- [Watch mode](https://bun.sh/docs/runtime/hot)
- [Module resolution](https://bun.sh/docs/runtime/modules)
- [Auto-install](https://bun.sh/docs/runtime/autoimport)
- [bunfig.toml](https://bun.sh/docs/runtime/bunfig)
- [Debugger](https://bun.sh/docs/runtime/debugger)
- [Framework API](https://bun.sh/docs/runtime/framework)
- Package manager
- [`bun install`](https://bun.sh/docs/cli/install)
- [`bun add`](https://bun.sh/docs/cli/add)
- [`bun remove`](https://bun.sh/docs/cli/remove)
- [`bun update`](https://bun.sh/docs/cli/update)
- [`bun link`](https://bun.sh/docs/cli/link)
- [`bun pm`](https://bun.sh/docs/cli/pm)
- [Global cache](https://bun.sh/docs/install/cache)
- [Workspaces](https://bun.sh/docs/install/workspaces)
- [Lifecycle scripts](https://bun.sh/docs/install/lifecycle)
- [Filter](https://bun.sh/docs/cli/filter)
- [Lockfile](https://bun.sh/docs/install/lockfile)
- [Scopes and registries](https://bun.sh/docs/install/registries)
- [Overrides and resolutions](https://bun.sh/docs/install/overrides)
- Bundler
- [`Bun.build`](https://bun.sh/docs/bundler)
- [Loaders](https://bun.sh/docs/bundler/loaders)
- [Plugins](https://bun.sh/docs/bundler/plugins)
- [Macros](https://bun.sh/docs/bundler/macros)
- [vs esbuild](https://bun.sh/docs/bundler/vs-esbuild)
- Test runner
- [`bun test`](https://bun.sh/docs/cli/test)
- [Writing tests](https://bun.sh/docs/test/writing)
- [Watch mode](https://bun.sh/docs/test/hot)
- [Lifecycle hooks](https://bun.sh/docs/test/lifecycle)
- [Mocks](https://bun.sh/docs/test/mocks)
- [Snapshots](https://bun.sh/docs/test/snapshots)
- [Dates and times](https://bun.sh/docs/test/time)
- [DOM testing](https://bun.sh/docs/test/dom)
- [Code coverage](https://bun.sh/docs/test/coverage)
- Package runner
- [`bunx`](https://bun.sh/docs/cli/bunx)
- Runtime
- [Runtime](https://bun.sh/docs/runtime/index)
- [Module resolution](https://bun.sh/docs/runtime/modules)
- [Hot &amp; live reloading](https://bun.sh/docs/runtime/hot)
- [Plugins](https://bun.sh/docs/bundler/plugins)
- Ecosystem
- [Node.js](https://bun.sh/docs/ecosystem/nodejs)
- [TypeScript](https://bun.sh/docs/ecosystem/typescript)
- [React](https://bun.sh/docs/ecosystem/react)
- [Elysia](https://bun.sh/docs/ecosystem/elysia)
- [Hono](https://bun.sh/docs/ecosystem/hono)
- [Express](https://bun.sh/docs/ecosystem/express)
- [awesome-bun](https://github.com/apvarun/awesome-bun)
- API
- [HTTP server](https://bun.sh/docs/api/http)
- [HTTP](https://bun.sh/docs/api/http)
- [WebSockets](https://bun.sh/docs/api/websockets)
- [Workers](https://bun.sh/docs/api/workers)
- [Binary data](https://bun.sh/docs/api/binary-data)
- [Streams](https://bun.sh/docs/api/streams)
- [TCP Sockets](https://bun.sh/docs/api/tcp)
- [File I/O](https://bun.sh/docs/api/file-io)
- [import.meta](https://bun.sh/docs/api/import-meta)
- [SQLite](https://bun.sh/docs/api/sqlite)
- [FileSystemRouter](https://bun.sh/docs/api/file-system-router)
- [TCP sockets](https://bun.sh/docs/api/tcp)
- [UDP sockets](https://bun.sh/docs/api/udp)
- [Globals](https://bun.sh/docs/api/globals)
- [$ Shell](https://bun.sh/docs/runtime/shell)
- [Child processes](https://bun.sh/docs/api/spawn)
- [Spawn](https://bun.sh/docs/api/spawn)
- [Transpiler](https://bun.sh/docs/api/transpiler)
- [Hashing](https://bun.sh/docs/api/hashing)
- [Console](https://bun.sh/docs/api/console)
- [FFI](https://bun.sh/docs/api/ffi)
- [HTMLRewriter](https://bun.sh/docs/api/html-rewriter)
- [Testing](https://bun.sh/docs/api/test)
- [Utils](https://bun.sh/docs/api/utils)
- [Node-API](https://bun.sh/docs/api/node-api)
- [Glob](https://bun.sh/docs/api/glob)
- [Semver](https://bun.sh/docs/api/semver)
- Project
- [Roadmap](https://bun.sh/docs/project/roadmap)
- [Benchmarking](https://bun.sh/docs/project/benchmarking)
- [Contributing](https://bun.sh/docs/project/contributing)
- [Building Windows](https://bun.sh/docs/project/building-windows)
- [License](https://bun.sh/docs/project/licensing)
## Guides
- Binary
- [Convert a Blob to a DataView](https://bun.sh/guides/binary/blob-to-dataview)
- [Convert a Blob to a ReadableStream](https://bun.sh/guides/binary/blob-to-stream)
- [Convert a Blob to a string](https://bun.sh/guides/binary/blob-to-string)
- [Convert a Blob to a Uint8Array](https://bun.sh/guides/binary/blob-to-typedarray)
- [Convert a Blob to an ArrayBuffer](https://bun.sh/guides/binary/blob-to-arraybuffer)
- [Convert a Buffer to a blob](https://bun.sh/guides/binary/buffer-to-blob)
- [Convert a Buffer to a ReadableStream](https://bun.sh/guides/binary/buffer-to-readablestream)
- [Convert a Buffer to a string](https://bun.sh/guides/binary/buffer-to-string)
- [Convert a Buffer to a Uint8Array](https://bun.sh/guides/binary/buffer-to-typedarray)
- [Convert a Buffer to an ArrayBuffer](https://bun.sh/guides/binary/buffer-to-arraybuffer)
- [Convert a DataView to a string](https://bun.sh/guides/binary/dataview-to-string)
- [Convert a Uint8Array to a Blob](https://bun.sh/guides/binary/typedarray-to-blob)
- [Convert a Uint8Array to a Buffer](https://bun.sh/guides/binary/typedarray-to-buffer)
- [Convert a Uint8Array to a DataView](https://bun.sh/guides/binary/typedarray-to-dataview)
- [Convert a Uint8Array to a ReadableStream](https://bun.sh/guides/binary/typedarray-to-readablestream)
- [Convert a Uint8Array to a string](https://bun.sh/guides/binary/typedarray-to-string)
- [Convert a Uint8Array to an ArrayBuffer](https://bun.sh/guides/binary/typedarray-to-arraybuffer)
- [Convert an ArrayBuffer to a Blob](https://bun.sh/guides/binary/arraybuffer-to-blob)
- [Convert an ArrayBuffer to a Buffer](https://bun.sh/guides/binary/arraybuffer-to-buffer)
- [Convert an ArrayBuffer to a string](https://bun.sh/guides/binary/arraybuffer-to-string)
- [Convert an ArrayBuffer to a Uint8Array](https://bun.sh/guides/binary/arraybuffer-to-typedarray)
- [Convert an ArrayBuffer to an array of numbers](https://bun.sh/guides/binary/arraybuffer-to-array)
- Ecosystem
- [Build a frontend using Vite and Bun](https://bun.sh/guides/ecosystem/vite)
- [Build an app with Astro and Bun](https://bun.sh/guides/ecosystem/astro)
- [Build an app with Next.js and Bun](https://bun.sh/guides/ecosystem/nextjs)
- [Build an app with Nuxt and Bun](https://bun.sh/guides/ecosystem/nuxt)
- [Build an app with Qwik and Bun](https://bun.sh/guides/ecosystem/qwik)
- [Build an app with Remix and Bun](https://bun.sh/guides/ecosystem/remix)
- [Build an app with SolidStart and Bun](https://bun.sh/guides/ecosystem/solidstart)
- [Build an app with SvelteKit and Bun](https://bun.sh/guides/ecosystem/sveltekit)
- [Build an HTTP server using Elysia and Bun](https://bun.sh/guides/ecosystem/elysia)
- [Build an HTTP server using Express and Bun](https://bun.sh/guides/ecosystem/express)
- [Build an HTTP server using Hono and Bun](https://bun.sh/guides/ecosystem/hono)
- [Build an HTTP server using StricJS and Bun](https://bun.sh/guides/ecosystem/stric)
- [Containerize a Bun application with Docker](https://bun.sh/guides/ecosystem/docker)
- [Create a Discord bot](https://bun.sh/guides/ecosystem/discordjs)
- [Read and write data to MongoDB using Mongoose and Bun](https://bun.sh/guides/ecosystem/mongoose)
- [Run Bun as a daemon with PM2](https://bun.sh/guides/ecosystem/pm2)
- [Run Bun as a daemon with systemd](https://bun.sh/guides/ecosystem/systemd)
- [Server-side render (SSR) a React component](https://bun.sh/guides/ecosystem/ssr-react)
- [Use Drizzle ORM with Bun](https://bun.sh/guides/ecosystem/drizzle)
- [Use EdgeDB with Bun](https://bun.sh/guides/ecosystem/edgedb)
- [Use Neon's Serverless Postgres with Bun](https://bun.sh/guides/ecosystem/neon-serverless-postgres)
- [Use Prisma with Bun](https://bun.sh/guides/ecosystem/prisma)
- [Use React and JSX](https://bun.sh/guides/ecosystem/react)
- HTTP
- [Common HTTP server usage](https://bun.sh/guides/http/server)
- [Configure TLS on an HTTP server](https://bun.sh/guides/http/tls)
- [fetch with unix domain sockets in Bun](https://bun.sh/guides/http/fetch-unix)
- [Hot reload an HTTP server](https://bun.sh/guides/http/hot)
- [Proxy HTTP requests using fetch()](https://bun.sh/guides/http/proxy)
- [Send an HTTP request using fetch](https://bun.sh/guides/http/fetch)
- [Start a cluster of HTTP servers](https://bun.sh/guides/http/cluster)
- [Stream a file as an HTTP Response](https://bun.sh/guides/http/stream-file)
- [Streaming HTTP Server with Async Iterators](https://bun.sh/guides/http/stream-iterator)
- [Streaming HTTP Server with Node.js Streams](https://bun.sh/guides/http/stream-node-streams-in-bun)
- [Upload files via HTTP using FormData](https://bun.sh/guides/http/file-uploads)
- [Write a simple HTTP server](https://bun.sh/guides/http/simple)
- Install
- [Add a dependency](https://bun.sh/guides/install/add)
- [Add a development dependency](https://bun.sh/guides/install/add-dev)
- [Add a Git dependency](https://bun.sh/guides/install/add-git)
- [Add a peer dependency](https://bun.sh/guides/install/add-peer)
- [Add a tarball dependency](https://bun.sh/guides/install/add-tarball)
- [Add a trusted dependency](https://bun.sh/guides/install/trusted)
- [Add an optional dependency](https://bun.sh/guides/install/add-optional)
- [Configure a private registry for an organization scope with bun install](https://bun.sh/guides/install/registry-scope)
- [Configure git to diff Bun's lockb lockfile](https://bun.sh/guides/install/git-diff-bun-lockfile)
- [Configuring a monorepo using workspaces](https://bun.sh/guides/install/workspaces)
- [Generate a human-readable lockfile](https://bun.sh/guides/install/yarnlock)
- [Install a package under a different name](https://bun.sh/guides/install/npm-alias)
- [Install dependencies with Bun in GitHub Actions](https://bun.sh/guides/install/cicd)
- [Override the default npm registry for bun install](https://bun.sh/guides/install/custom-registry)
- [Using bun install with an Azure Artifacts npm registry](https://bun.sh/guides/install/azure-artifacts)
- [Using bun install with Artifactory](https://bun.sh/guides/install/jfrog-artifactory)
- Process
- [Get the process uptime in nanoseconds](https://bun.sh/guides/process/nanoseconds)
- [Listen for CTRL+C](https://bun.sh/guides/process/ctrl-c)
- [Listen to OS signals](https://bun.sh/guides/process/os-signals)
- [Parse command-line arguments](https://bun.sh/guides/process/argv)
- [Read from stdin](https://bun.sh/guides/process/stdin)
- [Read stderr from a child process](https://bun.sh/guides/process/spawn-stderr)
- [Read stdout from a child process](https://bun.sh/guides/process/spawn-stdout)
- [Spawn a child process](https://bun.sh/guides/process/spawn)
- [Spawn a child process and communicate using IPC](https://bun.sh/guides/process/ipc)
- Read file
- [Check if a file exists](https://bun.sh/guides/read-file/exists)
- [Get the MIME type of a file](https://bun.sh/guides/read-file/mime)
- [Read a file as a ReadableStream](https://bun.sh/guides/read-file/stream)
- [Read a file as a string](https://bun.sh/guides/read-file/string)
- [Read a file to a Buffer](https://bun.sh/guides/read-file/buffer)
- [Read a file to a Uint8Array](https://bun.sh/guides/read-file/uint8array)
- [Read a file to an ArrayBuffer](https://bun.sh/guides/read-file/arraybuffer)
- [Read a JSON file](https://bun.sh/guides/read-file/json)
- [Watch a directory for changes](https://bun.sh/guides/read-file/watch)
- Runtime
- [Debugging Bun with the VS Code extension](https://bun.sh/guides/runtime/vscode-debugger)
- [Debugging Bun with the web debugger](https://bun.sh/guides/runtime/web-debugger)
- [Define and replace static globals & constants](https://bun.sh/guides/runtime/define-constant)
- [Import a JSON file](https://bun.sh/guides/runtime/import-json)
- [Import a TOML file](https://bun.sh/guides/runtime/import-toml)
- [Import HTML file as text](https://bun.sh/guides/runtime/import-html)
- [Install and run Bun in GitHub Actions](https://bun.sh/guides/runtime/cicd)
- [Install TypeScript declarations for Bun](https://bun.sh/guides/runtime/typescript)
- [Re-map import paths](https://bun.sh/guides/runtime/tsconfig-paths)
- [Read environment variables](https://bun.sh/guides/runtime/read-env)
- [Run a Shell Command](https://bun.sh/guides/runtime/shell)
- [Set a time zone in Bun](https://bun.sh/guides/runtime/timezone)
- [Set environment variables](https://bun.sh/guides/runtime/set-env)
- Streams
- [Convert a Node.js Readable to a Blob](https://bun.sh/guides/streams/node-readable-to-blob)
- [Convert a Node.js Readable to a string](https://bun.sh/guides/streams/node-readable-to-string)
- [Convert a Node.js Readable to an ArrayBuffer](https://bun.sh/guides/streams/node-readable-to-arraybuffer)
- [Convert a Node.js Readable to JSON](https://bun.sh/guides/streams/node-readable-to-json)
- [Convert a ReadableStream to a Blob](https://bun.sh/guides/streams/to-blob)
- [Convert a ReadableStream to a Buffer](https://bun.sh/guides/streams/to-buffer)
- [Convert a ReadableStream to a string](https://bun.sh/guides/streams/to-string)
- [Convert a ReadableStream to a Uint8Array](https://bun.sh/guides/streams/to-typedarray)
- [Convert a ReadableStream to an array of chunks](https://bun.sh/guides/streams/to-array)
- [Convert a ReadableStream to an ArrayBuffer](https://bun.sh/guides/streams/to-arraybuffer)
- [Convert a ReadableStream to JSON](https://bun.sh/guides/streams/to-json)
- Test
- [Bail early with the Bun test runner](https://bun.sh/guides/test/bail)
- [Generate code coverage reports with the Bun test runner](https://bun.sh/guides/test/coverage)
- [Mark a test as a "todo" with the Bun test runner](https://bun.sh/guides/test/todo-tests)
- [Migrate from Jest to Bun's test runner](https://bun.sh/guides/test/migrate-from-jest)
- [Mock functions in `bun test`](https://bun.sh/guides/test/mock-functions)
- [Re-run tests multiple times with the Bun test runner](https://bun.sh/guides/test/rerun-each)
- [Run tests in watch mode with Bun](https://bun.sh/guides/test/watch-mode)
- [Run your tests with the Bun test runner](https://bun.sh/guides/test/run-tests)
- [Set a code coverage threshold with the Bun test runner](https://bun.sh/guides/test/coverage-threshold)
- [Set a per-test timeout with the Bun test runner](https://bun.sh/guides/test/timeout)
- [Set the system time in Bun's test runner](https://bun.sh/guides/test/mock-clock)
- [Skip tests with the Bun test runner](https://bun.sh/guides/test/skip-tests)
- [Spy on methods in `bun test`](https://bun.sh/guides/test/spy-on)
- [Update snapshots in `bun test`](https://bun.sh/guides/test/update-snapshots)
- [Use snapshot testing in `bun test`](https://bun.sh/guides/test/snapshot)
- [Write browser DOM tests with Bun and happy-dom](https://bun.sh/guides/test/happy-dom)
- Util
- [Check if the current file is the entrypoint](https://bun.sh/guides/util/entrypoint)
- [Check if two objects are deeply equal](https://bun.sh/guides/util/deep-equals)
- [Compress and decompress data with DEFLATE](https://bun.sh/guides/util/deflate)
- [Compress and decompress data with gzip](https://bun.sh/guides/util/gzip)
- [Convert a file URL to an absolute path](https://bun.sh/guides/util/file-url-to-path)
- [Convert an absolute path to a file URL](https://bun.sh/guides/util/path-to-file-url)
- [Detect when code is executed with Bun](https://bun.sh/guides/util/detect-bun)
- [Encode and decode base64 strings](https://bun.sh/guides/util/base64)
- [Escape an HTML string](https://bun.sh/guides/util/escape-html)
- [Get the absolute path of the current file](https://bun.sh/guides/util/import-meta-path)
- [Get the absolute path to the current entrypoint](https://bun.sh/guides/util/main)
- [Get the current Bun version](https://bun.sh/guides/util/version)
- [Get the directory of the current file](https://bun.sh/guides/util/import-meta-dir)
- [Get the file name of the current file](https://bun.sh/guides/util/import-meta-file)
- [Get the path to an executable bin file](https://bun.sh/guides/util/which-path-to-executable-bin)
- [Hash a password](https://bun.sh/guides/util/hash-a-password)
- [Sleep for a fixed number of milliseconds](https://bun.sh/guides/util/sleep)
- WebSocket
- [Build a publish-subscribe WebSocket server](https://bun.sh/guides/websocket/pubsub)
- [Build a simple WebSocket server](https://bun.sh/guides/websocket/simple)
- [Enable compression for WebSocket messages](https://bun.sh/guides/websocket/compression)
- [Set per-socket contextual data on a WebSocket](https://bun.sh/guides/websocket/context)
- Write file
- [Append content to a file](https://bun.sh/guides/write-file/append)
- [Copy a file to another location](https://bun.sh/guides/write-file/file-cp)
- [Delete a file](https://bun.sh/guides/write-file/unlink)
- [Write a Blob to a file](https://bun.sh/guides/write-file/blob)
- [Write a file incrementally](https://bun.sh/guides/write-file/filesink)
- [Write a file to stdout](https://bun.sh/guides/write-file/cat)
- [Write a ReadableStream to a file](https://bun.sh/guides/write-file/stream)
- [Write a Response to a file](https://bun.sh/guides/write-file/response)
- [Write a string to a file](https://bun.sh/guides/write-file/basic)
- [Write to stdout](https://bun.sh/guides/write-file/stdout)
## Contributing

View File

@@ -1,24 +0,0 @@
import { bench, run } from "./runner.mjs";
var comparator = (a, b) => a - b;
const numbers = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51,
50, 49, 48.9,
];
const presorted = numbers.slice().sort(comparator);
bench(`Array.sort (${numbers.length} num, unsorted)`, () => {
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
16, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52,
51, 50, 49, 48.9,
].sort(comparator);
});
bench(`Array.sort (${numbers.length} num, pre-sorted)`, () => {
presorted.sort(comparator);
});
run();

View File

@@ -54,14 +54,4 @@ bench("JSON.stringify(obj)", () => {
globalThis.bar = JSON.stringify(obj);
});
var long_ascii = `"${"a".repeat(9999)}"`;
bench("JSON.parse(`\"${'a'.repeat(9999)}\"`)", () => {
globalThis.bar = JSON.parse(long_ascii);
});
const long_emoji = `"${"🥟".repeat(9999)}"`;
bench("JSON.parse(`\"${'🥟'.repeat(9999)}\"`)", () => {
globalThis.bar = JSON.parse(long_emoji);
});
await run();

View File

@@ -1,19 +0,0 @@
import { bench, run } from "./runner.mjs";
bench(`new URL('https://example.com/')`, () => {
const url = new URL("https://example.com/");
});
bench(`new URL('https://example.com')`, () => {
const url = new URL("https://example.com");
});
bench(`new URL('https://www.example.com')`, () => {
const url = new URL("https://www.example.com");
});
bench(`new URL('https://www.example.com/')`, () => {
const url = new URL("https://www.example.com/");
});
await run();

View File

@@ -146,7 +146,7 @@ const fs = std.fs;
pub fn build(b: *Build) !void {
build_(b) catch |err| {
if (@errorReturnTrace()) |trace| {
(std.debug).dumpStackTrace(trace.*);
std.debug.dumpStackTrace(trace.*);
}
return err;
@@ -394,7 +394,7 @@ pub fn build_(b: *Build) !void {
obj.linkLibC();
obj.dll_export_fns = true;
obj.strip = false;
obj.omit_frame_pointer = false;
obj.omit_frame_pointer = optimize != .Debug;
obj.subsystem = .Console;
// Disable stack probing on x86 so we don't need to include compiler_rt
@@ -629,3 +629,5 @@ pub fn configureObjectStep(b: *std.build.Builder, obj: *CompileStep, obj_step: *
obj.link_function_sections = true;
}
}
// !

View File

@@ -43,7 +43,6 @@ A `BunFile` can point to a location on disk where a file does not exist.
const notreal = Bun.file("notreal.txt");
notreal.size; // 0
notreal.type; // "text/plain;charset=utf-8"
const exists = await notreal.exists(); // false
```
The default MIME type is `text/plain;charset=utf-8`, but it can be overridden by passing a second argument to `Bun.file`.
@@ -341,7 +340,6 @@ interface BunFile {
arrayBuffer(): Promise<ArrayBuffer>;
json(): Promise<any>;
writer(params: { highWaterMark?: number }): FileSink;
exists(): Promise<boolean>;
}
export interface FileSink {

View File

@@ -112,7 +112,6 @@ Bun.hash.murmur64v2("data", 1234);
`Bun.CryptoHasher` is a general-purpose utility class that lets you incrementally compute a hash of string or binary data using a range of cryptographic hash algorithms. The following algorithms are supported:
- `"blake2b256"`
- `"blake2b512"`
- `"md4"`
- `"md5"`
- `"ripemd160"`
@@ -121,12 +120,7 @@ Bun.hash.murmur64v2("data", 1234);
- `"sha256"`
- `"sha384"`
- `"sha512"`
- `"sha512-224"`
- `"sha512-256"`
- `"sha3-224"`
- `"sha3-256"`
- `"sha3-384"`
- `"sha3-512"`
```ts
const hasher = new Bun.CryptoHasher("sha256");

View File

@@ -18,8 +18,6 @@ Bun.serve({
});
```
### `fetch` request handler
The `fetch` handler handles incoming requests. It receives a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) object and returns a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) or `Promise<Response>`.
```ts
@@ -33,46 +31,7 @@ Bun.serve({
});
```
The `fetch` handler supports async/await:
```ts
import { sleep, serve } from "bun";
serve({
async fetch(req) {
const start = performance.now();
await sleep(10);
const end = performance.now();
return new Response(`Slept for ${end - start}ms`);
},
});
```
Promise-based responses are also supported:
```ts
Bun.serve({
fetch(req) {
// Forward the request to another server.
return fetch("https://example.com");
},
});
```
You can also access the `Server` object from the `fetch` handler. It's the second argument passed to the `fetch` function.
```ts
// `server` is passed in as the second argument to `fetch`.
const server = Bun.serve({
fetch(req, server) {
const ip = server.requestIP(req);
return new Response(`Your IP is ${ip}`);
},
});
```
### Changing the `port` and `hostname`
To configure which port and hostname the server will listen on, set `port` and `hostname` in the options object.
To configure which port and hostname the server will listen on:
```ts
Bun.serve({
@@ -84,58 +43,7 @@ Bun.serve({
});
```
To randomly select an available port, set `port` to `0`.
```ts
const server = Bun.serve({
port: 0, // random port
fetch(req) {
return new Response("404!");
},
});
// server.port is the randomly selected port
console.log(server.port);
```
You can view the chosen port by accessing the `port` property on the server object, or by accessing the `url` property.
```ts
console.log(server.port); // 3000
console.log(server.url); // http://localhost:3000
```
#### Configuring a default port
Bun supports several options and environment variables to configure the default port. The default port is used when the `port` option is not set.
- `--port` CLI flag
```sh
$ bun --port=4002 server.ts
```
- `BUN_PORT` environment variable
```sh
$ BUN_PORT=4002 bun server.ts
```
- `PORT` environment variable
```sh
$ PORT=4002 bun server.ts
```
- `NODE_PORT` environment variable
```sh
$ NODE_PORT=4002 bun server.ts
```
### Unix domain sockets
To listen on a [unix domain socket](https://en.wikipedia.org/wiki/Unix_domain_socket), pass the `unix` option with the path to the socket.
To listen on a [unix domain socket](https://en.wikipedia.org/wiki/Unix_domain_socket):
```ts
Bun.serve({
@@ -146,24 +54,9 @@ Bun.serve({
});
```
### Abstract namespace sockets
Bun supports Linux abstract namespace sockets. To use an abstract namespace socket, prefix the `unix` path with a null byte.
```ts
Bun.serve({
unix: "\0my-abstract-socket", // abstract namespace socket
fetch(req) {
return new Response(`404!`);
},
});
```
Unlike unix domain sockets, abstract namespace sockets are not bound to the filesystem and are automatically removed when the last reference to the socket is closed.
## Error handling
To activate development mode, set `development: true`.
To activate development mode, set `development: true`. By default, development mode is _enabled_ unless `NODE_ENV` is `production`.
```ts
Bun.serve({
@@ -178,8 +71,6 @@ In development mode, Bun will surface errors in-browser with a built-in error pa
{% image src="/images/exception_page.png" caption="Bun's built-in 500 page" /%}
### `error` callback
To handle server-side errors, implement an `error` handler. This function should return a `Response` to serve to the client when an error occurs. This response will supersede Bun's default error page in `development` mode.
```ts
@@ -292,40 +183,6 @@ Bun.serve({
});
```
### Sever name indication (SNI)
To configure the server name indication (SNI) for the server, set the `serverName` field in the `tls` object.
```ts
Bun.serve({
// ...
tls: {
// ... other config
serverName: "my-server.com", // SNI
},
});
```
To allow multiple server names, pass an array of objects to `tls`, each with a `serverName` field.
```ts
Bun.serve({
// ...
tls: [
{
key: Bun.file("./key1.pem"),
cert: Bun.file("./cert1.pem"),
serverName: "my-server1.com",
},
{
key: Bun.file("./key2.pem"),
cert: Bun.file("./cert2.pem"),
serverName: "my-server2.com",
},
],
});
```
## Object syntax
Thus far, the examples on this page have used the explicit `Bun.serve` API. Bun also supports an alternate syntax.
@@ -436,98 +293,37 @@ The `Bun.serve` server can handle roughly 2.5x more requests per second than Nod
```ts
interface Bun {
serve(options: {
development?: boolean;
error?: (
request: ErrorLike,
) => Response | Promise<Response> | undefined | Promise<undefined>;
fetch(request: Request, server: Server): Response | Promise<Response>;
fetch: (req: Request, server: Server) => Response | Promise<Response>;
hostname?: string;
id?: string | null;
port?: number;
development?: boolean;
error?: (error: Error) => Response | Promise<Response>;
tls?: {
key?:
| string
| TypedArray
| BunFile
| Array<string | TypedArray | BunFile>;
cert?:
| string
| TypedArray
| BunFile
| Array<string | TypedArray | BunFile>;
ca?: string | TypedArray | BunFile | Array<string | TypedArray | BunFile>;
passphrase?: string;
dhParamsFile?: string;
};
maxRequestBodySize?: number;
port?: string | number;
reusePort?: boolean;
tls?: TLSOptions | Array<TLSOptions>;
unix: string;
websocket: WebSocketHandler<WebSocketDataType>;
lowMemoryMode?: boolean;
}): Server;
}
interface TLSOptions {
ca?: string | Buffer | BunFile | Array<string | Buffer | BunFile> | undefined;
cert?:
| string
| Buffer
| BunFile
| Array<string | Buffer | BunFile>
| undefined;
dhParamsFile?: string;
key?:
| string
| Buffer
| BunFile
| Array<string | Buffer | BunFile>
| undefined;
lowMemoryMode?: boolean;
passphrase?: string;
secureOptions?: number | undefined;
serverName?: string;
}
interface WebSocketHandler<T = undefined> {
backpressureLimit?: number;
close?(
ws: ServerWebSocket<T>,
code: number,
reason: string,
): void | Promise<void>;
closeOnBackpressureLimit?: boolean;
drain?(ws: ServerWebSocket<T>): void | Promise<void>;
idleTimeout?: number;
maxPayloadLength?: number;
message(
ws: ServerWebSocket<T>,
message: string | Buffer,
): void | Promise<void>;
open?(ws: ServerWebSocket<T>): void | Promise<void>;
perMessageDeflate?:
| boolean
| {
compress?: WebSocketCompressor | boolean;
decompress?: WebSocketCompressor | boolean;
};
ping?(ws: ServerWebSocket<T>, data: Buffer): void | Promise<void>;
pong?(ws: ServerWebSocket<T>, data: Buffer): void | Promise<void>;
publishToSelf?: boolean;
sendPings?: boolean;
}
interface Server {
fetch(request: Request | string): Response | Promise<Response>;
publish(
compress?: boolean,
data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
topic: string,
): ServerWebSocketSendStatus;
ref(): void;
reload(options: Serve): void;
requestIP(request: Request): SocketAddress | null;
stop(closeActiveConnections?: boolean): void;
unref(): void;
upgrade<T = undefined>(
options?: {
data?: T;
headers?: Bun.HeadersInit;
},
request: Request,
): boolean;
readonly development: boolean;
readonly hostname: string;
readonly id: string;
readonly pendingRequests: number;
readonly pendingWebSockets: number;
readonly port: number;
readonly url: URL;
development: boolean;
hostname: string;
port: number;
pendingRequests: number;
stop(): void;
}
```

View File

@@ -5,14 +5,13 @@ Spawn child processes with `Bun.spawn` or `Bun.spawnSync`.
Provide a command as an array of strings. The result of `Bun.spawn()` is a `Bun.Subprocess` object.
```ts
const proc = Bun.spawn(["bun", "--version"]);
console.log(await proc.exited); // 0
Bun.spawn(["echo", "hello"]);
```
The second argument to `Bun.spawn` is a parameters object that can be used to configure the subprocess.
```ts
const proc = Bun.spawn(["bun", "--version"], {
const proc = Bun.spawn(["echo", "hello"], {
cwd: "./path/to/subdir", // specify a working directory
env: { ...process.env, FOO: "bar" }, // specify environment variables
onExit(proc, exitCode, signalCode, error) {
@@ -108,9 +107,9 @@ proc.stdin.end();
You can read results from the subprocess via the `stdout` and `stderr` properties. By default these are instances of `ReadableStream`.
```ts
const proc = Bun.spawn(["bun", "--version"]);
const proc = Bun.spawn(["echo", "hello"]);
const text = await new Response(proc.stdout).text();
console.log(text); // => "1.1.7"
console.log(text); // => "hello"
```
Configure the output stream by passing one of the following values to `stdout/stderr`:
@@ -149,7 +148,7 @@ Configure the output stream by passing one of the following values to `stdout/st
Use the `onExit` callback to listen for the process exiting or being killed.
```ts
const proc = Bun.spawn(["bun", "--version"], {
const proc = Bun.spawn(["echo", "hello"], {
onExit(proc, exitCode, signalCode, error) {
// exit handler
},
@@ -159,7 +158,7 @@ const proc = Bun.spawn(["bun", "--version"], {
For convenience, the `exited` property is a `Promise` that resolves when the process exits.
```ts
const proc = Bun.spawn(["bun", "--version"]);
const proc = Bun.spawn(["echo", "hello"]);
await proc.exited; // resolves when process exit
proc.killed; // boolean — was the process killed?
@@ -170,7 +169,7 @@ proc.signalCode; // null | "SIGABRT" | "SIGALRM" | ...
To kill a process:
```ts
const proc = Bun.spawn(["bun", "--version"]);
const proc = Bun.spawn(["echo", "hello"]);
proc.kill();
proc.killed; // true
@@ -180,7 +179,7 @@ proc.kill(); // specify an exit code
The parent `bun` process will not terminate until all child processes have exited. Use `proc.unref()` to detach the child process from the parent.
```
const proc = Bun.spawn(["bun", "--version"]);
const proc = Bun.spawn(["echo", "hello"]);
proc.unref();
```
@@ -188,6 +187,10 @@ proc.unref();
Bun supports direct inter-process communication channel between two `bun` processes. To receive messages from a spawned Bun subprocess, specify an `ipc` handler.
{%callout%}
**Note** — This API is only compatible with other `bun` processes. Use `process.execPath` to get a path to the currently running `bun` executable.
{%/callout%}
```ts#parent.ts
const child = Bun.spawn(["bun", "child.ts"], {
ipc(message) {
@@ -238,34 +241,6 @@ The `ipcMode` option controls the underlying communication format between the tw
- `advanced`: (default) Messages are serialized using the JSC `serialize` API, which supports cloning [everything `structuredClone` supports](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm). This does not support transferring ownership of objects.
- `json`: Messages are serialized using `JSON.stringify` and `JSON.parse`, which does not support as many object types as `advanced` does.
### IPC between Bun & Node.js
To use IPC between a `bun` process and a Node.js process, set `serialization: "json"` in `Bun.spawn`. This is because Node.js and Bun use different JavaScript engines with different object serialization formats.
```js#bun-node-ipc.js
if (typeof Bun !== "undefined") {
const prefix = `[bun ${process.versions.bun} 🐇]`;
const node = Bun.spawn({
cmd: ["node", __filename],
ipc({ message }) {
console.log(message);
node.send({ message: `${prefix} 👋 hey node` });
node.kill();
},
stdio: ["inherit", "inherit", "inherit"],
serialization: "json",
});
node.send({ message: `${prefix} 👋 hey node` });
} else {
const prefix = `[node ${process.version}]`;
process.on("message", ({ message }) => {
console.log(message);
process.send({ message: `${prefix} 👋 hey bun` });
});
}
```
## Blocking API (`Bun.spawnSync()`)
Bun provides a synchronous equivalent of `Bun.spawn` called `Bun.spawnSync`. This is a blocking API that supports the same inputs and parameters as `Bun.spawn`. It returns a `SyncSubprocess` object, which differs from `Subprocess` in a few ways.

View File

@@ -62,7 +62,7 @@ const db = new Database("mydb.sqlite", { create: true });
You can also use an import attribute to load a database.
```ts
import db from "./mydb.sqlite" with { "type": "sqlite" };
import db from "./mydb.sqlite" with {"type": "sqlite"};
console.log(db.query("select * from users LIMIT 1").get());
```
@@ -74,39 +74,16 @@ import { Database } from "bun:sqlite";
const db = new Database("./mydb.sqlite");
```
### `.close(throwOnError: boolean = false)`
### `.close()`
To close a database connection, but allow existing queries to finish, call `.close(false)`:
To close a database:
```ts
const db = new Database();
// ... do stuff
db.close(false);
db.close();
```
To close the database and throw an error if there are any pending queries, call `.close(true)`:
```ts
const db = new Database();
// ... do stuff
db.close(true);
```
Note: `close(false)` is called automatically when the database is garbage collected. It is safe to call multiple times but has no effect after the first.
### `using` statement
You can use the `using` statement to ensure that a database connection is closed when the `using` block is exited.
```ts
import { Database } from "bun:sqlite";
{
using db = new Database("mydb.sqlite");
using query = db.query("select 'Hello world' as message;");
console.log(query.get()); // => { message: "Hello world" }
}
```
Note: `close()` is called automatically when the database is garbage collected. It is safe to call multiple times but has no effect after the first.
### `.serialize()`
@@ -151,8 +128,6 @@ db.exec("PRAGMA journal_mode = WAL;");
{% details summary="What is WAL mode" %}
In WAL mode, writes to the database are written directly to a separate file called the "WAL file" (write-ahead log). This file will be later integrated into the main database file. Think of it as a buffer for pending writes. Refer to the [SQLite docs](https://www.sqlite.org/wal.html) for a more detailed overview.
On macOS, WAL files may be persistent by default. This is not a bug, it is how macOS configured the system version of SQLite.
{% /details %}
## Statements
@@ -200,7 +175,7 @@ Internally, this calls [`sqlite3_reset`](https://www.sqlite.org/capi3ref.html#sq
### `.run()`
Use `.run()` to run a query and get back `undefined`. This is useful for schema-modifying queries (e.g. `CREATE TABLE`) or bulk write operations.
Use `.run()` to run a query and get back `undefined`. This is useful for queries schema-modifying queries (e.g. `CREATE TABLE`) or bulk write operations.
```ts
const query = db.query(`create table foo;`);
@@ -412,25 +387,6 @@ db.loadExtension("myext");
{% /details %}
### .fileControl(cmd: number, value: any)
To use the advanced `sqlite3_file_control` API, call `.fileControl(cmd, value)` on your `Database` instance.
```ts
import { Database, constants } from "bun:sqlite";
const db = new Database();
// Ensure WAL mode is NOT persistent
// this prevents wal files from lingering after the database is closed
db.fileControl(constants.SQLITE_FCNTL_PERSIST_WAL, 0);
```
`value` can be:
- `number`
- `TypedArray`
- `undefined` or `null`
## Reference
```ts

View File

@@ -1,125 +0,0 @@
Use Bun's UDP API to implement services with advanced real-time requirements, such as voice chat.
## Bind a UDP socket (`Bun.udpSocket()`)
To create a new (bound) UDP socket:
```ts
const socket = await Bun.udpSocket({})
console.log(socket.port); // assigned by the operating system
```
Specify a port:
```ts
const socket = await Bun.udpSocket({
port: 41234
})
console.log(socket.port); // 41234
```
### Send a datagram
Specify the data to send, as well as the destination port and address.
```ts
socket.send("Hello, world!", 41234, "127.0.0.1");
```
Note that the address must be a valid IP address - `send` does not perform
DNS resolution, as it is intended for low-latency operations.
### Receive datagrams
When creating your socket, add a callback to specify what should be done when packets are received:
```ts
const server = await Bun.udpSocket({
socket: {
data(socket, buf, port, addr) {
console.log(`message from ${addr}:${port}:`)
console.log(buf.toString());
}
}
})
const client = await Bun.udpSocket({});
client.send("Hello!", server.port, "127.0.0.1");
```
### Connections
While UDP does not have a concept of a connection, many UDP communications (especially as a client) involve only one peer.
In such cases it can be beneficial to connect the socket to that peer, which specifies to which address all packets are sent
and restricts incoming packets to that peer only.
```ts
const server = await Bun.udpSocket({
socket: {
data(socket, buf, port, addr) {
console.log(`message from ${addr}:${port}:`)
console.log(buf.toString());
}
}
})
const client = await Bun.udpSocket({
connect: {
port: server.port,
hostname: '127.0.0.1',
}
});
client.send("Hello");
```
Because connections are implemented on the operating system level, you can potentially observe performance benefits, too.
### Send many packets at once using `sendMany()`
If you want to send a large volume of packets at once, it can make sense to batch them all together to avoid the overhead
of making a system call for each. This is made possible by the `sendMany()` API:
For an unconnected socket, `sendMany` takes an array as its only argument. Each set of three array elements describes a packet:
The first item is the data to be sent, the second is the target port, and the last is the target address.
```ts
const socket = await Bun.udpSocket({})
// sends 'Hello' to 127.0.0.1:41234, and 'foo' to 1.1.1.1:53 in a single operation
socket.sendMany(['Hello', 41234, '127.0.0.1', 'foo', 53, '1.1.1.1'])
```
With a connected socket, `sendMany` simply takes an array, where each element represents the data to be sent to the peer.
```ts
const socket = await Bun.udpSocket({
connect: {
port: 41234,
hostname: 'localhost',
}
});
socket.sendMany(['foo', 'bar', 'baz']);
```
`sendMany` returns the number of packets that were successfully sent. As with `send`, `sendMany` only takes valid IP addresses
as destinations, as it does not perform DNS resolution.
### Handle backpressure
It may happen that a packet that you're sending does not fit into the operating system's packet buffer. You can detect that this
has happened when:
- `send` returns `false`
- `sendMany` returns a number smaller than the number of packets you specified
In this case, the `drain` socket handler will be called once the socket becomes writable again:
```ts
const socket = await Bun.udpSocket({
socket: {
drain(socket) {
// continue sending data
}
}
});
```

View File

@@ -23,7 +23,7 @@ Bun.serve({
if (server.upgrade(req)) {
return; // do not return a Response
}
return new Response("Upgrade failed", { status: 500 });
return new Response("Upgrade failed :(", { status: 500 });
},
websocket: {}, // handlers
});
@@ -321,7 +321,7 @@ namespace Bun {
message: string | ArrayBuffer | Uint8Array,
) => void;
open?: (ws: ServerWebSocket) => void;
close?: (ws: ServerWebSocket, code: number, reason: string) => void;
close?: (ws: ServerWebSocket) => void;
error?: (ws: ServerWebSocket, error: Error) => void;
drain?: (ws: ServerWebSocket) => void;
@@ -356,7 +356,7 @@ type Compressor =
| `"256KB"`;
interface Server {
pendingWebSockets: number;
pendingWebsockets: number;
publish(
topic: string,
data: string | ArrayBufferView | ArrayBuffer,

View File

@@ -21,76 +21,21 @@ Hello world!
All imported files and packages are bundled into the executable, along with a copy of the Bun runtime. All built-in Bun and Node.js APIs are supported.
## Cross-compile to other platforms
{% callout %}
The `--target` flag lets you compile your standalone executable for a different operating system, architecture, or version of Bun than the machine you're running `bun build` on.
**Note** — Currently, the `--compile` flag can only accept a single entrypoint at a time and does not support the following flags:
To build for Linux x64 (most servers):
- `--outdir` — use `outfile` instead.
- `--splitting`
- `--public-path`
```sh
bun build --compile --target=bun-linux-x64 ./index.ts --outfile myapp
# To support CPUs from before 2013, use the baseline version (nehalem)
bun build --compile --target=bun-linux-x64-baseline ./index.ts --outfile myapp
# To explicitly only support CPUs from 2013 and later, use the modern version (haswell)
# modern is faster, but baseline is more compatible.
bun build --compile --target=bun-linux-x64-modern ./index.ts --outfile myapp
```
To build for Linux ARM64 (e.g. Graviton or Raspberry Pi):
```sh
# Note: the default architecture is x64 if no architecture is specified.
bun build --compile --target=bun-linux-arm64 ./index.ts --outfile myapp
```
To build for Windows x64:
```sh
bun build --compile --target=bun-windows-x64 ./path/to/my/app.ts --outfile myapp
# To support CPUs from before 2013, use the baseline version (nehalem)
bun build --compile --target=bun-windows-x64-baseline ./path/to/my/app.ts --outfile myapp
# To explicitly only support CPUs from 2013 and later, use the modern version (haswell)
bun build --compile --target=bun-windows-x64-modern ./path/to/my/app.ts --outfile myapp
# note: if no .exe extension is provided, Bun will automatically add it for Windows executables
```
To build for macOS arm64:
```sh
bun build --compile --target=bun-darwin-arm64 ./path/to/my/app.ts --outfile myapp
```
To build for macOS x64:
```sh
bun build --compile --target=bun-darwin-x64 ./path/to/my/app.ts --outfile myapp
```
#### Supported targets
The order of the `--target` flag does not matter, as long as they're delimited by a `-`.
| --target | Operating System | Architecture | Modern | Baseline |
| --------------------- | ---------------- | ------------ | ------ | -------- |
| bun-linux-x64 | Linux | x64 | ✅ | ✅ |
| bun-linux-arm64 | Linux | arm64 | ✅ | N/A |
| bun-windows-x64 | Windows | x64 | ✅ | ✅ |
| ~~bun-windows-arm64~~ | Windows | arm64 | ❌ | ❌ |
| bun-darwin-x64 | macOS | x64 | ✅ | ✅ |
| bun-darwin-arm64 | macOS | arm64 | ✅ | N/A |
On x64 platforms, Bun uses SIMD optimizations which require a modern CPU supporting AVX2 instructions. The `-baseline` build of Bun is for older CPUs that don't support these optimizations. Normally, when you install Bun we automatically detect which version to use but this can be harder to do when cross-compiling since you might not know the target CPU. You usually don't need to worry about it on Darwin x64, but it is relevant for Windows x64 and Linux x64. If you or your users see `"Illegal instruction"` errors, you might need to use the baseline version.
{% /callout %}
## Deploying to production
Compiled executables reduce memory usage and improve Bun's start time.
Normally, Bun reads and transpiles JavaScript and TypeScript files on `import` and `require`. This is part of what makes so much of Bun "just work", but it's not free. It costs time and memory to read files from disk, resolve file paths, parse, transpile, and print source code.
Normally, Bun reads and transpiles JavaScript and TypeScript files on `import` and `require`. This is part of what makes so much of Bun "just work", but it's not free. It costs time and memory to read files from disk, resolve file paths, parse, transpile, and print source code.
With compiled executables, you can move that cost from runtime to build-time.
@@ -113,7 +58,7 @@ You can use `bun:sqlite` imports with `bun build --compile`.
By default, the database is resolved relative to the current working directory of the process.
```js
import db from "./my.db" with { type: "sqlite" };
import db from './my.db' with {type: "sqlite"};
console.log(db.query("select * from users LIMIT 1").get());
```
@@ -125,49 +70,42 @@ $ cd /home/me/Desktop
$ ./hello
```
## Embed assets & files
## Embedding files
Standalone executables support embedding files.
To embed files into an executable with `bun build --compile`, import the file in your code
```ts
```js
// this becomes an internal file path
import icon from "./icon.png" with { type: "file" };
import icon from "./icon.png";
import { file } from "bun";
export default {
fetch(req) {
// Embedded files can be streamed from Response objects
return new Response(file(icon));
},
};
```
You may need to specify a `--loader` for it to be treated as a `"file"` loader (so you get back a file path).
Embedded files can be read using `Bun.file`'s functions or the Node.js `fs.readFile` function (in `"node:fs"`).
For example, to read the contents of the embedded file:
```js
import icon from "./icon.png" with { type: "file" };
import { file } from "bun";
const bytes = await file(icon).arrayBuffer();
```
### Embed SQLite databases
### Embedding SQLite databases
If your application wants to embed a SQLite database, set `type: "sqlite"` in the import attribute and the `embed` attribute to `"true"`.
```js
import myEmbeddedDb from "./my.db" with { type: "sqlite", embed: "true" };
import myEmbeddedDb from "./my.db" with {type: "sqlite", embed: "true"};
console.log(myEmbeddedDb.query("select * from users LIMIT 1").get());
```
This database is read-write, but all changes are lost when the executable exits (since it's stored in memory).
### Embed N-API Addons
### Embedding N-API Addons
As of Bun v1.0.23, you can embed `.node` files into executables.
@@ -182,14 +120,3 @@ Unfortunately, if you're using `@mapbox/node-pre-gyp` or other similar tools, yo
## Minification
To trim down the size of the executable a little, pass `--minify` to `bun build --compile`. This uses Bun's minifier to reduce the code size. Overall though, Bun's binary is still way too big and we need to make it smaller.
## Unsupported CLI arguments
Currently, the `--compile` flag can only accept a single entrypoint at a time and does not support the following flags:
- `--outdir` — use `outfile` instead.
- `--splitting`
- `--public-path`
- `--target=node` or `--target=browser`
- `--format` - always outputs a binary executable. Internally, it's almost esm.
- `--no-bundle` - we always bundle everything into the executable.

View File

@@ -792,7 +792,7 @@ The names and locations of the generated files can be customized with the `namin
- `[name]` - The name of the entrypoint file, without the extension.
- `[ext]` - The extension of the generated bundle.
- `[hash]` - A hash of the bundle contents.
- `[dir]` - The relative path from the project root to the parent directory of the source file.
- `[dir]` - The relative path from the build root to the parent directory of the file.
For example:

View File

@@ -80,9 +80,6 @@ TOML files can be directly imported. Bun will parse them with its fast native TO
```ts
import config from "./bunfig.toml";
config.logLevel; // => "debug"
// via import attribute:
// import myCustomTOML from './my.config' with {type: "toml"};
```
During bundling, the parsed TOML is inlined into the bundle as a JavaScript object.
@@ -125,10 +122,6 @@ Text files can be directly imported. The file is read and returned as a string.
```ts
import contents from "./file.txt";
console.log(contents); // => "Hello, world!"
// To import an html file as text
// The "type' attribute can be used to override the default loader.
import html from "./index.html" with { type: "text" };
```
When referenced during a build, the contents are into the bundle as a string.
@@ -182,7 +175,7 @@ In the bundler, `.node` files are handled using the [`file`](#file) loader.
**SQLite loader**. `with { "type": "sqlite" }` import attribute
In the runtime and bundler, SQLite databases can be directly imported. This will load the database using [`bun:sqlite`](/docs/api/sqlite).
In the runtime and bundler, SQLite databases can be directly imported. This will load the database using [`bun:sqlite`](/docs/api/sqlite.md).
```ts
import db from "./my.db" with { type: "sqlite" };

View File

@@ -207,8 +207,8 @@ After cloning a template, `bun create` will automatically remove the `"bun-creat
---
- `GITHUB_TOKEN` (or `GITHUB_ACCESS_TOKEN`)
- This lets `bun create` work with private repositories or if you get rate-limited. `GITHUB_TOKEN` is chosen over `GITHUB_ACCESS_TOKEN` if both exist.
- `GITHUB_ACCESS_TOKEN`
- This lets `bun create` work with private repositories or if you get rate-limited
{% /table %}

View File

@@ -1,58 +0,0 @@
Use the `--filter` flag to execute lifecycle scripts in multiple packages at once:
```bash
bun --filter <pattern> <script>
```
Say you have a monorepo with two packages: `packages/api` and `packages/frontend`, both with a `dev` script that will start a local development server. Normally, you would have to open two separate terminal tabs, cd into each package directory, and run `bun dev`:
```bash
cd packages/api
bun dev
# in another terminal
cd packages/frontend
bun dev
```
Using `--filter`, you can run the `dev` script in both packages at once:
```bash
bun --filter '*' dev
```
Both commands will be run in parallel, and you will see a nice terminal UI showing their respective outputs:
![Terminal Output](https://github.com/oven-sh/bun/assets/48869301/2a103e42-9921-4c33-948f-a1ad6e6bac71)
## Matching
`--filter` accepts a pattern to match specific packages, either by name or by path. Patterns have full support for glob syntax.
### Package Name `--filter <pattern>`
Name patterns select packages based on the package name, as specified in `package.json`. For example, if you have packages `pkga`, `pkgb` and `other`, you can match all packages with `*`, only `pkga` and `pkgb` with `pkg*`, and a specific package by providing the full name of the package.
### Package Path `--filter ./<glob>`
Path patterns are specified by starting the pattern with `./`, and will select all packages in directories that match the pattern. For example, to match all packages in subdirectories of `packages`, you can use `--filter './packages/**'`. To match a package located in `pkgs/foo`, use `--filter ./pkgs/foo`.
## Workspaces
Filters respect your [workspace configuration](/docs/install/workspaces): If you have a `package.json` file that specifies which packages are part of the workspace,
`--filter` will be restricted to only these packages. Also, in a workspace you can use `--filter` to run scripts in packages that are located anywhere in the workspace:
```bash
# Packages
# src/foo
# src/bar
# in src/bar: runs myscript in src/foo, no need to cd!
bun run --filter foo myscript
```
## 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.
### Cyclic Dependencies

View File

@@ -151,19 +151,6 @@ By default, Bun respects this shebang and executes the script with `node`. Howev
$ bun run --bun vite
```
### Filtering
in monorepos containing multiple packages, you can use the `--filter` argument to execute scripts in many packages at once.
Use `bun run --filter <name_pattern> <script>` to execute `<script>` in all packages whose name matches `<name_pattern>`.
For example, if you have subdirectories containing packages named `foo`, `bar` and `baz`, running
```bash
bun run --filter 'ba*' <script>
```
will execute `<script>` in both `bar` and `baz`, but not in `foo`.
Find more details in the docs page for [filter](/docs/cli/filter).
## `bun run -` to pipe code from stdin
`bun run -` lets you read JavaScript, TypeScript, TSX, or JSX from stdin and execute it without writing to a temporary file first.

View File

@@ -77,7 +77,7 @@ coverage*
---
We'll now use `docker build` to convert this `Dockerfile` into a _Docker image_, a self-contained template containing all the dependencies and configuration required to run the application.
We'll now use `docker build` to convert this `Dockerfile` into a _Docker image_, is a self-contained template containing all the dependencies and configuration required to run the application.
The `-t` flag lets us specify a name for the image, and `--pull` tells Docker to automatically download the latest version of the base image (`oven/bun`). The initial build will take longer, as Docker will download all the base images and dependencies.

View File

@@ -1,55 +0,0 @@
---
name: Use Neon's Serverless Postgres with Bun
---
[Neon](https://neon.tech/) is a fully managed serverless Postgres. Neon separates compute and storage to offer modern developer features such as autoscaling, branching, bottomless storage, and more.
---
Get started by creating a project directory, initializing the directory using `bun init`, and adding the [Neon serverless driver](https://github.com/neondatabase/serverless/) as a project dependency.
```sh
$ mkdir bun-neon-postgres
$ cd bun-neon-postgres
$ bun init -y
$ bun add @neondatabase/serverless
```
---
Create a `.env.local` file and add your [Neon Postgres connection string](https://neon.tech/docs/connect/connect-from-any-app) to it.
```sh
DATBASE_URL=postgresql://username:password@ep-adj-noun-guid.us-east-1.aws.neon.tech/neondb?sslmode=require
```
---
Paste the following code into your project's `index.ts` file.
```ts
import { neon } from "@neondatabase/serverless";
// Bun automatically loads the DATABASE_URL from .env.local
// Refer to: https://bun.sh/docs/runtime/env for more information
const sql = neon(process.env.DATABASE_URL);
const rows = await sql`SELECT version()`;
console.log(rows[0].version);
```
---
Start the program using `bun ./index.ts`. The Postgres version should be printed to the console.
```sh
$ bun ./index.ts
PostgreSQL 16.2 on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
```
---
This example used the Neon serverless driver's SQL-over-HTTP functionality. Neon's serverless driver also exposes `Client` and `Pool` constructors to enable sessions, interactive transactions, and node-postgres compatibility.
Refer to [Neon's documentation](https://neon.tech/docs/serverless/serverless-driver) for a complete overview of the serverless driver.

View File

@@ -55,4 +55,4 @@ Open [localhost:3000](http://localhost:3000). Any changes you make to `src/route
---
Refer to the [SolidStart website](https://start.solidjs.com/getting-started/what-is-solidstart) for complete framework documentation.
Refer to the [SolidStart website](start.solidjs.com/getting-started/what-is-solidstart) for complete framework documentation.

View File

@@ -2,15 +2,6 @@
name: Server-side render (SSR) a React component
---
To get started, install the canary version of `react` & `react-dom`:
```sh
# Any package manager can be used
$ bun add react@canary react-dom@canary
```
---
To render a React component to an HTML stream server-side (SSR):
```tsx
@@ -48,4 +39,4 @@ Bun.serve({
---
React `19` and later includes an [SSR optimization](https://github.com/facebook/react/pull/25597) that takes advantage of Bun's "direct" `ReadableStream` implementation. If you run into an error like `export named 'renderToReadableStream' not found`, please make sure to install the canary version of `react` & `react-dom`, or import from `react-dom/server.browser` instead of `react-dom/server`. See [facebook/react#28941](https://github.com/facebook/react/issues/28941) for more information.
React `18.3` and later includes an [SSR optimization](https://github.com/facebook/react/pull/25597) that takes advantage of Bun's "direct" `ReadableStream` implementation.

View File

@@ -1,66 +0,0 @@
---
name: Start a cluster of HTTP servers
description: Run multiple HTTP servers concurrently via the "reusePort" option to share the same port across multiple processes
---
To run multiple HTTP servers concurrently, use the `reusePort` option in `Bun.serve()` which shares the same port across multiple processes.
This automatically load balances incoming requests across multiple instances of Bun.
```ts#server.ts
import { serve } from "bun";
const id = = Math.random().toString(36).slice(2);
serve({
port: process.env.PORT || 8080,
development: false,
// Share the same port across multiple processes
// This is the important part!
reusePort: true,
async fetch(request) {
return new Response("Hello from Bun #" + id + "!\n");
}
});
```
---
{% callout %}
**Linux only** &mdash; Windows and macOS ignore the `reusePort` option. This is an operating system limitation with `SO_REUSEPORT`, unfortunately.
{% /callout %}
After saving the file, start your servers on the same port.
Under the hood, this uses the Linux `SO_REUSEPORT` and `SO_REUSEADDR` socket options to ensure fair load balancing across multiple processes. [Learn more about `SO_REUSEPORT` and `SO_REUSEADDR`](https://lwn.net/Articles/542629/)
```ts#cluster.ts
import { spawn } from "bun";
const cpus = navigator.hardwareConcurrency; // Number of CPU cores
const buns = new Array(cpus);
for (let i = 0; i < cpus; i++) {
buns[i] = spawn({
cmd: ["bun", "./server.ts"],
stdout: "inherit",
stderr: "inherit",
stdin: "inherit",
});
}
function kill() {
for (const bun of buns) {
bun.kill();
}
}
process.on("SIGINT", kill);
process.on("exit", kill);
```
---
At the time of writing, Bun hasn't implemented the `node:cluster` module yet, but this is a faster, simple, and limited alternative. We will also implement `node:cluster` in the future.

View File

@@ -1,24 +0,0 @@
---
name: Proxy HTTP requests using fetch()
---
In Bun, `fetch` supports sending requests through an HTTP or HTTPS proxy. This is useful on corporate networks or when you need to ensure a request is sent through a specific IP address.
```ts
await fetch("https://example.com", {
// The URL of the proxy server
proxy: "https://username:password@proxy.example.com:8080",
});
```
---
The `proxy` option is a URL string that specifies the proxy server. It can include the username and password if the proxy requires authentication. It can be `http://` or `https://`.
---
You can also set the `$HTTP_PROXY` or `$HTTPS_PROXY` environment variable to the proxy URL. This is useful when you want to use the same proxy for all requests.
```sh
HTTPS_PROXY=https://username:password@proxy.example.com:8080 bun run index.ts
```

View File

@@ -1,47 +0,0 @@
---
name: Streaming HTTP Server with Async Iterators
---
In Bun, [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects can accept an async generator function as their body. This allows you to stream data to the client as it becomes available, rather than waiting for the entire response to be ready.
```ts
Bun.serve({
port: 3000,
fetch(req) {
return new Response(
// An async generator function
async function* () {
yield "Hello, ";
await Bun.sleep(100);
yield "world!";
// you can also yield a TypedArray or Buffer
yield new Uint8Array(["\n".charCodeAt(0)]);
},
{ headers: { "Content-Type": "text/plain" } },
);
},
});
```
---
You can pass any async iterable directly to `Response`:
```ts
Bun.serve({
port: 3000,
fetch(req) {
return new Response(
{
[Symbol.asyncIterator]: async function* () {
yield "Hello, ";
await Bun.sleep(100);
yield "world!";
},
},
{ headers: { "Content-Type": "text/plain" } },
);
},
});
```

View File

@@ -1,20 +0,0 @@
---
name: Streaming HTTP Server with Node.js Streams
---
In Bun, [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects can accept a Node.js [`Readable`](https://nodejs.org/api/stream.html#stream_readable_streams).
This works because Bun's `Response` object allows any async iterable as its body. Node.js streams are async iterables, so you can pass them directly to `Response`.
```ts
import { Readable } from "stream";
import { serve } from "bun";
serve({
port: 3000,
fetch(req) {
return new Response(Readable.from(["Hello, ", "world!"]), {
headers: { "Content-Type": "text/plain" },
});
},
});
```

View File

@@ -26,7 +26,7 @@ password = "$NPM_PASSWORD"
---
Then assign your Azure Personal Access Token to the `NPM_PASSWORD` environment variable. Bun [automatically reads](/docs/runtime/env) `.env` files, so create a file called `.env` in your project root. There is no need to base-64 encode this token! Bun will do this for you.
Then assign your Azure Personal Access Token to the the `NPM_PASSWORD` environment variable. Bun [automatically reads](/docs/runtime/env) `.env` files, so create a file called `.env` in your project root. There is no need to base-64 encode this token! Bun will do this for you.
```txt#.env
NPM_PASSWORD=<paste token here>

View File

@@ -1,38 +0,0 @@
---
name: Configure git to diff Bun's lockb lockfile
---
To teach `git` how to generate a human-readable diff of Bun's binary lockfile format (`.lockb`), add the following to your local or global `.gitattributes` file:
```js
*.lockb binary diff=lockb
```
---
Then add the following to you local git config with:
```sh
$ git config diff.lockb.textconv bun
$ git config diff.lockb.binary true
```
---
To globally configure git to diff Bun's lockfile, add the following to your global git config with:
```sh
$ git config --global diff.lockb.textconv bun
$ git config --global diff.lockb.binary true
```
---
## How this works
Why this works:
- `textconv` tells git to run bun on the file before diffing
- `binary` tells git to treat the file as binary (so it doesn't try to diff it line-by-line)
In Bun, you can execute Bun's lockfile (`bun ./bun.lockb`) to generate a human-readable version of the lockfile and `git diff` can then use that to generate a human-readable diff.

View File

@@ -19,9 +19,7 @@ If you are seeing one of the following errors, you are probably trying to use a
To tell Bun to allow lifecycle scripts for a particular package, add the package to `trustedDependencies` in your package.json.
{% callout %}
Note that this only allows lifecycle scripts for the specific package listed in `trustedDependencies`, _not_ the dependencies of that dependency!
{% /callout %}
<!-- Bun maintains an allow-list of popular packages containing `postinstall` scripts that are known to be safe. To run lifecycle scripts for packages that aren't on this list, add the package to `trustedDependencies` in your package.json. -->
@@ -45,4 +43,8 @@ $ bun install
---
Note that this only allows lifecycle scripts for the specific package listed in `trustedDependencies`, _not_ the dependencies of that dependency!
---
See [Docs > Package manager > Trusted dependencies](/docs/install/lifecycle) for complete documentation of trusted dependencies.

View File

@@ -1,145 +0,0 @@
---
name: Define and replace static globals & constants
---
The `--define` flag lets you declare statically-analyzable constants and globals. It replace all usages of an identifier or property in a JavaScript or TypeScript file with a constant value. This feature is supported at runtime and also in `bun build`. This is sort of similar to `#define` in C/C++, except for JavaScript.
```ts
bun --define:process.env.NODE_ENV="'production'" src/index.ts # Runtime
bun build --define:process.env.NODE_ENV="'production'" src/index.ts # Build
```
---
These statically-known values are used by Bun for dead code elimination and other optimizations.
```ts
if (process.env.NODE_ENV === "production") {
console.log("Production mode");
} else {
console.log("Development mode");
}
```
---
Before the code reaches the JavaScript engine, Bun replaces `process.env.NODE_ENV` with `"production"`.
```ts
if ("production" === "production") {
console.log("Production mode");
} else {
console.log("Development mode");
}
```
---
It doesn't stop there. Bun's optimizing transpiler is smart enough to do some basic constant folding.
Since `"production" === "production"` is always `true`, Bun replaces the entire expression with the `true` value.
```ts
if (true) {
console.log("Production mode");
} else {
console.log("Development mode");
}
```
---
And finally, Bun detects the `else` branch is not reachable, and eliminates it.
```ts
console.log("Production mode");
```
---
## What types of values are supported?
Values can be strings, identifiers, properties, or JSON.
### Replace global identifiers
To make all usages of `window` be `undefined`, you can use the following command.
```sh
bun --define window="undefined" src/index.ts
```
This can be useful when Server-Side Rendering (SSR) or when you want to make sure that the code doesn't depend on the `window` object.
```js
if (typeof window !== "undefined") {
console.log("Client-side code");
} else {
console.log("Server-side code");
}
```
You can also set the value to be another identifier. For example, to make all usages of `global` be `globalThis`, you can use the following command.
```sh
bun --define global="globalThis" src/index.ts
```
`global` is a global object in Node.js, but not in web browsers. So, you can use this to fix some cases where the code assumes that `global` is available.
### Replace values with JSON
`--define` can also be used to replace values with JSON objects and arrays.
To replace all usages of `AWS` with the JSON object `{"ACCESS_KEY":"abc","SECRET_KEY":"def"}`, you can use the following command.
```sh
# JSON
bun --define:AWS='{"ACCESS_KEY":"abc","SECRET_KEY":"def"}' src/index.ts
```
Those will be transformed into the equivalent JavaScript code.
From:
```ts
console.log(AWS.ACCESS_KEY); // => "abc"
```
To:
```ts
console.log("abc");
```
### Replace values with other properties
You can also pass properties to the `--define` flag.
For example, to replace all usages of `console.write` with `console.log`, you can use the following command (requires Bun v1.1.5 or later)
```sh
bun --define:console.write=console.log src/index.ts
```
That transforms the following input:
```ts
console.write("Hello, world!");
```
Into the following output:
```ts
console.log("Hello, world!");
```
## How is this different than setting a variable?
You can also set `process.env.NODE_ENV` to `"production"` in your code, but that won't help with dead code elimination. In JavaScript, property accesses can have side effects. Getters & setters can be functions, and even dynamically defined (due to prototype chains and Proxy). Even if you set `process.env.NODE_ENV` to `"production"`, on the next line, it is not safe for static analysis tools to assume that `process.env.NODE_ENV`is`"production"`.
## How is this different than find-and-replace or string replacement?
The `--define` flag operates on the AST (Abstract Syntax Tree) level, not on the text level. It happens during the transpilation process, which means it can be used in optimizations like dead code elimination.
String replacement tools tend to have escaping issues and replace unintended parts of the code.

View File

@@ -1,15 +0,0 @@
---
name: Import HTML file as text
---
To import a `.html` file in Bun as a text file, use the `type: "text"` attribute in the import statement.
```ts
import html from "./file.html" with { type: "text" };
console.log(html); // <!DOCTYPE html><html><head>...
```
This can also be used with hot module reloading and/or watch mode to force Bun to reload whenever the `./file.html` file changes.
This feature was added in Bun v1.1.5.

View File

@@ -1,11 +0,0 @@
---
name: Convert a Node.js Readable to an ArrayBuffer
---
To convert a Node.js `Readable` stream to an `ArrayBuffer` in Bun, you can create a new `Response` object with the stream as the body, then use `arrayBuffer()` to read the stream into an `ArrayBuffer`.
```ts
import { Readable } from "stream";
const stream = Readable.from(["Hello, ", "world!"]);
const buf = await new Response(stream).arrayBuffer();
```

View File

@@ -1,11 +0,0 @@
---
name: Convert a Node.js Readable to a Blob
---
To convert a Node.js `Readable` stream to a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) in Bun, you can create a new [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object with the stream as the body, then use [`response.blob()`](https://developer.mozilla.org/en-US/docs/Web/API/Response/blob) to read the stream into a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
```ts
import { Readable } from "stream";
const stream = Readable.from(["Hello, ", "world!"]);
const blob = await new Response(stream).blob();
```

View File

@@ -1,12 +0,0 @@
---
name: Convert a Node.js Readable to JSON
---
To convert a Node.js `Readable` stream to a JSON object in Bun, you can create a new [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object with the stream as the body, then use [`response.json()`](https://developer.mozilla.org/en-US/docs/Web/API/Response/json) to read the stream into a JSON object.
```ts
import { Readable } from "stream";
const stream = Readable.from([JSON.stringify({ hello: "world" })]);
const json = await new Response(stream).json();
console.log(json); // { hello: "world" }
```

View File

@@ -1,12 +0,0 @@
---
name: Convert a Node.js Readable to a string
---
To convert a Node.js `Readable` stream to a string in Bun, you can create a new [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object with the stream as the body, then use [`response.text()`](https://developer.mozilla.org/en-US/docs/Web/API/Response/text) to read the stream into a string.
```ts
import { Readable } from "stream";
const stream = Readable.from([Buffer.from("Hello, world!")]);
const text = await new Response(stream).text();
console.log(text); // "Hello, world!"
```

View File

@@ -38,7 +38,7 @@ In the root `package.json`, the `"workspaces"` key is used to indicate which sub
```
{% callout %}
**Glob support** — Bun supports full glob syntax in `"workspaces"` (see [here](/docs/api/glob#supported-glob-patterns) for a comprehensive list of supported syntax), _except_ for exclusions (e.g. `!**/excluded/**`), which are not implemented yet.
**Glob support** — Bun supports simple `<directory>/*` globs in `"workspaces"`. Full glob syntax (e.g. `**` and `?`) is not yet supported.
{% /callout %}
Each workspace has it's own `package.json` When referencing other packages in the monorepo, use `"workspace:*"` as the version field in your `package.json`.
@@ -61,7 +61,6 @@ Workspaces have a couple major benefits.
- **Code can be split into logical parts.** If one package relies on another, you can simply add it as a dependency in `package.json`. If package `b` depends on `a`, `bun install` will install your local `packages/a` directory into `node_modules` instead of downloading it from the npm registry.
- **Dependencies can be de-duplicated.** If `a` and `b` share a common dependency, it will be _hoisted_ to the root `node_modules` directory. This reduces redundant disk usage and minimizes "dependency hell" issues associated with having multiple versions of a package installed simultaneously.
- **Run scripts in multiple packages.** You can use the [`--filter` flag](/docs/cli/filter) to easily run `package.json` scripts in multiple packages in your workspace.
{% callout %}
⚡️ **Speed** — Installs are fast, even for big monorepos. Bun installs the [Remix](https://github.com/remix-run/remix) monorepo in about `500ms` on Linux.

View File

@@ -1,4 +1,4 @@
Bun ships as a single executable with no dependencies that can be installed a few different ways.
Bun ships as a single executable that can be installed a few different ways.
## Installing
@@ -38,6 +38,10 @@ $ proto install bun
### Windows
{% callout %}
Bun requires a minimum of Windows 10 version 1809
{% /callout %}
To install, paste this into a terminal:
{% codetabs %}
@@ -50,16 +54,8 @@ To install, paste this into a terminal:
> npm install -g bun # the last `npm` command you'll ever need
```
```powershell#Scoop
> scoop install bun
```
{% /codetabs %}
{% callout %}
Bun requires a minimum of Windows 10 version 1809
{% /callout %}
For support and discussion, please join the [#windows channel on our Discord](http://bun.sh/discord).
## Docker
@@ -144,65 +140,21 @@ $ bun upgrade
{% callout %}
**Homebrew users** — To avoid conflicts with Homebrew, use `brew upgrade bun` instead.
**Scoop users** — To avoid conflicts with Scoop, use `scoop upgrade bun` instead.
**proto users** - Use `proto install bun --pin` instead.
{% /callout %}
## Canary builds
Bun automatically releases an (untested) canary build on every commit to `main`. To upgrade to the latest canary build:
```sh
$ bun upgrade --canary
```
The canary build is useful for testing new features and bug fixes before they're released in a stable build. To help the Bun team fix bugs faster, canary builds automatically upload crash reports to Bun's team.
[View canary build](https://github.com/oven-sh/bun/releases/tag/canary)
{% callout %}
**Note** — To switch back to a stable release from canary, run `bun upgrade --stable`.
**Note** — To switch back to a stable release from canary, run `bun upgrade` again with no flags.
{% /callout %}
## Installing older versions of Bun
Since Bun is a single binary, you can install older versions of Bun by re-running the installer script with a specific version.
### Installing a specific version of Bun on Linux/Mac
To install a specific version of Bun, you can pass the git tag of the version you want to install to the install script, such as `bun-v1.1.6` or `bun-v1.1.1`.
```sh
$ curl -fsSL https://bun.sh/install | bash -s "bun-v1.1.6"
```
### Installing a specific version of Bun on Windows
On Windows, you can install a specific version of Bun by passing the version number to the Powershell install script.
```sh
# PowerShell:
$ iex "& {$(irm https://bun.sh/install.ps1)} -Version 1.1.6"
```
## Downloading Bun binaries directly
To download Bun binaries directly, you can visit the [releases page](https://github.com/oven-sh/bun/releases) page on GitHub.
For convenience, here are download links for the latest version:
- [`bun-linux-x64.zip`](https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64.zip)
- [`bun-linux-x64-baseline.zip`](https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64-baseline.zip)
- [`bun-windows-x64.zip`](https://github.com/oven-sh/bun/releases/latest/download/bun-windows-x64.zip)
- [`bun-windows-x64-baseline.zip`](https://github.com/oven-sh/bun/releases/latest/download/bun-windows-x64-baseline.zip)
- [`bun-darwin-aarch64.zip`](https://github.com/oven-sh/bun/releases/latest/download/bun-darwin-aarch64.zip)
- [`bun-linux-aarch64.zip`](https://github.com/oven-sh/bun/releases/latest/download/bun-linux-aarch64.zip)
- [`bun-darwin-x64.zip`](https://github.com/oven-sh/bun/releases/latest/download/bun-darwin-x64.zip)
- [`bun-darwin-x64-baseline.zip`](https://github.com/oven-sh/bun/releases/latest/download/bun-darwin-x64-baseline.zip)
The `baseline` binaries are built for older CPUs which may not support AVX2 instructions. If you run into an "Illegal Instruction" error when running Bun, try using the `baseline` binaries instead. Bun's install scripts automatically choose the correct binary for your system which helps avoid this issue. Baseline builds are slower than regular builds, so use them only if necessary.
<!--
## Native
@@ -279,10 +231,6 @@ $ rm -rf ~/.bun # for macOS, Linux, and WSL
> powershell -c ~\.bun\uninstall.ps1
```
```powershell#Scoop
> scoop uninstall bun
```
```bash#npm
$ npm uninstall -g bun
```

View File

@@ -180,9 +180,6 @@ export default {
page("install/lifecycle", "Lifecycle scripts", {
description: "How Bun handles package lifecycle scripts with trustedDependencies",
}),
page("cli/filter", "Filter", {
description: "Run scripts in multiple packages in parallel",
}),
page("install/lockfile", "Lockfile", {
description:
"Bun's binary lockfile `bun.lockb` tracks your resolved dependency tree, making future installs fast and repeatable.",
@@ -309,9 +306,6 @@ export default {
page("api/tcp", "TCP sockets", {
description: `Bun's native API implements Web-standard TCP Sockets, plus a Bun-native API for building fast TCP servers.`,
}), // "`Bun.{listen|connect}`")
page("api/udp", "UDP sockets", {
description: `Bun's native API implements fast and flexible UDP sockets.`,
}), // "`Bun.udpSocket`")
page("api/globals", "Globals", {
description: `Bun implements a range of Web APIs, Node.js APIs, and Bun-native APIs that are available in the global scope.`,
}), // "`Bun.write`"),

View File

@@ -73,7 +73,7 @@ The Zig compiler is automatically downloaded, installed, and updated by the buil
> irm https://get.scoop.sh | iex
> scoop install nodejs-lts go rust nasm ruby perl
# scoop seems to be buggy if you install llvm and the rest at the same time
> scoop install llvm@16.0.6
> scoop llvm@16.0.4
```
If you intend on building WebKit locally (optional), you should install these packages:

View File

@@ -1 +0,0 @@
../../CONTRIBUTING.md

View File

@@ -0,0 +1,313 @@
Configuring a development environment for Bun can take 10-30 minutes depending on your internet connection and computer speed. You will need ~10GB of free disk space for the repository and build artifacts.
If you are using Windows, you must use a WSL environment as Bun does not yet compile on Windows natively.
## Install Dependencies
Using your system's package manager, install Bun's dependencies:
{% codetabs %}
```bash#macOS (Homebrew)
$ brew install automake ccache cmake coreutils gnu-sed go icu4c libiconv libtool ninja pkg-config rust ruby
```
```bash#Ubuntu/Debian
$ sudo apt install curl wget lsb-release software-properties-common cargo ccache cmake git golang libtool ninja-build pkg-config rustc ruby-full xz-utils
```
```bash#Arch
$ sudo pacman -S base-devel ccache cmake git go libiconv libtool make ninja pkg-config python rust sed unzip ruby
```
```bash#Fedora
$ sudo dnf install cargo ccache 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
$ sudo zypper install go cmake ninja automake git rustup && rustup toolchain install stable
```
{% /codetabs %}
> **Note**: The Zig compiler is automatically installed and updated by the build scripts. Manual installation is not required.
Before starting, you will need to already have a release build of Bun installed, as we use our bundler to transpile and minify our code, as well as for code generation scripts.
{% codetabs %}
```bash#Native
$ curl -fsSL https://bun.sh/install | bash
```
```bash#npm
$ npm install -g bun
```
```bash#Homebrew
$ brew tap oven-sh/bun
$ brew install bun
```
{% /codetabs %}
## Install LLVM
Bun requires LLVM 16 and Clang 16 (`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 %}
```bash#macOS (Homebrew)
$ brew install llvm@16
```
```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 -- 16 all
```
```bash#Arch
$ sudo pacman -S llvm clang lld
```
```bash#Fedora
$ sudo dnf install 'dnf-command(copr)'
$ sudo dnf copr enable -y @fedora-llvm-team/llvm-snapshots
$ sudo dnf install llvm clang lld
```
```bash#openSUSE Tumbleweed
$ sudo zypper install clang16 lld16 llvm16
```
{% /codetabs %}
If none of the above solutions apply, you will have to install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-16.0.6).
Make sure LLVM 16 is in your path:
```bash
$ which clang-16
```
If not, run this to manually link it:
{% codetabs %}
```bash#macOS (Homebrew)
# use fish_add_path if you're using fish
$ export PATH="$(brew --prefix llvm@16)/bin:$PATH"
```
```bash#Arch
# use fish_add_path if you're using fish
$ export PATH="$PATH:/usr/lib/llvm16/bin"
```
{% /codetabs %}
> ⚠️ Ubuntu distributions may require installation of the C++ standard library independently. See the [troubleshooting section](#span-file-not-found-on-ubuntu) for more information.
## Building Bun
After cloning the repository, run the following command to run the first build. This may take a while as it will clone submodules and build dependencies.
```bash
$ bun setup
```
The binary will be located at `./build/bun-debug`. It is recommended to add this to your `$PATH`. To verify the build worked, let's print the version number on the development build of Bun.
```bash
$ build/bun-debug --version
x.y.z_debug
```
To rebuild, you can invoke `bun run build`
```bash
$ bun run build
```
These two scripts, `setup` and `build`, are aliases to do roughly the following:
```bash
$ ./scripts/setup.sh
$ cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
$ ninja -C build # 'bun run build' runs just this
```
Advanced users can pass CMake flags to customize the build.
## VSCode
VSCode is the recommended IDE for working on Bun, as it has been configured. Once opening, you can run `Extensions: Show Recommended Extensions` to install the recommended extensions for Zig and C++. ZLS is automatically configured.
If you use a different editor, make sure that you tell ZLS to use the automatically installed Zig compiler, which is located at `./.cache/zig/zig` (`zig.exe` on Windows).
## Code generation scripts
{% callout %}
**Note**: This section is outdated. The code generators are run automatically by ninja, instead of by `make`.
{% /callout %}
Bun leverages a lot of code generation scripts.
The [./src/bun.js/bindings/headers.h](https://github.com/oven-sh/bun/blob/main/src/bun.js/bindings/headers.h) file has bindings to & from Zig <> C++ code. This file is generated by running the following:
```bash
$ make headers
```
This ensures that the types for Zig and the types for C++ match up correctly, by using comptime reflection over functions exported/imported.
TypeScript files that end with `*.classes.ts` are another code generation script. They generate C++ boilerplate for classes implemented in Zig. The generated code lives in:
- [src/bun.js/bindings/ZigGeneratedClasses.cpp](https://github.com/oven-sh/bun/tree/main/src/bun.js/bindings/ZigGeneratedClasses.cpp)
- [src/bun.js/bindings/ZigGeneratedClasses.h](https://github.com/oven-sh/bun/tree/main/src/bun.js/bindings/ZigGeneratedClasses.h)
- [src/bun.js/bindings/generated_classes.zig](https://github.com/oven-sh/bun/tree/main/src/bun.js/bindings/generated_classes.zig)
To generate the code, run:
```bash
$ make codegen
```
Lastly, we also have a [code generation script](src/bun.js/scripts/generate-jssink.js) for our native stream implementations.
To run that, run:
```bash
$ make generate-sink
```
You probably won't need to run that one much.
## Modifying ESM modules
Certain modules like `node:fs`, `node:stream`, `bun:sqlite`, and `ws` are implemented in JavaScript. These live in `src/js/{node,bun,thirdparty}` files and are pre-bundled using Bun. In debug builds, Bun automatically loads these from the filesystem, wherever it was compiled, so no need to re-run `make dev`.
## Release build
To build a release build of Bun, run:
```bash
$ bun run build:release
```
The binary will be located at `./build-release/bun` and `./build-release/bun-profile`.
## Valgrind
On Linux, valgrind can help find memory issues.
Keep in mind:
- JavaScriptCore doesn't support valgrind. It will report spurious errors.
- Valgrind is slow
- Mimalloc will sometimes cause spurious errors when debug build is enabled
You'll need a very recent version of Valgrind due to DWARF 5 debug symbols. You may need to manually compile Valgrind instead of using it from your Linux package manager.
`--fair-sched=try` is necessary if running multithreaded code in Bun (such as the bundler). Otherwise it will hang.
```bash
$ valgrind --fair-sched=try --track-origins=yes bun-debug <args>
```
## Building WebKit locally + Debug mode of JSC
{% callout %}
**TODO**: This is out of date. TLDR is pass `-DUSE_DEBUG_JSC=1` or `-DWEBKIT_DIR=...` to CMake. it will probably need more fiddling. ask @paperdave if you need this.
{% /callout %}
WebKit is not cloned by default (to save time and disk space). To clone and build WebKit locally, run:
```bash
# once you run this, `make submodule` can be used to automatically
# update WebKit and the other submodules
$ git submodule update --init --depth 1 --checkout src/bun.js/WebKit
# to make a jsc release build
$ make jsc
# JSC debug build does not work perfectly with Bun yet, this is actively being
# worked on and will eventually become the default.
$ make jsc-build-linux-compile-debug cpp
$ make jsc-build-mac-compile-debug cpp
```
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.
## Troubleshooting
### 'span' file not found on Ubuntu
> ⚠️ Please note that the instructions below are specific to issues occurring on Ubuntu. It is unlikely that the same issues will occur on other Linux distributions.
The Clang compiler typically uses the `libstdc++` C++ standard library by default. `libstdc++` is the default C++ Standard Library implementation provided by the GNU Compiler Collection (GCC). While Clang may link against the `libc++` library, this requires explicitly providing the `-stdlib` flag when running Clang.
Bun relies on C++20 features like `std::span`, which are not available in GCC versions lower than 11. GCC 10 doesn't have all of the C++20 features implemented. As a result, running `make setup` may fail with the following error:
```
fatal error: 'span' file not found
#include <span>
^~~~~~
```
The issue may manifest when initially running `bun setup` as Clang being unable to compile a simple program:
```
The C++ compiler
"/usr/bin/clang++-16"
is not able to compile a simple test program.
```
To fix the error, we need to update the GCC version to 11. To do this, we'll need to check if the latest version is available in the distribution's official repositories or use a third-party repository that provides GCC 11 packages. Here are general steps:
```bash
$ sudo apt update
$ sudo apt install gcc-11 g++-11
# If the above command fails with `Unable to locate package gcc-11` we need
# to add the APT repository
$ sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
# Now run `apt install` again
$ sudo apt install gcc-11 g++-11
```
Now, we need to set GCC 11 as the default compiler:
```bash
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 100
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 100
```
### libarchive
If you see an error when compiling `libarchive`, run this:
```bash
$ brew install pkg-config
```
### macOS `library not found for -lSystem`
If you see this error when compiling, run:
```bash
$ xcode-select --install
```
## Cannot find `libatomic.a`
Bun defaults to linking `libatomic` statically, as not all systems have it. If you are building on a distro that does not have a static libatomic available, you can run the following command to enable dynamic linking:
```bash
$ bun setup -DUSE_STATIC_LIBATOMIC=OFF
```
The built version of Bun may not work on other systems if compiled this way.

View File

@@ -36,8 +36,7 @@ Some methods are not optimized yet.
### [`node:dgram`](https://nodejs.org/api/dgram.html)
🟡 Missing `setBroadcast` `setTTL` `setMulticastTTL` `setMulticastLoopback` `setMulticastInterface` `addMembership` `dropMembership`
`addSourceSpecificMembership` `dropSourceSpecificMembership`
🔴 Not implemented.
### [`node:diagnostics_channel`](https://nodejs.org/api/diagnostics_channel.html)
@@ -81,7 +80,7 @@ Some methods are not optimized yet.
### [`node:net`](https://nodejs.org/api/net.html)
🟡 Missing `SocketAddress` `Stream`. `BlockList` exists but is a no-op.
🟡 Missing `BlockList` `SocketAddress` `Stream` `getDefaultAutoSelectFamily` `getDefaultAutoSelectFamilyAttemptTimeout` `setDefaultAutoSelectFamily` `setDefaultAutoSelectFamilyAttemptTimeout`
### [`node:os`](https://nodejs.org/api/os.html)
@@ -173,7 +172,7 @@ Some methods are not optimized yet.
### [`node:zlib`](https://nodejs.org/api/zlib.html)
🟡 Unoptimized.
🟡 Missing `BrotliCompress` `BrotliDecompress` `brotliCompressSync` `brotliDecompress` `brotliDecompressSync` `createBrotliCompress` `createBrotliDecompress`. Unoptimized.
## Globals
@@ -341,7 +340,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa
### [`process`](https://nodejs.org/api/process.html)
🟡 Missing `domain` `initgroups` `setegid` `seteuid` `setgid` `setgroups` `setuid` `allowedNodeEnvironmentFlags` `getActiveResourcesInfo` `setActiveResourcesInfo` `moduleLoadList` `setSourceMapsEnabled` `channel`. `process.binding` is partially implemented.
🟡 Missing `domain` `hasUncaughtExceptionCaptureCallback` `initgroups` `resourceUsage` `setUncaughtExceptionCaptureCallback` `setegid` `seteuid` `setgid` `setgroups` `setuid` `allowedNodeEnvironmentFlags` `getActiveResourcesInfo` `setActiveResourcesInfo` `moduleLoadList` `setSourceMapsEnabled` `channel`. `process.binding` is partially implemented.
### [`queueMicrotask()`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask)

View File

@@ -74,8 +74,8 @@ try {
console.log(output);
} catch (err) {
console.log(`Failed with code ${err.exitCode}`);
console.log(err.stdout.toString());
console.log(err.stderr.toString());
console.log(output.stdout.toString());
console.log(output.stderr.toString());
}
```
@@ -99,7 +99,6 @@ console.log(stderr);
The default handling of non-zero exit codes can be configured by calling `.nothrow()` or `.throws(boolean)` on the `$` function itself.
```js
import { $ } from "bun";
// shell promises will not throw, meaning you will have to
// check for `exitCode` manually on every shell command.
$.nothrow(); // equivilent to $.throws(false)
@@ -109,8 +108,6 @@ $.throws(true);
// alias for $.nothrow()
$.throws(false);
await $`something-that-may-fail`; // No exception thrown
```
## Redirection
@@ -152,7 +149,7 @@ The following JavaScript objects are supported for redirection to:
To redirect the output from JavaScript objects to stdin, use the `<` operator:
```js
import { $ } from "bun";
import { $, file } from "bun";
const response = new Response("hello i am a response body");
@@ -191,7 +188,7 @@ import { $ } from "bun";
await $`bun run index.ts 2> errors.txt`;
```
### Example: Redirect stderr -> stdout
### Example: Redirect stdout -> stderr
```js
import { $ } from "bun";
@@ -201,7 +198,7 @@ import { $ } from "bun";
await $`bun run ./index.ts 2>&1`;
```
### Example: Redirect stdout -> stderr
### Example: Redirect stderr -> stdout
```js
import { $ } from "bun";
@@ -399,18 +396,6 @@ For cross-platform compatibility, Bun Shell implements a set of builtin commands
- `echo`: print text
- `pwd`: print the working directory
- `bun`: run bun in bun
- `cat`
- `touch`
- `mkdir`
- `which`
- `mv`
- `exit`
- `true`
- `false`
- `yes`
- `seq`
- `dirname`
- `basename`
**Partially** implemented:
@@ -418,7 +403,9 @@ For cross-platform compatibility, Bun Shell implements a set of builtin commands
**Not** implemented yet, but planned:
- See https://github.com/oven-sh/bun/issues/9716 for the full list.
- `mkdir`: create directories
- `cp`: copy files and directories
- `cat`: concatenate files
## Utilities

View File

@@ -57,7 +57,7 @@ coverageThreshold = { lines = 0.9, functions = 0.9 }
### Sourcemaps
Internally, Bun transpiles all files by default, so Bun automatically generates an internal [source map](https://web.dev/source-maps/) that maps lines of your original source code onto Bun's internal representation. If for any reason you want to disable this, set `test.coverageIgnoreSourcemaps` to `true`; this will rarely be desirable outside of advanced use cases.
Internally, Bun transpiles all files by default, so Bun automatically generates an internal [source map](https://web.dev/source-maps/) that maps lines of your original source code onto Bun's internal representation. If for any reason you want to disable this, set `test.coverageIgnoreSourcemaps` to `false`; this will rarely be desirable outside of advanced use cases.
```toml
[test]

View File

@@ -1,18 +0,0 @@
let internal;
try {
internal = require("bun:internal-for-testing");
} catch {
const result = Bun.spawnSync({
cmd: [process.execPath, import.meta.file],
env: {
...process.env,
BUN_DEBUG_QUIET_LOGS: "1",
BUN_GARBAGE_COLLECTOR_LEVEL: "0",
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "1",
},
});
process.exit(result.exitCode);
}
if (internal) {
console.log(JSON.stringify(internal.crash_handler.getFeatureData(), null, 2));
}

View File

@@ -14,13 +14,13 @@ pub usingnamespace @import("root").bun;
const clap = bun.clap;
const URL = @import("../src/url.zig").URL;
const Headers = bun.http.Headers;
const Headers = @import("root").bun.http.Headers;
const Method = @import("../src/http/method.zig").Method;
const ColonListType = @import("../src/cli/colon_list_type.zig").ColonListType;
const HeadersTuple = ColonListType(string, noop_resolver);
const path_handler = @import("../src/resolver/resolve_path.zig");
const HTTPThread = bun.http.HTTPThread;
const HTTP = bun.http;
const HTTPThread = @import("root").bun.http.HTTPThread;
const HTTP = @import("root").bun.http;
fn noop_resolver(in: string) !string {
return in;
}

View File

@@ -177,7 +177,7 @@ pub const Arguments = struct {
}
};
const HTTP = bun.http;
const HTTP = @import("root").bun.http;
const NetworkThread = HTTP.NetworkThread;
var stdout_: std.fs.File = undefined;

View File

@@ -13,13 +13,13 @@ const C = bun.C;
const clap = @import("../src/deps/zig-clap/clap.zig");
const URL = @import("../src/url.zig").URL;
const Headers = bun.http.Headers;
const Headers = @import("root").bun.http.Headers;
const Method = @import("../src/http/method.zig").Method;
const ColonListType = @import("../src/cli/colon_list_type.zig").ColonListType;
const HeadersTuple = ColonListType(string, noop_resolver);
const path_handler = @import("../src/resolver/resolve_path.zig");
const NetworkThread = bun.http.NetworkThread;
const HTTP = bun.http;
const NetworkThread = @import("root").bun.http.NetworkThread;
const HTTP = @import("root").bun.http;
fn noop_resolver(in: string) !string {
return in;
}

View File

@@ -21,13 +21,11 @@
},
"scripts": {
"setup": "./scripts/setup.sh",
"bump": "bun ./scripts/bump.ts",
"build": "if [ ! -e build ]; then bun setup; fi && ninja -C build",
"build:valgrind": "cmake . -DZIG_OPTIMIZE=Debug -DUSE_DEBUG_JSC=ON -DCMAKE_BUILD_TYPE=Debug -GNinja -Bbuild-valgrind && ninja -Cbuild-valgrind",
"build:release": "cmake . -DCMAKE_BUILD_TYPE=Release -GNinja -Bbuild-release && ninja -Cbuild-release",
"build:debug-zig-release": "cmake . -DCMAKE_BUILD_TYPE=Release -DZIG_OPTIMIZE=Debug -GNinja -Bbuild-debug-zig-release && ninja -Cbuild-debug-zig-release",
"build:safe": "cmake . -DZIG_OPTIMIZE=ReleaseSafe -DUSE_DEBUG_JSC=ON -DCMAKE_BUILD_TYPE=Release -GNinja -Bbuild-safe && ninja -Cbuild-safe",
"build:windows": "cmake -B build -S . -G Ninja -DCMAKE_BUILD_TYPE=Debug && ninja -Cbuild",
"typecheck": "tsc --noEmit && cd test && bun run typecheck",
"fmt": "prettier --write --cache './{.vscode,src,test,bench,packages/{bun-types,bun-inspector-*,bun-vscode,bun-debug-adapter-protocol}}/**/*.{mjs,ts,tsx,js,jsx}'",
"fmt:zig": "zig fmt src/*.zig src/*/*.zig src/*/*/*.zig src/*/*/*/*.zig",

View File

@@ -1,13 +0,0 @@
{
" != undefined": "This is by definition Undefined Behavior.",
" == undefined": "This is by definition Undefined Behavior.",
"@import(\"root\").bun.": "Only import 'bun' once",
"std.debug.assert": "Use bun.assert instead",
"std.debug.dumpStackTrace": "Use bun.handleErrorReturnTrace or bun.crash_handler.dumpStackTrace instead",
"std.debug.print": "Don't let this be committed",
"std.mem.indexOfAny": "Use bun.strings.indexAny or bun.strings.indexAnyComptime",
"undefined != ": "This is by definition Undefined Behavior.",
"undefined == ": "This is by definition Undefined Behavior.",
"bun.toFD(std.fs.cwd().fd)": "Use bun.FD.cwd()",
"": ""
}

View File

@@ -1,72 +0,0 @@
import { $ } from "bun";
import BANNED from "./banned.json";
import * as action from "@actions/core";
const IGNORED_FOLDERS = [
// list of folders to ignore
"windows-shim",
];
const ci = !!process.env["GITHUB_ACTIONS"];
process.chdir(require("path").join(import.meta.dir, "../../../"));
let bad = [];
let report = "";
const write = (text: string) => {
process.stdout.write(text);
report += text;
};
for (const [banned, suggestion] of Object.entries(BANNED)) {
if (banned.length === 0) continue;
// Run git grep to find occurrences of std.debug.assert in .zig files
// .nothrow() is here since git will exit with non-zero if no matches are found.
let stdout = await $`git grep -n -F "${banned}" "src/**/**.zig" | grep -v -F '//' | grep -v -F bench`
.nothrow()
.text();
stdout = stdout.trim();
if (stdout.length === 0) continue;
let lines = stdout.split("\n");
// Parse each line to extract filename and line number
const matches = lines
.filter(line => !IGNORED_FOLDERS.some(folder => line.includes(folder)))
.map(line => {
const [path, lineNumber, ...text] = line.split(":");
return { path, lineNumber, banned, suggestion, text: text.join(":") };
});
// Check if we got any output
// Split the output into lines
if (matches.length === 0) continue;
write(`Banned **'${banned}'** found in the following locations:` + "\n");
matches.forEach(match => {
write(`${match.path}:${match.lineNumber}: ${match.text.trim()}` + "\n");
});
bad = bad.concat(matches);
}
if (report.length === 0) {
process.exit(0);
}
function link({ path, lineNumber, suggestion, banned }) {
action.error(`Lint failure: ${banned} is banned, ${suggestion}`, {
file: path,
startLine: Number(lineNumber),
endLine: Number(lineNumber),
});
return `[\`${path}:${lineNumber}\`](https://github.com/oven-sh/bun/blob/${process.env.GITHUB_SHA}/${path}#L${lineNumber})`;
}
if (ci) {
if (report.length > 0) {
action.setFailed(`${bad.length} lint failures`);
}
action.setOutput("count", bad.length);
action.setOutput("text_output", bad.map(m => `- ${link(m)}: ${m.banned} is banned, ${m.suggestion}`).join("\n"));
action.setOutput("json_output", JSON.stringify(bad));
action.summary.addRaw(report);
await action.summary.write();
}
process.exit(1);

View File

@@ -1,10 +1,11 @@
import * as action from "@actions/core";
import { spawn, spawnSync } from "child_process";
import { rmSync, writeFileSync, readFileSync, mkdirSync, openSync, closeSync } from "fs";
import { rmSync, writeFileSync, readFileSync, mkdirSync, openSync, close, closeSync } from "fs";
import { readFile, rm } from "fs/promises";
import { readdirSync } from "node:fs";
import { resolve, basename } from "node:path";
import { cpus, hostname, tmpdir, totalmem, userInfo } from "os";
import { join, normalize, posix, relative } from "path";
import { constants, cpus, hostname, tmpdir, totalmem, userInfo } from "os";
import { join, normalize } from "path";
import { fileURLToPath } from "url";
import PQueue from "p-queue";
@@ -21,7 +22,9 @@ function defaultConcurrency() {
return Math.min(Math.floor((cpus().length - 2) / 2), 2);
}
const windows = process.platform === "win32";
const KEEP_TMPDIR = process.env["BUN_KEEP_TMPDIR"] === "1";
const nativeMemory = totalmem();
const force_ram_size_input = parseInt(process.env["BUN_JSC_forceRAMSize"] || "0", 10);
let force_ram_size = Number(BigInt(nativeMemory) >> BigInt(2)) + "";
@@ -205,15 +208,14 @@ function checkSlowTests() {
setInterval(checkSlowTests, SHORT_TIMEOUT_DURATION).unref();
var currentTestNumber = 0;
async function runTest(path) {
const pathOnDisk = resolve(path);
const thisTestNumber = currentTestNumber++;
const testFileName = posix.normalize(relative(cwd, path).replaceAll("\\", "/"));
const name = path.replace(cwd, "").slice(1);
let exitCode, signal, err, output;
const start = Date.now();
const activeTestObject = { start, proc: undefined };
activeTests.set(testFileName, activeTestObject);
activeTests.set(path, activeTestObject);
try {
await new Promise((finish, reject) => {
@@ -223,12 +225,12 @@ async function runTest(path) {
at ${((start - run_start.getTime()) / 1000).toFixed(2)}s, file ${thisTestNumber
.toString()
.padStart(total.toString().length, "0")}/${total}, ${failing_tests.length} failing files
Starting "${testFileName}"
Starting "${name}"
`,
);
const TMPDIR = maketemp();
const proc = spawn(bunExe, ["test", pathOnDisk], {
const proc = spawn(bunExe, ["test", resolve(path)], {
stdio: ["ignore", "pipe", "pipe"],
env: {
...process.env,
@@ -238,8 +240,6 @@ Starting "${testFileName}"
BUN_RUNTIME_TRANSPILER_CACHE_PATH: "0",
GITHUB_ACTIONS: process.env.GITHUB_ACTIONS ?? "true",
BUN_DEBUG_QUIET_LOGS: "1",
BUN_INSTALL_CACHE_DIR: join(TMPDIR, ".bun-install-cache"),
BUN_ENABLE_CRASH_REPORTING: "1",
[windows ? "TEMP" : "TMPDIR"]: TMPDIR,
},
});
@@ -300,7 +300,7 @@ Starting "${testFileName}"
});
});
} finally {
activeTests.delete(testFileName);
activeTests.delete(path);
}
if (!hasInitialMaxFD) {
@@ -310,7 +310,7 @@ Starting "${testFileName}"
maxFd = getMaxFileDescriptor();
if (maxFd > prevMaxFd + queue.concurrency * 2) {
process.stderr.write(
`\n\x1b[31mewarn\x1b[0;2m:\x1b[0m file descriptor leak in ${testFileName}, delta: ${
`\n\x1b[31mewarn\x1b[0;2m:\x1b[0m file descriptor leak in ${name}, delta: ${
maxFd - prevMaxFd
}, current: ${maxFd}, previous: ${prevMaxFd}\n`,
);
@@ -362,7 +362,7 @@ Starting "${testFileName}"
console.log(
`\x1b[2m${formatTime(duration).padStart(6, " ")}\x1b[0m ${
passed ? "\x1b[32m✔" : "\x1b[31m✖"
} ${testFileName}\x1b[0m${reason ? ` (${reason})` : ""}`,
} ${name}\x1b[0m${reason ? ` (${reason})` : ""}`,
);
finished++;
@@ -376,11 +376,11 @@ Starting "${testFileName}"
}
if (!passed) {
failing_tests.push({ path: testFileName, reason, output });
failing_tests.push({ path: name, reason, output });
process.exitCode = 1;
if (err) console.error(err);
} else {
passing_tests.push(testFileName);
passing_tests.push(name);
}
return passed;
@@ -496,17 +496,9 @@ if (failing_tests.length) {
report += "[Link to file](" + linkToGH(path) + ")\n\n";
report += `${reason}\n\n`;
report += "```\n";
let failing_output = output
report += output
.replace(/\x1b\[[0-9;]*m/g, "")
.replace(/^::(group|endgroup|error|warning|set-output|add-matcher|remove-matcher).*$/gm, "");
if (failing_output.length > 1024 * 64) {
failing_output = failing_output.slice(0, 1024 * 64) + `\n\n[truncated output (length: ${failing_output.length})]`;
}
report += failing_output;
report += "```\n\n";
}
}
@@ -520,31 +512,7 @@ writeFileSync(
}),
);
function mabeCapitalize(str) {
str = str.toLowerCase();
if (str.includes("arm64") || str.includes("aarch64")) {
return str.toUpperCase();
}
if (str.includes("x64")) {
return "x64";
}
if (str.includes("baseline")) {
return str;
}
return str[0].toUpperCase() + str.slice(1);
}
console.log("-> test-report.md, test-report.json");
function linkify(text, url) {
if (url?.startsWith?.("https://")) {
return `[${text}](${url})`;
}
return text;
}
if (ci) {
if (failing_tests.length > 0) {
@@ -552,21 +520,6 @@ if (ci) {
}
action.setOutput("failing_tests", failingTestDisplay);
action.setOutput("failing_tests_count", failing_tests.length);
if (failing_tests.length) {
const { env } = process;
const tag = process.env.BUN_TAG || "unknown";
const url = `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}`;
let comment = `## ${linkify(`${emojiTag(tag)}${failing_tests.length} failing tests`, url)} ${tag
.split("-")
.map(mabeCapitalize)
.join(" ")}
${failingTestDisplay}
`;
writeFileSync("comment.md", comment);
}
let truncated_report = report;
if (truncated_report.length > 512 * 1000) {
truncated_report = truncated_report.slice(0, 512 * 1000) + "\n\n...truncated...";
@@ -575,38 +528,4 @@ ${failingTestDisplay}
await action.summary.write();
}
function emojiTag(tag) {
let emojiText = "";
tag = tag.toLowerCase();
if (tag.includes("win32") || tag.includes("windows")) {
emojiText += "🪟";
}
if (tag.includes("linux")) {
emojiText += "🐧";
}
if (tag.includes("macos") || tag.includes("darwin")) {
emojiText += "";
}
if (tag.includes("x86") || tag.includes("x64") || tag.includes("_64") || tag.includes("amd64")) {
if (!tag.includes("linux")) {
emojiText += "💻";
} else {
emojiText += "🖥";
}
}
if (tag.includes("arm64") || tag.includes("aarch64")) {
emojiText += "💪";
}
if (emojiText) {
emojiText += " ";
}
return emojiText;
}
process.exit(failing_tests.length ? 1 : process.exitCode);

View File

@@ -1,32 +1,16 @@
import { AwsClient } from "aws4fetch";
import { getBuild, getRelease, getSemver, getSha } from "../src/github";
const dryRun = process.argv.includes("--dry-run");
import { getBuild, getRelease, getSemver } from "../src/github";
const [tag] = process.argv.slice(2);
let bucketUrl;
let aws: AwsClient;
try {
bucketUrl = new URL(`${env("AWS_BUCKET")}/`, env("AWS_ENDPOINT"));
aws = new AwsClient({
accessKeyId: env("AWS_ACCESS_KEY_ID"),
secretAccessKey: env("AWS_SECRET_ACCESS_KEY"),
});
} catch (error) {
bucketUrl = new URL(`bun/`, "https://s3.amazonaws.com");
console.error("Failed to create S3 client:", error);
if (!dryRun) {
process.exit(1);
}
console.log("since this is a dry run, i'll allow it");
}
const bucketUrl = new URL(`${env("AWS_BUCKET")}/`, env("AWS_ENDPOINT"));
const aws = new AwsClient({
accessKeyId: env("AWS_ACCESS_KEY_ID"),
secretAccessKey: env("AWS_SECRET_ACCESS_KEY"),
});
const latest = await getRelease();
const release = await getRelease(tag);
const full_commit_hash = await getSha(tag, "long");
console.log("Found release:", release.tag_name, "with commit hash:", full_commit_hash);
console.log("Found build:", full_commit_hash);
console.log("Found release:", release.tag_name);
let paths: string[];
if (latest.tag_name === release.tag_name) {
@@ -34,13 +18,13 @@ if (latest.tag_name === release.tag_name) {
} else if (release.tag_name === "canary") {
try {
const build = await getSemver("canary", await getBuild());
paths = ["releases/canary", `releases/${build}`, `releases/${full_commit_hash}`];
paths = ["releases/canary", `releases/${build}`];
} catch (error) {
console.warn(error);
paths = ["releases/canary"];
}
} else {
paths = [`releases/${release.tag_name}`, `releases/${full_commit_hash}`];
paths = [`releases/${release.tag_name}`];
}
console.log("Found paths:", paths);
@@ -94,10 +78,6 @@ async function uploadToS3({
};
}): Promise<void> {
const { href } = new URL(key, bucketUrl);
if (dryRun) {
console.log("Would upload:", key, "to", href);
return;
}
const response = await aws.fetch(href, {
method: "PUT",
body,

View File

@@ -111,7 +111,7 @@ function isWindowsAVX2(): boolean {
spawn("powershell", [
"-c",
`(Add-Type -MemberDefinition '[DllImport("kernel32.dll")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);' -Name 'Kernel32' -Namespace 'Win32' -PassThru)::IsProcessorFeaturePresent(40);`,
]).stdout.trim() === "True"
]).stdout == "True"
);
} catch (error) {
debug("isWindowsAVX2 failed", error);

View File

@@ -2414,7 +2414,7 @@ declare module "bun" {
extends WebSocketServeOptions<WebSocketDataType>,
TLSOptions {
unix?: never;
tls?: TLSOptions | Array<TLSOptions>;
tls?: TLSOptions;
}
interface UnixTLSWebSocketServeOptions<WebSocketDataType = undefined>
extends UnixWebSocketServeOptions<WebSocketDataType>,
@@ -2424,7 +2424,7 @@ declare module "bun" {
* (Cannot be used with hostname+port)
*/
unix: string;
tls?: TLSOptions | Array<TLSOptions>;
tls?: TLSOptions;
}
interface ErrorLike extends Error {
code?: string;
@@ -2493,11 +2493,23 @@ declare module "bun" {
}
interface TLSServeOptions extends ServeOptions, TLSOptions {
tls?: TLSOptions | Array<TLSOptions>;
/**
* The keys are [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) hostnames.
* The values are SSL options objects.
*/
serverNames?: Record<string, TLSOptions>;
tls?: TLSOptions;
}
interface UnixTLSServeOptions extends UnixServeOptions, TLSOptions {
tls?: TLSOptions | Array<TLSOptions>;
/**
* The keys are [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) hostnames.
* The values are SSL options objects.
*/
serverNames?: Record<string, TLSOptions>;
tls?: TLSOptions;
}
interface SocketAddress {
@@ -2980,19 +2992,12 @@ declare module "bun" {
}
/**
* Returns the number of nanoseconds since the process was started.
* Nanoseconds since Bun.js was started as an integer.
*
* This function uses a high-resolution monotonic system timer to provide precise time measurements.
* In JavaScript, numbers are represented as double-precision floating-point values (IEEE 754),
* which can safely represent integers up to 2^53 - 1 (Number.MAX_SAFE_INTEGER).
* This uses a high-resolution monotonic system timer.
*
* Due to this limitation, while the internal counter may continue beyond this point,
* the precision of the returned value will degrade after 14.8 weeks of uptime (when the nanosecond
* count exceeds Number.MAX_SAFE_INTEGER). Beyond this point, the function will continue to count but
* with reduced precision, which might affect time calculations and comparisons in long-running applications.
*
* @returns {number} The number of nanoseconds since the process was started, with precise values up to
* Number.MAX_SAFE_INTEGER.
* After 14 weeks of consecutive uptime, this function
* wraps
*/
function nanoseconds(): number;
@@ -3065,7 +3070,6 @@ declare module "bun" {
type SupportedCryptoAlgorithms =
| "blake2b256"
| "blake2b512"
| "md4"
| "md5"
| "ripemd160"
@@ -3074,13 +3078,7 @@ declare module "bun" {
| "sha256"
| "sha384"
| "sha512"
| "sha512-224"
| "sha512-256"
| "sha3-224"
| "sha3-256"
| "sha3-384"
| "sha3-512";
| "sha512-256";
/**
* Hardware-accelerated cryptographic hash functions
*
@@ -3973,91 +3971,6 @@ declare module "bun" {
function listen<Data = undefined>(options: TCPSocketListenOptions<Data>): TCPSocketListener<Data>;
function listen<Data = undefined>(options: UnixSocketOptions<Data>): UnixSocketListener<Data>;
namespace udp {
type Data = string | ArrayBufferView | ArrayBufferLike;
export interface SocketHandler<DataBinaryType extends BinaryType> {
data?(
socket: Socket<DataBinaryType>,
data: BinaryTypeList[DataBinaryType],
port: number,
address: string,
): void | Promise<void>;
drain?(socket: Socket<DataBinaryType>): void | Promise<void>;
error?(socket: Socket<DataBinaryType>, error: Error): void | Promise<void>;
}
export interface ConnectedSocketHandler<DataBinaryType extends BinaryType> {
data?(
socket: ConnectedSocket<DataBinaryType>,
data: BinaryTypeList[DataBinaryType],
port: number,
address: string,
): void | Promise<void>;
drain?(socket: ConnectedSocket<DataBinaryType>): void | Promise<void>;
error?(socket: ConnectedSocket<DataBinaryType>, error: Error): void | Promise<void>;
}
export interface SocketOptions<DataBinaryType extends BinaryType> {
hostname?: string;
port?: number;
binaryType?: DataBinaryType;
socket?: SocketHandler<DataBinaryType>;
}
export interface ConnectSocketOptions<DataBinaryType extends BinaryType> {
hostname?: string;
port?: number;
binaryType?: DataBinaryType;
socket?: ConnectedSocketHandler<DataBinaryType>;
connect: {
hostname: string;
port: number;
};
}
export interface BaseUDPSocket {
readonly hostname: string;
readonly port: number;
readonly address: SocketAddress;
readonly binaryType: BinaryType;
readonly closed: boolean;
ref(): void;
unref(): void;
close(): void;
}
export interface ConnectedSocket<DataBinaryType extends BinaryType> extends BaseUDPSocket {
readonly remoteAddress: SocketAddress;
sendMany(packets: readonly Data[]): number;
send(data: Data): boolean;
reload(handler: ConnectedSocketHandler<DataBinaryType>): void;
}
export interface Socket<DataBinaryType extends BinaryType> extends BaseUDPSocket {
sendMany(packets: readonly (Data | string | number)[]): number;
send(data: Data, port: number, address: string): boolean;
reload(handler: SocketHandler<DataBinaryType>): void;
}
}
/**
* Create a UDP socket
*
* @param options The options to use when creating the server
* @param options.socket The socket handler to use
* @param options.hostname The hostname to listen on
* @param options.port The port to listen on
* @param options.binaryType The binary type to use for the socket
* @param options.connect The hostname and port to connect to
*/
export function udpSocket<DataBinaryType extends BinaryType = "buffer">(
options: udp.SocketOptions<DataBinaryType>,
): Promise<udp.Socket<DataBinaryType>>;
export function udpSocket<DataBinaryType extends BinaryType = "buffer">(
options: udp.ConnectSocketOptions<DataBinaryType>,
): Promise<udp.ConnectedSocket<DataBinaryType>>;
namespace SpawnOptions {
/**
* Option for stdout/stderr
@@ -4225,11 +4138,6 @@ declare module "bun" {
*/
windowsHide?: boolean;
/**
* If true, no quoting or escaping of arguments is done on Windows.
*/
windowsVerbatimArguments?: boolean;
/**
* Path to the executable to run in the subprocess. This defaults to `cmds[0]`.
*
@@ -4755,6 +4663,34 @@ declare module "bun" {
*/
function indexOfLine(buffer: ArrayBufferView | ArrayBufferLike, offset?: number): number;
/**
* Provides a higher level API for command-line argument parsing than interacting
* with `process.argv` directly. Takes a specification for the expected arguments
* and returns a structured object with the parsed options and positionals.
*
* ```js
* const args = ['-f', '--bar', 'b'];
* const options = {
* foo: {
* type: 'boolean',
* short: 'f',
* },
* bar: {
* type: 'string',
* },
* };
* const {
* values,
* positionals,
* } = Bun.parseArgs({ args, options });
* console.log(values, positionals);
* // Prints: { foo: true, bar: 'b' } []
* ```
* @param config Used to provide arguments for parsing and to configure the parser.
* @return The parsed command line arguments
*/
const parseArgs: typeof import("util").parseArgs;
interface GlobScanOptions {
/**
* The root directory to start matching from. Defaults to `process.cwd()`

Binary file not shown.

View File

@@ -592,10 +592,7 @@ declare module "bun:ffi" {
* bun uses [tinycc](https://github.com/TinyCC/tinycc), so a big thanks
* goes to Fabrice Bellard and TinyCC maintainers for making this possible.
*/
function dlopen<Fns extends Record<string, FFIFunction>>(
name: string | import("bun").BunFile | URL,
symbols: Fns,
): Library<Fns>;
function dlopen<Fns extends Record<string, FFIFunction>>(name: string, symbols: Fns): Library<Fns>;
/**
* Turn a native library's function pointer into a JavaScript function

View File

@@ -1068,6 +1068,23 @@ declare global {
*/
canParse(url: string, base?: string): boolean;
}
var URL: typeof globalThis extends {
onerror: any;
URL: infer T;
}
? T
: typeof URL;
interface URLSearchParams {
new (init?: string | string[][] | Record<string, string> | URLSearchParams | undefined): URLSearchParams;
toString(): string;
}
var URLSearchParams: typeof globalThis extends {
onerror: any;
URLSearchParams: infer T;
}
? T
: typeof URLSearchParams;
interface EventListener {
(evt: Event): void;

View File

@@ -14,7 +14,7 @@
],
"homepage": "https://bun.sh",
"dependencies": {
"@types/node": "~20.12.8",
"@types/node": "~20.11.3",
"@types/ws": "~8.5.10"
},
"devDependencies": {
@@ -34,4 +34,4 @@
"bun.js",
"types"
]
}
}

View File

@@ -24,7 +24,7 @@
* | `null` | `NULL` |
*/
declare module "bun:sqlite" {
export class Database implements Disposable {
export class Database {
/**
* Open or create a SQLite3 database
*
@@ -257,20 +257,7 @@ declare module "bun:sqlite" {
*
* Internally, this calls `sqlite3_close_v2`.
*/
close(
/**
* If `true`, then the database will throw an error if it is in use
* @default false
*
* When true, this calls `sqlite3_close` instead of `sqlite3_close_v2`.
*
* Learn more about this in the [sqlite3 documentation](https://www.sqlite.org/c3ref/close.html).
*
* Bun will automatically call close by default when the database instance is garbage collected.
* In The future, Bun may default `throwOnError` to be true but for backwards compatibility, it is false by default.
*/
throwOnError?: boolean,
): void;
close(): void;
/**
* The filename passed when `new Database()` was called
@@ -317,8 +304,6 @@ declare module "bun:sqlite" {
*/
static setCustomSQLite(path: string): boolean;
[Symbol.dispose](): void;
/**
* Creates a function that always runs inside a transaction. When the
* function is invoked, it will begin a new transaction. When the function
@@ -442,17 +427,6 @@ declare module "bun:sqlite" {
* ```
*/
static deserialize(serialized: NodeJS.TypedArray | ArrayBufferLike, isReadOnly?: boolean): Database;
/**
* See `sqlite3_file_control` for more information.
* @link https://www.sqlite.org/c3ref/file_control.html
*/
fileControl(op: number, arg?: ArrayBufferView | number): number;
/**
* See `sqlite3_file_control` for more information.
* @link https://www.sqlite.org/c3ref/file_control.html
*/
fileControl(zDbName: string, op: number, arg?: ArrayBufferView | number): number;
}
/**
@@ -481,7 +455,7 @@ declare module "bun:sqlite" {
* // => undefined
* ```
*/
export class Statement<ReturnType = unknown, ParamsType extends SQLQueryBindings[] = any[]> implements Disposable {
export class Statement<ReturnType = unknown, ParamsType extends SQLQueryBindings[] = any[]> {
/**
* Creates a new prepared statement from native code.
*
@@ -659,11 +633,6 @@ declare module "bun:sqlite" {
*/
finalize(): void;
/**
* Calls {@link finalize} if it wasn't already called.
*/
[Symbol.dispose](): void;
/**
* Return the expanded SQL string for the prepared statement.
*
@@ -797,187 +766,6 @@ declare module "bun:sqlite" {
* @constant 0x04
*/
SQLITE_PREPARE_NO_VTAB: number;
/**
* @constant 1
*/
SQLITE_FCNTL_LOCKSTATE: number;
/**
* @constant 2
*/
SQLITE_FCNTL_GET_LOCKPROXYFILE: number;
/**
* @constant 3
*/
SQLITE_FCNTL_SET_LOCKPROXYFILE: number;
/**
* @constant 4
*/
SQLITE_FCNTL_LAST_ERRNO: number;
/**
* @constant 5
*/
SQLITE_FCNTL_SIZE_HINT: number;
/**
* @constant 6
*/
SQLITE_FCNTL_CHUNK_SIZE: number;
/**
* @constant 7
*/
SQLITE_FCNTL_FILE_POINTER: number;
/**
* @constant 8
*/
SQLITE_FCNTL_SYNC_OMITTED: number;
/**
* @constant 9
*/
SQLITE_FCNTL_WIN32_AV_RETRY: number;
/**
* @constant 10
*
* Control whether or not the WAL is persisted
* Some versions of macOS configure WAL to be persistent by default.
*
* You can change this with code like the below:
* ```ts
* import { Database } from "bun:sqlite";
*
* const db = Database.open("mydb.sqlite");
* db.fileControl(constants.SQLITE_FCNTL_PERSIST_WAL, 0);
* // enable WAL
* db.exec("PRAGMA journal_mode = WAL");
* // .. do some work
* db.close();
* ```
*
*/
SQLITE_FCNTL_PERSIST_WAL: number;
/**
* @constant 11
*/
SQLITE_FCNTL_OVERWRITE: number;
/**
* @constant 12
*/
SQLITE_FCNTL_VFSNAME: number;
/**
* @constant 13
*/
SQLITE_FCNTL_POWERSAFE_OVERWRITE: number;
/**
* @constant 14
*/
SQLITE_FCNTL_PRAGMA: number;
/**
* @constant 15
*/
SQLITE_FCNTL_BUSYHANDLER: number;
/**
* @constant 16
*/
SQLITE_FCNTL_TEMPFILENAME: number;
/**
* @constant 18
*/
SQLITE_FCNTL_MMAP_SIZE: number;
/**
* @constant 19
*/
SQLITE_FCNTL_TRACE: number;
/**
* @constant 20
*/
SQLITE_FCNTL_HAS_MOVED: number;
/**
* @constant 21
*/
SQLITE_FCNTL_SYNC: number;
/**
* @constant 22
*/
SQLITE_FCNTL_COMMIT_PHASETWO: number;
/**
* @constant 23
*/
SQLITE_FCNTL_WIN32_SET_HANDLE: number;
/**
* @constant 24
*/
SQLITE_FCNTL_WAL_BLOCK: number;
/**
* @constant 25
*/
SQLITE_FCNTL_ZIPVFS: number;
/**
* @constant 26
*/
SQLITE_FCNTL_RBU: number;
/**
* @constant 27
*/
SQLITE_FCNTL_VFS_POINTER: number;
/**
* @constant 28
*/
SQLITE_FCNTL_JOURNAL_POINTER: number;
/**
* @constant 29
*/
SQLITE_FCNTL_WIN32_GET_HANDLE: number;
/**
* @constant 30
*/
SQLITE_FCNTL_PDB: number;
/**
* @constant 31
*/
SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: number;
/**
* @constant 32
*/
SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: number;
/**
* @constant 33
*/
SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: number;
/**
* @constant 34
*/
SQLITE_FCNTL_LOCK_TIMEOUT: number;
/**
* @constant 35
*/
SQLITE_FCNTL_DATA_VERSION: number;
/**
* @constant 36
*/
SQLITE_FCNTL_SIZE_LIMIT: number;
/**
* @constant 37
*/
SQLITE_FCNTL_CKPT_DONE: number;
/**
* @constant 38
*/
SQLITE_FCNTL_RESERVE_BYTES: number;
/**
* @constant 39
*/
SQLITE_FCNTL_CKPT_START: number;
/**
* @constant 40
*/
SQLITE_FCNTL_EXTERNAL_READER: number;
/**
* @constant 41
*/
SQLITE_FCNTL_CKSM_FILE: number;
/**
* @constant 42
*/
SQLITE_FCNTL_RESET_CACHE: number;
};
/**

View File

@@ -26,6 +26,7 @@
#include <stdlib.h>
#ifndef _WIN32
//#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -37,185 +38,107 @@
#include <errno.h>
#endif
#if defined(__APPLE__) && defined(__aarch64__)
#define HAS_MSGX
/* Internal structure of packet buffer */
struct us_internal_udp_packet_buffer {
#if defined(_WIN32) || defined(__APPLE__)
char *buf[LIBUS_UDP_MAX_NUM];
size_t len[LIBUS_UDP_MAX_NUM];
struct sockaddr_storage addr[LIBUS_UDP_MAX_NUM];
#else
struct mmsghdr msgvec[LIBUS_UDP_MAX_NUM];
struct iovec iov[LIBUS_UDP_MAX_NUM];
struct sockaddr_storage addr[LIBUS_UDP_MAX_NUM];
char control[LIBUS_UDP_MAX_NUM][256];
#endif
};
/* We need to emulate sendmmsg, recvmmsg on platform who don't have it */
int bsd_sendmmsg(LIBUS_SOCKET_DESCRIPTOR fd, struct udp_sendbuf* sendbuf, int flags) {
#if defined(_WIN32)// || defined(__APPLE__)
for (int i = 0; i < sendbuf->num; i++) {
while (1) {
int ret = 0;
struct sockaddr *addr = (struct sockaddr *)sendbuf->addresses[i];
if (!addr || addr->sa_family == AF_UNSPEC) {
ret = send(fd, sendbuf->payloads[i], sendbuf->lengths[i], flags);
} else if (addr->sa_family == AF_INET) {
socklen_t len = sizeof(struct sockaddr_in);
ret = sendto(fd, sendbuf->payloads[i], sendbuf->lengths[i], flags, addr, len);
} else if (addr->sa_family == AF_INET6) {
socklen_t len = sizeof(struct sockaddr_in6);
ret = sendto(fd, sendbuf->payloads[i], sendbuf->lengths[i], flags, addr, len);
int bsd_sendmmsg(LIBUS_SOCKET_DESCRIPTOR fd, void *msgvec, unsigned int vlen, int flags) {
#if defined(__APPLE__)
struct mmsghdr {
struct msghdr msg_hdr; /* Message header */
unsigned int msg_len; /* Number of bytes transmitted */
};
struct mmsghdr *hdrs = (struct mmsghdr *) msgvec;
for (int i = 0; i < vlen; i++) {
int ret = sendmsg(fd, &hdrs[i].msg_hdr, flags);
if (ret == -1) {
if (i) {
return i;
} else {
errno = EAFNOSUPPORT;
return -1;
}
if (ret < 0) {
if (errno == EINTR) continue;
if (errno == EAGAIN || errno == EWOULDBLOCK) return i;
return ret;
}
break;
} else {
hdrs[i].msg_len = ret;
}
}
return sendbuf->num;
#elif defined(__APPLE__)
// TODO figure out why sendmsg_x fails when one of the messages is empty
// so that we can get rid of this code.
// One of the weird things is that once a non-empty message has been sent on the socket,
// empty messages start working as well. Bizzare.
#ifdef HAS_MSGX
if (sendbuf->has_empty) {
#endif
for (int i = 0; i < sendbuf->num; i++) {
while (1) {
ssize_t ret = sendmsg(fd, &sendbuf->msgvec[i].msg_hdr, flags);
if (ret < 0) {
if (errno == EINTR) continue;
if (errno == EAGAIN || errno == EWOULDBLOCK) return i;
return ret;
}
break;
}
return vlen;
#elif defined(_WIN32)
struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
/* Let's just use sendto here */
/* Winsock does not have sendmsg, while macOS has, however, we simply use sendto since both macOS and Winsock has it.
* Besides, you should use Linux either way to get best performance with the sendmmsg */
// while we do not get error, send next
for (int i = 0; i < LIBUS_UDP_MAX_NUM; i++) {
// need to support ipv6 addresses also!
int ret = sendto(fd, packet_buffer->buf[i], packet_buffer->len[i], flags, (struct sockaddr *)&packet_buffer->addr[i], sizeof(struct sockaddr_in));
if (ret == -1) {
// if we fail then we need to buffer up, no that's not our problem
// we do need to register poll out though and have a callback for it
return i;
}
return sendbuf->num;
#ifdef HAS_MSGX
//printf("sendto: %d\n", ret);
}
while (1) {
int ret = sendmsg_x(fd, sendbuf->msgvec, sendbuf->num, flags);
if (ret >= 0 || errno != EINTR) return ret;
}
#endif
return LIBUS_UDP_MAX_NUM; // one message
#else
while (1) {
int ret = sendmmsg(fd, sendbuf->msgvec, sendbuf->num, flags | MSG_NOSIGNAL);
if (ret >= 0 || errno != EINTR) return ret;
}
return sendmmsg(fd, (struct mmsghdr *)msgvec, vlen, flags | MSG_NOSIGNAL);
#endif
}
int bsd_recvmmsg(LIBUS_SOCKET_DESCRIPTOR fd, struct udp_recvbuf *recvbuf, int flags) {
#if defined(_WIN32)
socklen_t addr_len = sizeof(struct sockaddr_storage);
while (1) {
ssize_t ret = recvfrom(fd, recvbuf->buf, LIBUS_RECV_BUFFER_LENGTH, flags, (struct sockaddr *)&recvbuf->addr, &addr_len);
if (ret < 0) {
if (errno == EINTR) continue;
return ret;
int bsd_recvmmsg(LIBUS_SOCKET_DESCRIPTOR fd, void *msgvec, unsigned int vlen, int flags, void *timeout) {
#if defined(_WIN32) || defined(__APPLE__)
struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
for (int i = 0; i < LIBUS_UDP_MAX_NUM; i++) {
socklen_t addr_len = sizeof(struct sockaddr_storage);
int ret = recvfrom(fd, packet_buffer->buf[i], LIBUS_UDP_MAX_SIZE, flags, (struct sockaddr *)&packet_buffer->addr[i], &addr_len);
if (ret == -1) {
return i;
}
recvbuf->recvlen = ret;
return 1;
}
#elif defined(__APPLE__)
#ifdef HAS_MSGX
while (1) {
int ret = recvmsg_x(fd, recvbuf->msgvec, LIBUS_UDP_RECV_COUNT, flags);
if (ret >= 0 || errno != EINTR) return ret;
packet_buffer->len[i] = ret;
}
return LIBUS_UDP_MAX_NUM;
#else
for (int i = 0; i < LIBUS_UDP_RECV_COUNT; ++i) {
while (1) {
ssize_t ret = recvmsg(fd, &recvbuf->msgvec[i].msg_hdr, flags);
if (ret < 0) {
if (errno == EINTR) continue;
if (errno == EAGAIN || errno == EWOULDBLOCK) return i;
return ret;
}
recvbuf->msgvec[i].msg_len = ret;
break;
}
// we need to set controllen for ip packet
for (int i = 0; i < vlen; i++) {
((struct mmsghdr *)msgvec)[i].msg_hdr.msg_controllen = 256;
}
return LIBUS_UDP_RECV_COUNT;
#endif
#else
while (1) {
int ret = recvmmsg(fd, (struct mmsghdr *)&recvbuf->msgvec, LIBUS_UDP_RECV_COUNT, flags, 0);
if (ret >= 0 || errno != EINTR) return ret;
}
#endif
}
void bsd_udp_setup_recvbuf(struct udp_recvbuf *recvbuf, void *databuf, size_t databuflen) {
#if defined(_WIN32)
recvbuf->buf = databuf;
recvbuf->buflen = databuflen;
#else
// assert(databuflen > LIBUS_UDP_MAX_SIZE * LIBUS_UDP_RECV_COUNT);
for (int i = 0; i < LIBUS_UDP_RECV_COUNT; i++) {
recvbuf->iov[i].iov_base = (char*)databuf + i * LIBUS_UDP_MAX_SIZE;
recvbuf->iov[i].iov_len = LIBUS_UDP_MAX_SIZE;
recvbuf->msgvec[i].msg_hdr.msg_name = &recvbuf->addr[i];
recvbuf->msgvec[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
recvbuf->msgvec[i].msg_hdr.msg_iov = &recvbuf->iov[i];
recvbuf->msgvec[i].msg_hdr.msg_iovlen = 1;
recvbuf->msgvec[i].msg_hdr.msg_control = recvbuf->control[i];
recvbuf->msgvec[i].msg_hdr.msg_controllen = 256;
}
#endif
}
int bsd_udp_setup_sendbuf(struct udp_sendbuf *buf, size_t bufsize, void** payloads, size_t* lengths, void** addresses, int num) {
#if defined(_WIN32)
buf->payloads = payloads;
buf->lengths = lengths;
buf->addresses = addresses;
buf->num = num;
return num;
#else
buf->has_empty = 0;
struct mmsghdr *msgvec = buf->msgvec;
// todo check this math
size_t count = (bufsize - sizeof(struct udp_sendbuf)) / (sizeof(struct mmsghdr) + sizeof(struct iovec));
if (count > num) {
count = num;
}
struct iovec *iov = (struct iovec *) (msgvec + count);
for (int i = 0; i < count; i++) {
struct sockaddr *addr = (struct sockaddr *)addresses[i];
socklen_t addr_len = 0;
if (addr) {
addr_len = addr->sa_family == AF_INET ? sizeof(struct sockaddr_in)
: addr->sa_family == AF_INET6 ? sizeof(struct sockaddr_in6)
: 0;
}
iov[i].iov_base = payloads[i];
iov[i].iov_len = lengths[i];
msgvec[i].msg_hdr.msg_name = addresses[i];
msgvec[i].msg_hdr.msg_namelen = addr_len;
msgvec[i].msg_hdr.msg_control = NULL;
msgvec[i].msg_hdr.msg_controllen = 0;
msgvec[i].msg_hdr.msg_iov = iov + i;
msgvec[i].msg_hdr.msg_iovlen = 1;
msgvec[i].msg_hdr.msg_flags = 0;
msgvec[i].msg_len = 0;
if (lengths[i] == 0) {
buf->has_empty = 1;
}
}
buf->num = count;
return count;
return recvmmsg(fd, (struct mmsghdr *)msgvec, vlen, flags, 0);
#endif
}
// this one is needed for knowing the destination addr of udp packet
// an udp socket can only bind to one port, and that port never changes
// this function returns ONLY the IP address, not any port
int bsd_udp_packet_buffer_local_ip(struct udp_recvbuf *msgvec, int index, char *ip) {
int bsd_udp_packet_buffer_local_ip(void *msgvec, int index, char *ip) {
#if defined(_WIN32) || defined(__APPLE__)
return 0; // not supported
#else
@@ -240,30 +163,99 @@ int bsd_udp_packet_buffer_local_ip(struct udp_recvbuf *msgvec, int index, char *
#endif
}
char *bsd_udp_packet_buffer_peer(struct udp_recvbuf *msgvec, int index) {
#if defined(_WIN32)
return (char *)&msgvec->addr;
char *bsd_udp_packet_buffer_peer(void *msgvec, int index) {
#if defined(_WIN32) || defined(__APPLE__)
struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
return (char *)&packet_buffer->addr[index];
#else
return ((struct mmsghdr *) msgvec)[index].msg_hdr.msg_name;
#endif
}
char *bsd_udp_packet_buffer_payload(struct udp_recvbuf *msgvec, int index) {
#if defined(_WIN32)
return msgvec->buf;
char *bsd_udp_packet_buffer_payload(void *msgvec, int index) {
#if defined(_WIN32) || defined(__APPLE__)
struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
return packet_buffer->buf[index];
#else
return ((struct mmsghdr *) msgvec)[index].msg_hdr.msg_iov[0].iov_base;
#endif
}
int bsd_udp_packet_buffer_payload_length(struct udp_recvbuf *msgvec, int index) {
#if defined(_WIN32)
return msgvec->recvlen;
int bsd_udp_packet_buffer_payload_length(void *msgvec, int index) {
#if defined(_WIN32) || defined(__APPLE__)
struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
return packet_buffer->len[index];
#else
return ((struct mmsghdr *) msgvec)[index].msg_len;
#endif
}
void bsd_udp_buffer_set_packet_payload(struct us_udp_packet_buffer_t *send_buf, int index, int offset, void *payload, int length, void *peer_addr) {
#if defined(_WIN32) || defined(__APPLE__)
struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) send_buf;
memcpy(packet_buffer->buf[index], payload, length);
memcpy(&packet_buffer->addr[index], peer_addr, sizeof(struct sockaddr_storage));
packet_buffer->len[index] = length;
#else
//printf("length: %d, offset: %d\n", length, offset);
struct mmsghdr *ss = (struct mmsghdr *) send_buf;
// copy the peer address
memcpy(ss[index].msg_hdr.msg_name, peer_addr, /*ss[index].msg_hdr.msg_namelen*/ sizeof(struct sockaddr_in));
// set control length to 0
ss[index].msg_hdr.msg_controllen = 0;
// copy the payload
ss[index].msg_hdr.msg_iov->iov_len = length + offset;
memcpy(((char *) ss[index].msg_hdr.msg_iov->iov_base) + offset, payload, length);
#endif
}
/* The maximum UDP payload size is 64kb, but in IPV6 you can have jumbopackets larger than so.
* We do not support those jumbo packets currently, but will safely ignore them.
* Any sane sender would assume we don't support them if we consistently drop them.
* Therefore a udp_packet_buffer_t will be 64 MB in size (64kb * 1024). */
void *bsd_create_udp_packet_buffer() {
#if defined(_WIN32) || defined(__APPLE__)
struct us_internal_udp_packet_buffer *b = malloc(sizeof(struct us_internal_udp_packet_buffer) + LIBUS_UDP_MAX_SIZE * LIBUS_UDP_MAX_NUM);
for (int i = 0; i < LIBUS_UDP_MAX_NUM; i++) {
b->buf[i] = ((char *) b) + sizeof(struct us_internal_udp_packet_buffer) + LIBUS_UDP_MAX_SIZE * i;
}
return (struct us_udp_packet_buffer_t *) b;
#else
/* Allocate 64kb times 1024 */
struct us_internal_udp_packet_buffer *b = malloc(sizeof(struct us_internal_udp_packet_buffer) + LIBUS_UDP_MAX_SIZE * LIBUS_UDP_MAX_NUM);
for (int n = 0; n < LIBUS_UDP_MAX_NUM; ++n) {
b->iov[n].iov_base = &((char *) (b + 1))[n * LIBUS_UDP_MAX_SIZE];
b->iov[n].iov_len = LIBUS_UDP_MAX_SIZE;
b->msgvec[n].msg_hdr = (struct msghdr) {
.msg_name = &b->addr,
.msg_namelen = sizeof (struct sockaddr_storage),
.msg_iov = &b->iov[n],
.msg_iovlen = 1,
.msg_control = b->control[n],
.msg_controllen = 256,
};
}
return (struct us_udp_packet_buffer_t *) b;
#endif
}
LIBUS_SOCKET_DESCRIPTOR apple_no_sigpipe(LIBUS_SOCKET_DESCRIPTOR fd) {
#ifdef __APPLE__
if (fd != LIBUS_SOCKET_ERROR) {
@@ -774,10 +766,10 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_udp_socket(const char *host, int port) {
if (setsockopt(listenFd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *) &enabled, sizeof(enabled)) == -1) {
if (errno == 92) {
if (setsockopt(listenFd, IPPROTO_IP, IP_PKTINFO, (void *) &enabled, sizeof(enabled)) != 0) {
//printf("Error setting IPv4 pktinfo!\n");
printf("Error setting IPv4 pktinfo!\n");
}
} else {
//printf("Error setting IPv6 pktinfo!\n");
printf("Error setting IPv6 pktinfo!\n");
}
}
@@ -785,10 +777,10 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_udp_socket(const char *host, int port) {
if (setsockopt(listenFd, IPPROTO_IPV6, IPV6_RECVTCLASS, (void *) &enabled, sizeof(enabled)) == -1) {
if (errno == 92) {
if (setsockopt(listenFd, IPPROTO_IP, IP_RECVTOS, (void *) &enabled, sizeof(enabled)) != 0) {
//printf("Error setting IPv4 ECN!\n");
printf("Error setting IPv4 ECN!\n");
}
} else {
//printf("Error setting IPv6 ECN!\n");
printf("Error setting IPv6 ECN!\n");
}
}
@@ -803,83 +795,37 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_udp_socket(const char *host, int port) {
return listenFd;
}
int bsd_connect_udp_socket(LIBUS_SOCKET_DESCRIPTOR fd, const char *host, int port) {
struct addrinfo hints, *result;
memset(&hints, 0, sizeof(struct addrinfo));
int bsd_udp_packet_buffer_ecn(void *msgvec, int index) {
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
#if defined(_WIN32) || defined(__APPLE__)
printf("ECN not supported!\n");
#else
// we should iterate all control messages once, after recvmmsg and then only fetch them with these functions
struct msghdr *mh = &((struct mmsghdr *) msgvec)[index].msg_hdr;
for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL; cmsg = CMSG_NXTHDR(mh, cmsg)) {
// do we need to get TOS from ipv6 also?
if (cmsg->cmsg_level == IPPROTO_IP) {
if (cmsg->cmsg_type == IP_TOS) {
uint8_t tos = *(uint8_t *)CMSG_DATA(cmsg);
return tos & 3;
}
}
char port_string[16];
snprintf(port_string, 16, "%d", port);
if (getaddrinfo(host, port_string, &hints, &result)) {
return -1;
}
if (result == NULL) {
return -1;
}
for (struct addrinfo *rp = result; rp != NULL; rp = rp->ai_next) {
if (connect(fd, rp->ai_addr, rp->ai_addrlen) == 0) {
freeaddrinfo(result);
return 0;
if (cmsg->cmsg_level == IPPROTO_IPV6) {
if (cmsg->cmsg_type == IPV6_TCLASS) {
// is this correct?
uint8_t tos = *(uint8_t *)CMSG_DATA(cmsg);
return tos & 3;
}
}
}
#endif
freeaddrinfo(result);
return LIBUS_SOCKET_ERROR;
printf("We got no ECN!\n");
return 0; // no ecn defaults to 0
}
int bsd_disconnect_udp_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
struct sockaddr addr;
memset(&addr, 0, sizeof(addr));
addr.sa_family = AF_UNSPEC;
#ifdef __APPLE__
addr.sa_len = sizeof(addr);
#endif
int res = connect(fd, &addr, sizeof(addr));
// EAFNOSUPPORT is harmless in this case - we just want to disconnect
if (res == 0 || errno == EAFNOSUPPORT) {
return 0;
} else {
return -1;
}
}
// int bsd_udp_packet_buffer_ecn(void *msgvec, int index) {
// #if defined(_WIN32) || defined(__APPLE__)
// errno = ENOSYS;
// return -1;
// #else
// // we should iterate all control messages once, after recvmmsg and then only fetch them with these functions
// struct msghdr *mh = &((struct mmsghdr *) msgvec)[index].msg_hdr;
// for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL; cmsg = CMSG_NXTHDR(mh, cmsg)) {
// // do we need to get TOS from ipv6 also?
// if (cmsg->cmsg_level == IPPROTO_IP) {
// if (cmsg->cmsg_type == IP_TOS) {
// uint8_t tos = *(uint8_t *)CMSG_DATA(cmsg);
// return tos & 3;
// }
// }
// if (cmsg->cmsg_level == IPPROTO_IPV6) {
// if (cmsg->cmsg_type == IPV6_TCLASS) {
// // is this correct?
// uint8_t tos = *(uint8_t *)CMSG_DATA(cmsg);
// return tos & 3;
// }
// }
// }
// #endif
// //printf("We got no ECN!\n");
// return 0; // no ecn defaults to 0
// }
static int bsd_do_connect_raw(struct addrinfo *rp, int fd)
{
do {

View File

@@ -16,6 +16,7 @@
*/
#if (defined(LIBUS_USE_OPENSSL) || defined(LIBUS_USE_WOLFSSL))
/* These are in sni_tree.cpp */
void *sni_new();
void sni_free(void *sni, void (*cb)(void *));
@@ -71,10 +72,7 @@ struct us_internal_ssl_socket_context_t {
// socket context
SSL_CTX *ssl_context;
int is_parent;
#if ALLOW_SERVER_RENEGOTIATION
unsigned int client_renegotiation_limit;
unsigned int client_renegotiation_window;
#endif
/* These decorate the base implementation */
struct us_internal_ssl_socket_t *(*on_open)(struct us_internal_ssl_socket_t *,
int is_client, char *ip,
@@ -98,24 +96,13 @@ struct us_internal_ssl_socket_context_t {
void *handshake_data;
};
// same here, should or shouldn't it
enum {
HANDSHAKE_PENDING = 0,
HANDSHAKE_COMPLETED = 1,
HANDSHAKE_RENEGOTIATION_PENDING = 2,
};
// same here, should or shouldn't it contain s?
struct us_internal_ssl_socket_t {
struct us_socket_t s;
SSL *ssl;
#if ALLOW_SERVER_RENEGOTIATION
unsigned int client_pending_renegotiations;
uint64_t last_ssl_renegotiation;
unsigned int is_client : 1;
#endif
unsigned int ssl_write_wants_read : 1; // we use this for now
unsigned int ssl_read_wants_write : 1;
unsigned int handshake_state : 2;
unsigned int pending_handshake : 1;
unsigned int received_ssl_shutdown : 1;
};
@@ -155,6 +142,8 @@ int BIO_s_custom_write(BIO *bio, const char *data, int length) {
return -1;
}
// printf("BIO_s_custom_write returns: %d\n", written);
return written;
}
@@ -162,6 +151,8 @@ int BIO_s_custom_read(BIO *bio, char *dst, int length) {
struct loop_ssl_data *loop_ssl_data =
(struct loop_ssl_data *)BIO_get_data(bio);
// printf("BIO_s_custom_read\n");
if (!loop_ssl_data->ssl_read_input_length) {
BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ);
return -1;
@@ -192,40 +183,17 @@ struct us_internal_ssl_socket_t *ssl_on_open(struct us_internal_ssl_socket_t *s,
(struct loop_ssl_data *)loop->data.ssl_data;
s->ssl = SSL_new(context->ssl_context);
#if ALLOW_SERVER_RENEGOTIATION
s->client_pending_renegotiations = context->client_renegotiation_limit;
s->last_ssl_renegotiation = 0;
s->is_client = is_client ? 1 : 0;
#endif
s->ssl_write_wants_read = 0;
s->ssl_read_wants_write = 0;
s->handshake_state = HANDSHAKE_PENDING;
s->pending_handshake = 1;
s->received_ssl_shutdown = 0;
SSL_set_bio(s->ssl, loop_ssl_data->shared_rbio, loop_ssl_data->shared_wbio);
// if we allow renegotiation, we need to set the mode here
// https://github.com/oven-sh/bun/issues/6197
// https://github.com/oven-sh/bun/issues/5363
// renegotiation is only valid for <= TLS1_2_VERSION
// this can be a DoS vector for servers, so we enable it using a limit
// we do not use ssl_renegotiate_freely, since ssl_renegotiate_explicit is
// more performant when using BoringSSL
#if ALLOW_SERVER_RENEGOTIATION
if (context->client_renegotiation_limit) {
SSL_set_renegotiate_mode(s->ssl, ssl_renegotiate_explicit);
} else {
SSL_set_renegotiate_mode(s->ssl, ssl_renegotiate_never);
}
#endif
BIO_up_ref(loop_ssl_data->shared_rbio);
BIO_up_ref(loop_ssl_data->shared_wbio);
if (is_client) {
#if ALLOW_SERVER_RENEGOTIATION == 0
SSL_set_renegotiate_mode(s->ssl, ssl_renegotiate_explicit);
#endif
SSL_set_connect_state(s->ssl);
} else {
SSL_set_accept_state(s->ssl);
@@ -237,9 +205,7 @@ struct us_internal_ssl_socket_t *ssl_on_open(struct us_internal_ssl_socket_t *s,
// Hello Message!
// always handshake after open
// this is important because some servers/clients can get stuck waiting for
// this
us_internal_update_handshake(s);
us_internal_ssl_handshake(s);
return result;
}
@@ -257,74 +223,39 @@ void us_internal_on_ssl_handshake(
struct us_internal_ssl_socket_t *
us_internal_ssl_socket_close(struct us_internal_ssl_socket_t *s, int code,
void *reason) {
if (s->handshake_state != HANDSHAKE_COMPLETED) {
struct us_internal_ssl_socket_context_t *context =
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
if (s->pending_handshake) {
s->pending_handshake = 0;
// if we have some pending handshake we cancel it and try to check the
// latest handshake error this way we will always call on_handshake with the
// latest error before closing this should always call
// secureConnection/secure before close if we remove this here, we will need
// to do this check on every on_close event on sockets, fetch etc and will
// increase complexity on a lot of places
us_internal_trigger_handshake_callback(s, 0);
if (context->on_handshake != NULL) {
struct us_bun_verify_error_t verify_error = us_internal_verify_error(s);
context->on_handshake(s, 0, verify_error, context->handshake_data);
}
}
return (struct us_internal_ssl_socket_t *)us_socket_close(
0, (struct us_socket_t *)s, code, reason);
}
void us_internal_trigger_handshake_callback(struct us_internal_ssl_socket_t *s,
int success) {
void us_internal_ssl_handshake(struct us_internal_ssl_socket_t *s) {
struct us_internal_ssl_socket_context_t *context =
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
void (*on_handshake)(struct us_internal_ssl_socket_t *, int,
struct us_bun_verify_error_t, void *) =
context->on_handshake;
void *custom_data = context->handshake_data;
// always set the handshake state to completed
s->handshake_state = HANDSHAKE_COMPLETED;
if (context->on_handshake != NULL) {
struct us_bun_verify_error_t verify_error = us_internal_verify_error(s);
context->on_handshake(s, success, verify_error, context->handshake_data);
}
}
int us_internal_ssl_renegotiate(struct us_internal_ssl_socket_t *s) {
// handle renegotation here since we are using ssl_renegotiate_explicit
// if is a server and we have no pending renegotiation we can check
// the limits
s->handshake_state = HANDSHAKE_RENEGOTIATION_PENDING;
#if ALLOW_SERVER_RENEGOTIATION
if (!s->is_client && !SSL_renegotiate_pending(s->ssl)) {
uint64_t now = time(NULL);
struct us_internal_ssl_socket_context_t *context =
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
// if is not the first time we negotiate and we are outside the time
// window, reset the limits
if (s->last_ssl_renegotiation && (now - s->last_ssl_renegotiation) >=
context->client_renegotiation_window) {
// reset the limits
s->client_pending_renegotiations = context->client_renegotiation_limit;
}
// if we have no more renegotiations, we should close the connection
if (s->client_pending_renegotiations == 0) {
return 0;
}
s->last_ssl_renegotiation = now;
s->client_pending_renegotiations--;
}
#endif
if (!SSL_renegotiate(s->ssl)) {
// we failed to renegotiate
us_internal_trigger_handshake_callback(s, 0);
return 0;
}
return 1;
}
void us_internal_update_handshake(struct us_internal_ssl_socket_t *s) {
struct us_internal_ssl_socket_context_t *context =
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
// nothing todo here, renegotiation must be handled in SSL_read
if (s->handshake_state != HANDSHAKE_PENDING)
// will start on_open, on_writable or on_data
if (!s->ssl) {
return;
}
struct us_loop_t *loop = us_socket_context_loop(0, &context->sc);
struct loop_ssl_data *loop_ssl_data =
@@ -337,8 +268,13 @@ void us_internal_update_handshake(struct us_internal_ssl_socket_t *s) {
if (us_socket_is_closed(0, &s->s) || us_internal_ssl_socket_is_shut_down(s) ||
SSL_get_shutdown(s->ssl) & SSL_RECEIVED_SHUTDOWN) {
s->pending_handshake = 0;
us_internal_trigger_handshake_callback(s, 0);
struct us_bun_verify_error_t verify_error = (struct us_bun_verify_error_t){
.error = 0, .code = NULL, .reason = NULL};
if (on_handshake != NULL) {
on_handshake(s, 0, verify_error, custom_data);
}
return;
}
@@ -349,34 +285,45 @@ void us_internal_update_handshake(struct us_internal_ssl_socket_t *s) {
us_internal_ssl_socket_close(s, 0, NULL);
return;
}
if (result <= 0) {
int err = SSL_get_error(s->ssl, result);
// as far as I know these are the only errors we want to handle
if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
us_internal_trigger_handshake_callback(s, 1);
s->pending_handshake = 0;
struct us_bun_verify_error_t verify_error = us_internal_verify_error(s);
// clear per thread error queue if it may contain something
if (err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL) {
ERR_clear_error();
}
// error
if (on_handshake != NULL) {
on_handshake(s, 0, verify_error, custom_data);
}
return;
}
s->handshake_state = HANDSHAKE_PENDING;
s->pending_handshake = 1;
context->on_handshake = on_handshake;
context->handshake_data = custom_data;
// Ensure that we'll cycle through internal openssl's state
if (!us_socket_is_closed(0, &s->s) &&
!us_internal_ssl_socket_is_shut_down(s)) {
us_socket_write(1, loop_ssl_data->ssl_socket, "\0", 0, 0);
}
} else {
s->pending_handshake = 0;
return;
}
// success
us_internal_trigger_handshake_callback(s, 1);
// Ensure that we'll cycle through internal openssl's state
if (!us_socket_is_closed(0, &s->s) &&
!us_internal_ssl_socket_is_shut_down(s)) {
us_socket_write(1, loop_ssl_data->ssl_socket, "\0", 0, 0);
struct us_bun_verify_error_t verify_error = us_internal_verify_error(s);
// success
if (on_handshake != NULL) {
on_handshake(s, 1, verify_error, custom_data);
}
// Ensure that we'll cycle through internal openssl's state
if (!us_socket_is_closed(0, &s->s) &&
!us_internal_ssl_socket_is_shut_down(s)) {
us_socket_write(1, loop_ssl_data->ssl_socket, "\0", 0, 0);
}
}
}
@@ -385,6 +332,7 @@ ssl_on_close(struct us_internal_ssl_socket_t *s, int code, void *reason) {
struct us_internal_ssl_socket_context_t *context =
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
s->pending_handshake = 0;
SSL_free(s->ssl);
return context->on_close(s, code, reason);
@@ -392,6 +340,9 @@ ssl_on_close(struct us_internal_ssl_socket_t *s, int code, void *reason) {
struct us_internal_ssl_socket_t *
ssl_on_end(struct us_internal_ssl_socket_t *s) {
if (s && s->pending_handshake) {
s->pending_handshake = 0;
}
// whatever state we are in, a TCP FIN is always an answered shutdown
/* Todo: this should report CLEANLY SHUTDOWN as reason */
@@ -401,7 +352,6 @@ ssl_on_end(struct us_internal_ssl_socket_t *s) {
// this whole function needs a complete clean-up
struct us_internal_ssl_socket_t *ssl_on_data(struct us_internal_ssl_socket_t *s,
void *data, int length) {
// note: this context can change when we adopt the socket!
struct us_internal_ssl_socket_context_t *context =
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
@@ -410,6 +360,9 @@ struct us_internal_ssl_socket_t *ssl_on_data(struct us_internal_ssl_socket_t *s,
struct loop_ssl_data *loop_ssl_data =
(struct loop_ssl_data *)loop->data.ssl_data;
if (s->pending_handshake) {
us_internal_ssl_handshake(s);
}
// note: if we put data here we should never really clear it (not in write
// either, it still should be available for SSL_write to read from!)
loop_ssl_data->ssl_read_input = data;
@@ -427,6 +380,7 @@ struct us_internal_ssl_socket_t *ssl_on_data(struct us_internal_ssl_socket_t *s,
int ret = 0;
if ((ret = SSL_shutdown(s->ssl)) == 1) {
// two phase shutdown is complete here
// printf("Two step SSL shutdown complete\n");
/* Todo: this should also report some kind of clean shutdown */
return us_internal_ssl_socket_close(s, 0, NULL);
@@ -444,6 +398,7 @@ struct us_internal_ssl_socket_t *ssl_on_data(struct us_internal_ssl_socket_t *s,
// no further processing of data when in shutdown state
return s;
}
// bug checking: this loop needs a lot of attention and clean-ups and
// check-ups
int read = 0;
@@ -456,24 +411,17 @@ restart:
LIBUS_RECV_BUFFER_LENGTH - read);
// we need to check if we received a shutdown here
if (SSL_get_shutdown(s->ssl) & SSL_RECEIVED_SHUTDOWN) {
s->pending_handshake = 0;
s->received_ssl_shutdown = 1;
// we will only close after we handle the data and errors
}
if (just_read <= 0) {
int err = SSL_get_error(s->ssl, just_read);
// as far as I know these are the only errors we want to handle
if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
if (err == SSL_ERROR_WANT_RENEGOTIATE) {
if (us_internal_ssl_renegotiate(s)) {
// ok, we are done here, we need to call SSL_read again
// this dont mean that we are done with the handshake renegotiation
// we need to call SSL_read again
continue;
}
// clean and close renegotiation failed
err = SSL_ERROR_SSL;
} else if (err == SSL_ERROR_ZERO_RETURN) {
if (err == SSL_ERROR_ZERO_RETURN) {
// zero return can be EOF/FIN, if we have data just signal on_data and
// close
if (read) {
@@ -529,9 +477,6 @@ restart:
break;
}
} else if (s->handshake_state == HANDSHAKE_RENEGOTIATION_PENDING) {
// renegotiation ended successfully call on_handshake
us_internal_trigger_handshake_callback(s, 1);
}
read += just_read;
@@ -554,7 +499,6 @@ restart:
goto restart;
}
}
// we received the shutdown after reading so we close
if (s->received_ssl_shutdown) {
us_internal_ssl_socket_close(s, 0, NULL);
@@ -582,11 +526,13 @@ restart:
struct us_internal_ssl_socket_t *
ssl_on_writable(struct us_internal_ssl_socket_t *s) {
us_internal_update_handshake(s);
struct us_internal_ssl_socket_context_t *context =
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
if (s->pending_handshake) {
us_internal_ssl_handshake(s);
}
// todo: cork here so that we efficiently output both from reading and from
// writing?
if (s->ssl_read_wants_write) {
@@ -601,6 +547,7 @@ ssl_on_writable(struct us_internal_ssl_socket_t *s) {
s = (struct us_internal_ssl_socket_t *)context->sc.on_data(&s->s, 0,
0); // cast here!
}
// Do not call on_writable if the socket is closed.
// on close means the socket data is no longer accessible
if (!s || us_socket_is_closed(0, &s->s)) {
@@ -1025,7 +972,8 @@ long us_internal_verify_peer_certificate( // NOLINT(runtime/int)
struct us_bun_verify_error_t
us_internal_verify_error(struct us_internal_ssl_socket_t *s) {
if (us_socket_is_closed(0, &s->s) || us_internal_ssl_socket_is_shut_down(s)) {
if (us_socket_is_closed(0, &s->s) || us_internal_ssl_socket_is_shut_down(s) ||
s->received_ssl_shutdown) {
return (struct us_bun_verify_error_t){
.error = 0, .code = NULL, .reason = NULL};
}
@@ -1300,18 +1248,11 @@ void us_bun_internal_ssl_socket_context_add_server_name(
/* Attach the user data to this context */
if (1 != SSL_CTX_set_ex_data(ssl_context, 0, user)) {
#if BUN_DEBUG
printf("CANNOT SET EX DATA!\n");
abort();
#endif
}
/* We do not want to hold any nullptr's in our SNI tree */
if (ssl_context) {
#if ALLOW_SERVER_RENEGOTIATION
context->client_renegotiation_limit = options.client_renegotiation_limit;
context->client_renegotiation_window = options.client_renegotiation_window;
#endif
if (sni_add(context->sni, hostname_pattern, ssl_context)) {
/* If we already had that name, ignore */
free_ssl_context(ssl_context);
@@ -1369,6 +1310,8 @@ int sni_cb(SSL *ssl, int *al, void *arg) {
SSL_CTX *resolved_ssl_context = resolve_context(
(struct us_internal_ssl_socket_context_t *)arg, hostname);
if (resolved_ssl_context) {
// printf("Did find matching SNI context for hostname: <%s>!\n",
// hostname);
SSL_set_SSL_CTX(ssl, resolved_ssl_context);
} else {
/* Call a blocking callback notifying of missing context */
@@ -1453,6 +1396,7 @@ us_internal_bun_create_ssl_socket_context(
/* I guess this is the only optional callback */
context->on_server_name = NULL;
/* Then we extend its SSL parts */
context->ssl_context =
ssl_context; // create_ssl_context_from_options(options);
@@ -1460,10 +1404,6 @@ us_internal_bun_create_ssl_socket_context(
context->on_handshake = NULL;
context->handshake_data = NULL;
#if ALLOW_SERVER_RENEGOTIATION
context->client_renegotiation_limit = options.client_renegotiation_limit;
context->client_renegotiation_window = options.client_renegotiation_window;
#endif
/* We, as parent context, may ignore data */
context->sc.is_low_prio = (int (*)(struct us_socket_t *))ssl_is_low_prio;
@@ -1660,7 +1600,9 @@ int us_internal_ssl_socket_write(struct us_internal_ssl_socket_t *s,
loop_ssl_data->ssl_socket = &s->s;
loop_ssl_data->msg_more = msg_more;
loop_ssl_data->last_write_was_msg_more = 0;
// printf("Calling SSL_write\n");
int written = SSL_write(s->ssl, data, length);
// printf("Returning from SSL_write\n");
loop_ssl_data->msg_more = 0;
if (loop_ssl_data->last_write_was_msg_more && !msg_more) {
@@ -1669,22 +1611,22 @@ int us_internal_ssl_socket_write(struct us_internal_ssl_socket_t *s,
if (written > 0) {
return written;
} else {
int err = SSL_get_error(s->ssl, written);
if (err == SSL_ERROR_WANT_READ) {
// here we need to trigger writable event next ssl_read!
s->ssl_write_wants_read = 1;
} else if (err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL) {
// these two errors may add to the error queue, which is per thread and
// must be cleared
ERR_clear_error();
// all errors here except for want write are critical and should not
// happen
}
return 0;
}
int err = SSL_get_error(s->ssl, written);
if (err == SSL_ERROR_WANT_READ) {
// here we need to trigger writable event next ssl_read!
s->ssl_write_wants_read = 1;
} else if (err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL) {
// these two errors may add to the error queue, which is per thread and
// must be cleared
ERR_clear_error();
// all errors here except for want write are critical and should not
// happen
}
return 0;
}
void *us_internal_ssl_socket_ext(struct us_internal_ssl_socket_t *s) {
@@ -1996,7 +1938,7 @@ struct us_internal_ssl_socket_t *us_internal_ssl_socket_wrap_with_tls(
socket->ssl = NULL;
socket->ssl_write_wants_read = 0;
socket->ssl_read_wants_write = 0;
socket->handshake_state = HANDSHAKE_PENDING;
socket->pending_handshake = 1;
socket->received_ssl_shutdown = 0;
return socket;
}

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