mirror of
https://github.com/oven-sh/bun
synced 2026-02-16 22:01:47 +00:00
Compare commits
7 Commits
claude/fix
...
claude/fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a4f9ca278 | ||
|
|
bfe40e8760 | ||
|
|
bcaae48a95 | ||
|
|
6b3403a2b4 | ||
|
|
70fe76209b | ||
|
|
ab3df344b8 | ||
|
|
4680e89a91 |
2
.github/workflows/update-cares.yml
vendored
2
.github/workflows/update-cares.yml
vendored
@@ -88,7 +88,7 @@ jobs:
|
||||
commit-message: "deps: update c-ares to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
|
||||
title: "deps: update c-ares to ${{ steps.check-version.outputs.tag }}"
|
||||
delete-branch: true
|
||||
branch: deps/update-cares-${{ github.run_number }}
|
||||
branch: deps/update-cares
|
||||
body: |
|
||||
## What does this PR do?
|
||||
|
||||
|
||||
2
.github/workflows/update-hdrhistogram.yml
vendored
2
.github/workflows/update-hdrhistogram.yml
vendored
@@ -91,7 +91,7 @@ jobs:
|
||||
commit-message: "deps: update hdrhistogram to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
|
||||
title: "deps: update hdrhistogram to ${{ steps.check-version.outputs.tag }}"
|
||||
delete-branch: true
|
||||
branch: deps/update-hdrhistogram-${{ github.run_number }}
|
||||
branch: deps/update-hdrhistogram
|
||||
body: |
|
||||
## What does this PR do?
|
||||
|
||||
|
||||
2
.github/workflows/update-highway.yml
vendored
2
.github/workflows/update-highway.yml
vendored
@@ -107,7 +107,7 @@ jobs:
|
||||
commit-message: "deps: update highway to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
|
||||
title: "deps: update highway to ${{ steps.check-version.outputs.tag }}"
|
||||
delete-branch: true
|
||||
branch: deps/update-highway-${{ github.run_number }}
|
||||
branch: deps/update-highway
|
||||
body: |
|
||||
## What does this PR do?
|
||||
|
||||
|
||||
2
.github/workflows/update-libarchive.yml
vendored
2
.github/workflows/update-libarchive.yml
vendored
@@ -88,7 +88,7 @@ jobs:
|
||||
commit-message: "deps: update libarchive to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
|
||||
title: "deps: update libarchive to ${{ steps.check-version.outputs.tag }}"
|
||||
delete-branch: true
|
||||
branch: deps/update-libarchive-${{ github.run_number }}
|
||||
branch: deps/update-libarchive
|
||||
body: |
|
||||
## What does this PR do?
|
||||
|
||||
|
||||
2
.github/workflows/update-libdeflate.yml
vendored
2
.github/workflows/update-libdeflate.yml
vendored
@@ -88,7 +88,7 @@ jobs:
|
||||
commit-message: "deps: update libdeflate to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
|
||||
title: "deps: update libdeflate to ${{ steps.check-version.outputs.tag }}"
|
||||
delete-branch: true
|
||||
branch: deps/update-libdeflate-${{ github.run_number }}
|
||||
branch: deps/update-libdeflate
|
||||
body: |
|
||||
## What does this PR do?
|
||||
|
||||
|
||||
2
.github/workflows/update-lolhtml.yml
vendored
2
.github/workflows/update-lolhtml.yml
vendored
@@ -100,7 +100,7 @@ jobs:
|
||||
commit-message: "deps: update lolhtml to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
|
||||
title: "deps: update lolhtml to ${{ steps.check-version.outputs.tag }}"
|
||||
delete-branch: true
|
||||
branch: deps/update-lolhtml-${{ github.run_number }}
|
||||
branch: deps/update-lolhtml
|
||||
body: |
|
||||
## What does this PR do?
|
||||
|
||||
|
||||
2
.github/workflows/update-lshpack.yml
vendored
2
.github/workflows/update-lshpack.yml
vendored
@@ -105,7 +105,7 @@ jobs:
|
||||
commit-message: "deps: update lshpack to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
|
||||
title: "deps: update lshpack to ${{ steps.check-version.outputs.tag }}"
|
||||
delete-branch: true
|
||||
branch: deps/update-lshpack-${{ github.run_number }}
|
||||
branch: deps/update-lshpack
|
||||
body: |
|
||||
## What does this PR do?
|
||||
|
||||
|
||||
2
.github/workflows/update-root-certs.yml
vendored
2
.github/workflows/update-root-certs.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
```
|
||||
${{ env.changed_files }}
|
||||
```
|
||||
branch: certs/update-root-certs-${{ github.run_number }}
|
||||
branch: certs/update-root-certs
|
||||
base: main
|
||||
delete-branch: true
|
||||
labels:
|
||||
|
||||
2
.github/workflows/update-sqlite3.yml
vendored
2
.github/workflows/update-sqlite3.yml
vendored
@@ -83,7 +83,7 @@ jobs:
|
||||
commit-message: "deps: update sqlite to ${{ steps.check-version.outputs.latest }}"
|
||||
title: "deps: update sqlite to ${{ steps.check-version.outputs.latest }}"
|
||||
delete-branch: true
|
||||
branch: deps/update-sqlite-${{ steps.check-version.outputs.latest }}
|
||||
branch: deps/update-sqlite
|
||||
body: |
|
||||
## What does this PR do?
|
||||
|
||||
|
||||
2
.github/workflows/update-vendor.yml
vendored
2
.github/workflows/update-vendor.yml
vendored
@@ -68,7 +68,7 @@ jobs:
|
||||
commit-message: "deps: update ${{ matrix.package }} to ${{ steps.check-version.outputs.latest }} (${{ steps.check-version.outputs.latest }})"
|
||||
title: "deps: update ${{ matrix.package }} to ${{ steps.check-version.outputs.latest }}"
|
||||
delete-branch: true
|
||||
branch: deps/update-${{ matrix.package }}-${{ github.run_number }}
|
||||
branch: deps/update-${{ matrix.package }}
|
||||
body: |
|
||||
## What does this PR do?
|
||||
|
||||
|
||||
2
.github/workflows/update-zstd.yml
vendored
2
.github/workflows/update-zstd.yml
vendored
@@ -88,7 +88,7 @@ jobs:
|
||||
commit-message: "deps: update zstd to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
|
||||
title: "deps: update zstd to ${{ steps.check-version.outputs.tag }}"
|
||||
delete-branch: true
|
||||
branch: deps/update-zstd-${{ github.run_number }}
|
||||
branch: deps/update-zstd
|
||||
body: |
|
||||
## What does this PR do?
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ register_repository(
|
||||
REPOSITORY
|
||||
cloudflare/lol-html
|
||||
COMMIT
|
||||
d64457d9ff0143deef025d5df7e8586092b9afb7
|
||||
e9e16dca48dd4a8ffbc77642bc4be60407585f11
|
||||
)
|
||||
|
||||
set(LOLHTML_CWD ${VENDOR_PATH}/lolhtml/c-api)
|
||||
|
||||
@@ -6,7 +6,8 @@ endif()
|
||||
|
||||
optionx(BUILDKITE_ORGANIZATION_SLUG STRING "The organization slug to use on Buildkite" DEFAULT "bun")
|
||||
optionx(BUILDKITE_PIPELINE_SLUG STRING "The pipeline slug to use on Buildkite" DEFAULT "bun")
|
||||
optionx(BUILDKITE_BUILD_ID STRING "The build ID to use on Buildkite")
|
||||
optionx(BUILDKITE_BUILD_ID STRING "The build ID (UUID) to use on Buildkite")
|
||||
optionx(BUILDKITE_BUILD_NUMBER STRING "The build number to use on Buildkite")
|
||||
optionx(BUILDKITE_GROUP_ID STRING "The group ID to use on Buildkite")
|
||||
|
||||
if(ENABLE_BASELINE)
|
||||
@@ -32,7 +33,13 @@ if(NOT BUILDKITE_BUILD_ID)
|
||||
return()
|
||||
endif()
|
||||
|
||||
setx(BUILDKITE_BUILD_URL https://buildkite.com/${BUILDKITE_ORGANIZATION_SLUG}/${BUILDKITE_PIPELINE_SLUG}/builds/${BUILDKITE_BUILD_ID})
|
||||
# Use BUILDKITE_BUILD_NUMBER for the URL if available, as the UUID format causes a 302 redirect
|
||||
# that CMake's file(DOWNLOAD) doesn't follow, resulting in empty response.
|
||||
if(BUILDKITE_BUILD_NUMBER)
|
||||
setx(BUILDKITE_BUILD_URL https://buildkite.com/${BUILDKITE_ORGANIZATION_SLUG}/${BUILDKITE_PIPELINE_SLUG}/builds/${BUILDKITE_BUILD_NUMBER})
|
||||
else()
|
||||
setx(BUILDKITE_BUILD_URL https://buildkite.com/${BUILDKITE_ORGANIZATION_SLUG}/${BUILDKITE_PIPELINE_SLUG}/builds/${BUILDKITE_BUILD_ID})
|
||||
endif()
|
||||
setx(BUILDKITE_BUILD_PATH ${BUILDKITE_BUILDS_PATH}/builds/${BUILDKITE_BUILD_ID})
|
||||
|
||||
file(
|
||||
|
||||
@@ -1150,7 +1150,11 @@ pub const Printer = struct {
|
||||
}
|
||||
|
||||
const writer = Output.writerBuffered();
|
||||
try printWithLockfile(allocator, lockfile, format, @TypeOf(writer), writer);
|
||||
printWithLockfile(allocator, lockfile, format, @TypeOf(writer), writer) catch |err| switch (err) {
|
||||
error.OutOfMemory => bun.outOfMemory(),
|
||||
error.BrokenPipe, error.WriteFailed => return,
|
||||
else => |e| return e,
|
||||
};
|
||||
Output.flush();
|
||||
}
|
||||
|
||||
|
||||
@@ -1534,7 +1534,7 @@ var _Interface = class Interface extends InterfaceConstructor {
|
||||
prefix +
|
||||
StringPrototypeSlice.$call(this.line, this.cursor, this.line.length);
|
||||
this.cursor = this.cursor - completeOn.length + prefix.length;
|
||||
this._refreshLine();
|
||||
this[kRefreshLine]();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -964,6 +964,7 @@ fn NewPrinter(
|
||||
}
|
||||
|
||||
if (import.default_name) |default| {
|
||||
p.printSemicolonIfNeeded();
|
||||
p.print("var ");
|
||||
p.printSymbol(default.ref.?);
|
||||
if (comptime Statement == void) {
|
||||
@@ -984,6 +985,7 @@ fn NewPrinter(
|
||||
}
|
||||
|
||||
if (import.items.len > 0) {
|
||||
p.printSemicolonIfNeeded();
|
||||
p.printWhitespacer(ws("var {"));
|
||||
|
||||
if (!import.is_single_line) {
|
||||
|
||||
@@ -1109,15 +1109,15 @@ describe("bundler", () => {
|
||||
"/entry.js": /* js */ `
|
||||
// Test all equality operators with typeof undefined
|
||||
console.log(typeof x !== 'undefined');
|
||||
console.log(typeof x != 'undefined');
|
||||
console.log(typeof x != 'undefined');
|
||||
console.log('undefined' !== typeof x);
|
||||
console.log('undefined' != typeof x);
|
||||
|
||||
|
||||
console.log(typeof x === 'undefined');
|
||||
console.log(typeof x == 'undefined');
|
||||
console.log('undefined' === typeof x);
|
||||
console.log('undefined' == typeof x);
|
||||
|
||||
|
||||
// These should not be optimized
|
||||
console.log(typeof x === 'string');
|
||||
console.log(x === 'undefined');
|
||||
@@ -1135,4 +1135,61 @@ describe("bundler", () => {
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
// https://github.com/oven-sh/bun/issues/26371
|
||||
// Minified bundler output missing semicolon between statements when
|
||||
// using both default and named imports from "bun" module
|
||||
itBundled("minify/BunImportSemicolonInsertion", {
|
||||
files: {
|
||||
"/entry.js": /* js */ `
|
||||
import bun, { embeddedFiles } from "bun"
|
||||
console.log(typeof embeddedFiles)
|
||||
console.log(typeof bun.argv)
|
||||
`,
|
||||
},
|
||||
minifySyntax: true,
|
||||
minifyWhitespace: true,
|
||||
minifyIdentifiers: true,
|
||||
target: "bun",
|
||||
run: {
|
||||
stdout: "object\nobject",
|
||||
},
|
||||
});
|
||||
|
||||
itBundled("minify/BunImportNamespaceAndNamed", {
|
||||
files: {
|
||||
"/entry.js": /* js */ `
|
||||
import * as bun from "bun"
|
||||
import { embeddedFiles } from "bun"
|
||||
console.log(typeof embeddedFiles)
|
||||
console.log(typeof bun.argv)
|
||||
`,
|
||||
},
|
||||
minifySyntax: true,
|
||||
minifyWhitespace: true,
|
||||
minifyIdentifiers: true,
|
||||
target: "bun",
|
||||
run: {
|
||||
stdout: "object\nobject",
|
||||
},
|
||||
});
|
||||
|
||||
itBundled("minify/BunImportDefaultNamespaceAndNamed", {
|
||||
files: {
|
||||
"/entry.js": /* js */ `
|
||||
import bun, * as bunNs from "bun"
|
||||
import { embeddedFiles } from "bun"
|
||||
console.log(typeof embeddedFiles)
|
||||
console.log(typeof bun.argv)
|
||||
console.log(typeof bunNs.argv)
|
||||
`,
|
||||
},
|
||||
minifySyntax: true,
|
||||
minifyWhitespace: true,
|
||||
minifyIdentifiers: true,
|
||||
target: "bun",
|
||||
run: {
|
||||
stdout: "object\nobject\nobject",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
28
test/regression/issue/05828.test.ts
Normal file
28
test/regression/issue/05828.test.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe, isPosix } from "harness";
|
||||
import { join } from "path";
|
||||
|
||||
// https://github.com/oven-sh/bun/issues/5828
|
||||
test.if(isPosix)("bun bun.lockb handles BrokenPipe gracefully", async () => {
|
||||
// Use an existing lockfile that has enough content to trigger the BrokenPipe
|
||||
// The sharp integration test has a lockfile with many dependencies
|
||||
const lockfilePath = join(import.meta.dir, "../../integration/sharp/bun.lockb");
|
||||
|
||||
// Simulate piping to a command that closes stdin immediately (like `true`)
|
||||
// This tests that `bun bun.lockb` doesn't crash with BrokenPipe error
|
||||
await using proc = Bun.spawn({
|
||||
cmd: ["sh", "-c", `${bunExe()} ${lockfilePath} | true`],
|
||||
env: bunEnv,
|
||||
stderr: "pipe",
|
||||
stdout: "pipe",
|
||||
});
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||||
|
||||
// Should exit cleanly (0) instead of crashing with BrokenPipe error
|
||||
// The stderr should NOT contain "BrokenPipe" or "WriteFailed" error
|
||||
expect(stderr).not.toContain("BrokenPipe");
|
||||
expect(stderr).not.toContain("WriteFailed");
|
||||
expect(stderr).not.toContain("error");
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
@@ -1,86 +0,0 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
// https://github.com/oven-sh/bun/issues/26394
|
||||
// Race condition in Bun.serve() where requests can arrive before routes are fully registered,
|
||||
// causing the default "Welcome to Bun!" response instead of the configured handler's response.
|
||||
|
||||
test("concurrent Bun.serve instances should not return Welcome to Bun", async () => {
|
||||
const serverCount = 60;
|
||||
const servers: ReturnType<typeof Bun.serve>[] = [];
|
||||
|
||||
try {
|
||||
// Create many servers concurrently
|
||||
for (let i = 0; i < serverCount; i++) {
|
||||
servers.push(
|
||||
Bun.serve({
|
||||
port: 0,
|
||||
fetch: () => new Response("OK"),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Make concurrent requests to all servers
|
||||
const responses = await Promise.all(
|
||||
servers.map(async server => {
|
||||
const res = await fetch(`http://127.0.0.1:${server.port}/`);
|
||||
return res.text();
|
||||
}),
|
||||
);
|
||||
|
||||
// Verify no "Welcome to Bun!" responses - check for both debug mode message and production mode
|
||||
for (let i = 0; i < responses.length; i++) {
|
||||
expect(responses[i]).not.toContain("Welcome to Bun");
|
||||
expect(responses[i]).not.toBe(""); // Production mode returns empty for renderMissing
|
||||
expect(responses[i]).toBe("OK");
|
||||
}
|
||||
} finally {
|
||||
// Clean up - guaranteed to run even if assertions fail
|
||||
for (const server of servers) {
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("Bun.serve should be ready to handle requests immediately after returning", async () => {
|
||||
// Test a single server with immediate fetch - this tests if the server is ready synchronously
|
||||
using server = Bun.serve({
|
||||
port: 0,
|
||||
fetch: () => new Response("handler response"),
|
||||
});
|
||||
|
||||
// Immediately fetch - if there's a race condition, this might return "Welcome to Bun!"
|
||||
const response = await fetch(`http://127.0.0.1:${server.port}/`);
|
||||
const text = await response.text();
|
||||
|
||||
expect(text).toBe("handler response");
|
||||
});
|
||||
|
||||
test("multiple sequential Bun.serve instances with immediate requests", async () => {
|
||||
// Create servers sequentially and immediately request from each
|
||||
const results: string[] = [];
|
||||
const servers: ReturnType<typeof Bun.serve>[] = [];
|
||||
|
||||
try {
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const server = Bun.serve({
|
||||
port: 0,
|
||||
fetch: () => new Response(`server-${i}`),
|
||||
});
|
||||
servers.push(server);
|
||||
|
||||
// Immediately fetch from the server
|
||||
const response = await fetch(`http://127.0.0.1:${server.port}/`);
|
||||
results.push(await response.text());
|
||||
}
|
||||
|
||||
// Verify all responses match expected
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
expect(results[i]).toBe(`server-${i}`);
|
||||
}
|
||||
} finally {
|
||||
// Clean up - guaranteed to run even if assertions fail
|
||||
for (const server of servers) {
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
40
test/regression/issue/26411.test.ts
Normal file
40
test/regression/issue/26411.test.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe } from "harness";
|
||||
|
||||
// https://github.com/oven-sh/bun/issues/26411
|
||||
// Tab completion with node:readline/promises threw
|
||||
// "TypeError: this._refreshLine is not a function"
|
||||
test("tab completion works with node:readline/promises", async () => {
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [
|
||||
bunExe(),
|
||||
"-e",
|
||||
`
|
||||
import readline from "node:readline/promises";
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
terminal: true,
|
||||
completer: (line) => [["FOO", "FOOBAR"], line]
|
||||
});
|
||||
rl.line = "foo";
|
||||
rl.cursor = 3;
|
||||
setTimeout(() => {
|
||||
rl.close();
|
||||
console.log("OK");
|
||||
process.exit(0);
|
||||
}, 100);
|
||||
rl.write("", { name: "tab" });
|
||||
`,
|
||||
],
|
||||
env: bunEnv,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||||
|
||||
expect(stderr).not.toContain("this._refreshLine is not a function");
|
||||
expect(stdout).toContain("OK");
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
Reference in New Issue
Block a user