Compare commits

...

1 Commits

Author SHA1 Message Date
Claude Bot
95c759a578 fix(serve): allow server config with stop method to auto-start
The fix for #26142 incorrectly used `typeof def.stop !== 'function'`
to detect Server instances returned by Bun.serve(). This caused server
config objects with a custom `stop` method (e.g., Elysia apps) to not
auto-start.

Changed the detection to use `typeof def.reload !== 'function'` instead,
since `reload` is specific to Server instances and unlikely to be on
user config objects.

Fixes #26747

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 07:03:03 +00:00
2 changed files with 79 additions and 2 deletions

View File

@@ -167,7 +167,7 @@ pub const ServerEntryPoint = struct {
\\var hmrSymbol = Symbol("BunServerHMR");
\\var entryNamespace = start;
\\function isServerConfig(def) {{
\\ return def && def !== globalThis && (typeof def.fetch === 'function' || def.app != undefined) && typeof def.stop !== 'function';
\\ return def && def !== globalThis && (typeof def.fetch === 'function' || def.app != undefined) && typeof def.reload !== 'function';
\\}}
\\if (typeof entryNamespace?.then === 'function') {{
\\ entryNamespace = entryNamespace.then((entryNamespace) => {{
@@ -206,7 +206,7 @@ pub const ServerEntryPoint = struct {
\\import * as start from "{f}";
\\var entryNamespace = start;
\\function isServerConfig(def) {{
\\ return def && def !== globalThis && (typeof def.fetch === 'function' || def.app != undefined) && typeof def.stop !== 'function';
\\ return def && def !== globalThis && (typeof def.fetch === 'function' || def.app != undefined) && typeof def.reload !== 'function';
\\}}
\\if (typeof entryNamespace?.then === 'function') {{
\\ entryNamespace = entryNamespace.then((entryNamespace) => {{

View File

@@ -0,0 +1,77 @@
import { expect, test } from "bun:test";
import { bunEnv, bunExe, tempDir } from "harness";
// https://github.com/oven-sh/bun/issues/26747
// Server config objects with a `stop` method should still auto-start.
// The previous fix for #26142 incorrectly used the presence of a `stop` method
// to detect Server instances, but user config objects (like Elysia apps) can
// legitimately have a `stop` method.
test("server config with stop method as default export should auto-start", async () => {
using dir = tempDir("issue-26747", {
"server.js": `
// Export a config object with a stop method
// This should still trigger auto-start
export default {
port: 0,
fetch(req) {
return new Response("Hello from server with stop method");
},
stop() {
// Custom stop method - should not prevent auto-start
},
};
// Force the process to exit after 100ms so the test can verify the startup message
// without the server blocking forever
setTimeout(() => process.exit(0), 100);
`,
});
await using proc = Bun.spawn({
cmd: [bunExe(), "server.js"],
env: bunEnv,
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
// Should have started the server (look for the debug message on stdout)
expect(stdout).toContain("Started");
expect(exitCode).toBe(0);
});
test("server config with both stop and reload methods should not auto-start", async () => {
// A config object with a `reload` method is likely a Server instance
// or something that manages itself, so we should not auto-start it
using dir = tempDir("issue-26747-reload", {
"server.js": `
export default {
port: 0,
fetch(req) {
return new Response("Hello");
},
stop() {},
reload() {},
};
console.log("Script completed without auto-starting");
`,
});
await using proc = Bun.spawn({
cmd: [bunExe(), "server.js"],
env: bunEnv,
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
// Should NOT have started the server because it has a reload method
expect(stdout).not.toContain("Started");
expect(stdout).toContain("Script completed without auto-starting");
expect(exitCode).toBe(0);
});