#!/usr/bin/env bun import { spawn } from "bun"; import { resolve } from "path"; const ROOT = resolve(import.meta.dir, ".."); const BACKEND = resolve(ROOT, "backend"); const FRONTEND = resolve(ROOT, "frontend"); function run(cmd: string[], cwd = ROOT): Promise { console.log(` → ${cmd.join(" ")}`); const proc = spawn(cmd, { cwd, stdout: "inherit", stderr: "inherit" }); return proc.exited.then((code) => { if (code !== 0) throw new Error(`Command failed (exit ${code}): ${cmd.join(" ")}`); }); } async function waitForService( label: string, check: string[], retries = 30, delayMs = 2000 ): Promise { for (let i = 1; i <= retries; i++) { const proc = spawn(check, { cwd: ROOT, stdout: "pipe", stderr: "pipe" }); if ((await proc.exited) === 0) { console.log(`āœ… ${label} is ready`); return; } console.log(`ā³ Waiting for ${label}... (${i}/${retries})`); await Bun.sleep(delayMs); } throw new Error(`${label} did not become ready in time`); } async function main() { console.log("\n🐳 Starting Docker containers..."); await run(["docker", "compose", "up", "-d"]); console.log("\nā³ Waiting for services..."); await waitForService("PostgreSQL", [ "docker", "compose", "exec", "postgres", "pg_isready", "-U", "xip", ]); await waitForService("Redis", [ "docker", "compose", "exec", "redis", "redis-cli", "ping", ]); console.log("\nšŸ”§ Generating Prisma client..."); await run(["bunx", "prisma", "generate"], BACKEND); console.log("\nšŸ—„ļø Applying database migrations..."); await run( ["bunx", "prisma", "migrate", "dev", "--name", "init", "--skip-seed"], BACKEND ); console.log("\n🌱 Seeding database..."); await run(["bun", "run", "prisma/seed.ts"], BACKEND); console.log("\nāœ… Stack ready! Starting dev servers...\n"); console.log(" Backend → http://localhost:3000"); console.log(" Frontend → http://localhost:5173\n"); const backend = spawn(["bun", "run", "dev"], { cwd: BACKEND, stdout: "inherit", stderr: "inherit", }); const frontend = spawn(["bun", "run", "dev"], { cwd: FRONTEND, stdout: "inherit", stderr: "inherit", }); const cleanup = () => { backend.kill(); frontend.kill(); process.exit(0); }; process.on("SIGINT", cleanup); process.on("SIGTERM", cleanup); await Promise.all([backend.exited, frontend.exited]); } main().catch((err: Error) => { console.error("\nāŒ ", err.message); process.exit(1); });