diff options
| author | Adam Malczewski <[email protected]> | 2026-06-04 21:21:20 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-04 21:21:20 +0900 |
| commit | 394f1ed37ce860da6fdc385769bf29f9737105cd (patch) | |
| tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /packages/api/src/index.ts | |
| parent | 81a9cdbadf8c9d940d4fe9a2a0de607dee1f5f1a (diff) | |
| download | dispatch-394f1ed37ce860da6fdc385769bf29f9737105cd.tar.gz dispatch-394f1ed37ce860da6fdc385769bf29f9737105cd.zip | |
chore: genesis — remove all files to rebuild from scratch (arch rewrite)
Diffstat (limited to 'packages/api/src/index.ts')
| -rw-r--r-- | packages/api/src/index.ts | 127 |
1 files changed, 0 insertions, 127 deletions
diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts deleted file mode 100644 index 5615e08..0000000 --- a/packages/api/src/index.ts +++ /dev/null @@ -1,127 +0,0 @@ -import type { PermissionReply } from "@dispatch/core"; -import { createBunWebSocket } from "hono/bun"; -import { agentManager, app, permissionManager } from "./app.js"; - -const { upgradeWebSocket, websocket } = createBunWebSocket(); - -let clientIdCounter = 0; - -app.get( - "/ws", - upgradeWebSocket((_c) => { - const clientId = String(++clientIdCounter); - - return { - onOpen(_event, ws) { - // Send current statuses immediately - ws.send(JSON.stringify({ type: "statuses", statuses: agentManager.getAllStatuses() })); - - // Send any pending permission prompts - const pending = permissionManager.getPending(); - if (pending.length > 0) { - ws.send(JSON.stringify({ type: "permission-prompt", pending })); - } - - const unsubscribe = agentManager.onEvent((event) => { - ws.send(JSON.stringify(event)); - }); - - permissionManager.registerClient(clientId, (data) => { - ws.send(JSON.stringify(data)); - }); - - // Store cleanup on the raw socket - (ws as unknown as { _unsub?: () => void; _clientId?: string })._unsub = unsubscribe; - (ws as unknown as { _unsub?: () => void; _clientId?: string })._clientId = clientId; - }, - onMessage(event, _ws) { - try { - const message = JSON.parse(String(event.data)) as { - type?: string; - id?: string; - reply?: string; - }; - if ( - message.type === "permission-reply" && - typeof message.id === "string" && - typeof message.reply === "string" - ) { - const validReplies: PermissionReply[] = ["once", "always", "reject"]; - if (validReplies.includes(message.reply as PermissionReply)) { - permissionManager.reply(message.id, message.reply as PermissionReply); - } - } - } catch { - // ignore malformed messages - } - }, - onClose(_event, ws) { - const raw = ws as unknown as { _unsub?: () => void; _clientId?: string }; - if (raw._unsub) { - raw._unsub(); - } - if (raw._clientId) { - permissionManager.unregisterClient(raw._clientId); - } - }, - }; - }), -); - -export { app }; - -// Starting port (overridable via PORT). When the port is already in use we -// bump up one at a time (3000 → 3001 → 3002, …) until we find a free one, 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; - -/** - * Bind the server to `START_PORT`, incrementing by one on EADDRINUSE until a - * free port is found (up to the maximum valid TCP port, 65535). 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 <= 65535; 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 at or above ${START_PORT}. ` + - `Free one up or set PORT to an open port.`, - ); - throw lastError ?? new Error(`No free port at or above ${START_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(); -} |
