import { loadEnvFile } from 'node:process'; import { existsSync } from 'node:fs'; import { createServer } from 'node:net'; import { spawn } from 'node:child_process'; if (existsSync('.env')) loadEnvFile('.env'); async function availablePort() { const server = createServer(); await new Promise((resolve, reject) => { server.once('error', reject); server.listen(0, '127.0.0.1', resolve); }); const address = server.address(); if (!address || typeof address === 'string') throw Error('No development port'); const port = address.port; await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())), ); return port; } const build = spawn('npm', ['run', 'build', '-w', '@hop/shared'], { stdio: 'inherit' }); if ((await new Promise((resolve) => build.on('exit', resolve))) !== 0) process.exit(1); const apiPort = await availablePort(), webPort = await availablePort(); if (apiPort === webPort) throw Error('Port allocation conflicted; run npm run dev again.'); const child = spawn( 'node', [ '--watch', '--watch-path=apps/server/src', '--watch-path=apps/server/drizzle', '--watch-path=packages/shared/dist', '--watch-path=scripts/dev-runtime.mjs', '--watch-preserve-output', '--import', 'tsx', 'scripts/dev-runtime.mjs', ], { stdio: 'inherit', env: { ...process.env, HOP_DEV_API_PORT: String(apiPort), HOP_DEV_WEB_PORT: String(webPort), NODE_ENV: 'development', }, }, ); for (const signal of ['SIGINT', 'SIGTERM']) process.on(signal, () => child.kill(signal)); child.on('exit', (code) => process.exit(code ?? 0));