diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index fb791a1..2a2bb41 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -1,3 +1,5 @@ +import { fileURLToPath } from 'node:url' +import { realpathSync } from 'node:fs' import { serve } from '@hono/node-server' import { serveStatic } from '@hono/node-server/serve-static' import { Hono } from 'hono' @@ -75,8 +77,28 @@ startOutboxWorker() app.use('/*', serveStatic({ root: './public' })) app.get('*', serveStatic({ path: './public/index.html' })) +/** + * True only when this module is the process entrypoint (run directly), not when it + * is imported (e.g. by route tests that import `app`). + * + * WR-05: the previous basename-tail comparison + * import.meta.url.endsWith(process.argv[1].replace(/^.*\//, '')) + * was fragile — a symlinked entrypoint or a differently-located file sharing the same + * basename could make it mis-fire (start the server during an unrelated import, or fail + * to start it in production). Compare fully-resolved real paths instead. realpathSync + * resolves symlinks on argv[1]; fileURLToPath turns the module URL into a real path. + */ +function isMainModule(): boolean { + if (!process.argv[1]) return false + try { + return fileURLToPath(import.meta.url) === realpathSync(process.argv[1]) + } catch { + return false + } +} + // Only start the HTTP server when this module is run directly (not imported in tests) -if (process.argv[1] && import.meta.url.endsWith(process.argv[1].replace(/^.*\//, ''))) { +if (isMainModule()) { serve({ fetch: app.fetch, port: 3000 }, (info) => { console.log(`FamilySync API running on http://localhost:${info.port}`) })