diff --git a/src/index.tsx b/src/index.tsx index 0ccf188..6a85fe9 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -161,14 +161,37 @@ export class Hype< get defaults() { this.registerRoutes() + const isDev = process.env.NODE_ENV !== 'production' + let port = process.env.PORT ? Number(process.env.PORT) : 3000 + + if (isDev) { + port = findAvailablePortSync(port) + } + return { - port: process.env.PORT ?? '3000', + port, fetch: this.fetch, idleTimeout: 255 } } } +/** + * Synchronously find an available port starting from the given port + */ +function findAvailablePortSync(startPort: number, maxAttempts = 100): number { + for (let port = startPort; port < startPort + maxAttempts; port++) { + try { + const server = Bun.serve({ port, fetch: () => new Response() }) + server.stop(true) + return port + } catch { + continue + } + } + throw new Error(`Could not find an available port after ${maxAttempts} attempts starting from ${startPort}`) +} + function render404(c: Context) { return c.text('File not found', 404) } \ No newline at end of file diff --git a/src/port-selection.test.ts b/src/port-selection.test.ts new file mode 100644 index 0000000..2625ce3 --- /dev/null +++ b/src/port-selection.test.ts @@ -0,0 +1,44 @@ +import { test, expect } from "bun:test" +import { Hype } from "./index.tsx" + +test("defaults returns next available port in dev mode", () => { + // Start a server on port 4000 to block it + const blocker = Bun.serve({ + port: 4000, + fetch: () => new Response("blocker"), + }) + + // Set NODE_ENV to development and PORT to 4000 + const originalNodeEnv = process.env.NODE_ENV + const originalPort = process.env.PORT + process.env.NODE_ENV = "development" + process.env.PORT = "4000" + + const app = new Hype({}) + const config = app.defaults + + // Should have found port 4001 since 4000 is taken + expect(config.port).toBe(4001) + + // Clean up + blocker.stop(true) + process.env.NODE_ENV = originalNodeEnv + process.env.PORT = originalPort +}) + +test("defaults uses exact port in production mode", () => { + const originalNodeEnv = process.env.NODE_ENV + const originalPort = process.env.PORT + process.env.NODE_ENV = "production" + process.env.PORT = "4002" + + const app = new Hype({}) + const config = app.defaults + + // Should use exact port in production + expect(config.port).toBe(4002) + + // Clean up + process.env.NODE_ENV = originalNodeEnv + process.env.PORT = originalPort +})