summaryrefslogtreecommitdiffhomepage
path: root/packages/api/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/api/src')
-rw-r--r--packages/api/src/index.ts61
1 files changed, 55 insertions, 6 deletions
diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts
index a0ad025..478abe0 100644
--- a/packages/api/src/index.ts
+++ b/packages/api/src/index.ts
@@ -70,9 +70,58 @@ app.get(
export { app };
-export default {
- port: Number(process.env.PORT) || 3000,
- idleTimeout: 60,
- fetch: app.fetch,
- websocket,
-};
+// Starting port (overridable via PORT) and the inclusive ceiling we will bump
+// up to when a port is already in use. If 3000 is taken we try 3001, 3002, …
+// up to MAX_PORT, so multiple dispatch instances (e.g. testing several
+// features at once) can coexist without manually juggling ports. The frontend
+// defaults to :3000 — point it at the chosen port via the in-app API-URL
+// field / VITE_API_URL when a bump happens.
+const START_PORT = Number(process.env.PORT) || 3000;
+const MAX_PORT = 3010;
+
+/**
+ * Bind the server to `START_PORT`, incrementing by one on EADDRINUSE until a
+ * free port is found or MAX_PORT is exceeded. Bun's `Bun.serve` throws
+ * synchronously when the port is taken, so we can catch and retry. Returns the
+ * live server (whose `.port` reflects the port actually bound).
+ */
+function serveWithPortFallback() {
+ let lastError: unknown;
+ for (let port = START_PORT; port <= MAX_PORT; port++) {
+ try {
+ const server = Bun.serve({
+ port,
+ idleTimeout: 60,
+ fetch: app.fetch,
+ websocket,
+ });
+ if (port !== START_PORT) {
+ console.warn(
+ `dispatch: port ${START_PORT} in use — bound to ${port} instead. ` +
+ `Set the frontend's API URL to http://localhost:${port}.`,
+ );
+ }
+ console.log(`dispatch: API listening on http://localhost:${server.port}`);
+ return server;
+ } catch (err) {
+ const code = (err as NodeJS.ErrnoException)?.code;
+ if (code === "EADDRINUSE") {
+ lastError = err;
+ continue;
+ }
+ throw err;
+ }
+ }
+ console.error(
+ `dispatch: no free port in range ${START_PORT}-${MAX_PORT}. ` +
+ `Free one up or set PORT to an open port.`,
+ );
+ throw lastError ?? new Error(`No free port in range ${START_PORT}-${MAX_PORT}`);
+}
+
+// Only start the server when run as the entry point — importing this module
+// (e.g. for `app`) must not bind a port. This preserves the prior
+// default-export behavior where Bun served only the entry file.
+if (import.meta.main) {
+ serveWithPortFallback();
+}