/
Corpuscul
/
sdr_crm
Обзор
Документация
Войти
/
Corpuscul
/
sdr_crm
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
scripts/dev-api.mjs
98 строк
3 KB
Andrey Ivanchenkov
feat: v3.3.2 — онлайн-чат и embed для сайта, снимок релиза
28 июл 2026, 08:11
28 июл 2026, 08:11
1b1de56
Код
Авторство
О чём код?
#!/usr/bin/env node /** * Dev API launcher: free :3000, run tsx (no hot-reload — PGlite breaks on watch). */ import { spawn, spawnSync } from "node:child_process"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; const ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); const SERVER = join(ROOT, "server"); const npm = process.platform === "win32" ? "npm.cmd" : "npm"; function ensureDevEnv() { if (!process.env.ALLOW_DEMO_LOGIN) process.env.ALLOW_DEMO_LOGIN = "1"; if (!process.env.SEED_DEMO_USERS) process.env.SEED_DEMO_USERS = "1"; if (!process.env.ADMIN_PASSWORD) process.env.ADMIN_PASSWORD = "Admin1234"; if (!process.env.DEMO_PASSWORD) process.env.DEMO_PASSWORD = "DemoOp2026x"; if (!process.env.INTEGRATOR_PASSWORD) process.env.INTEGRATOR_PASSWORD = "DemoInt2026x"; if (!process.env.MARKETER_PASSWORD) process.env.MARKETER_PASSWORD = "DemoMrk2026x"; if (!process.env.JWT_SECRET) process.env.JWT_SECRET = "dev-only-jwt-secret-min-32-chars-long"; if (!process.env.USE_PGLITE) process.env.USE_PGLITE = "1"; } ensureDevEnv(); function killPort(port) { if (process.platform === "win32") { const r = spawnSync("netstat", ["-ano"], { encoding: "utf8", shell: true }); const pids = new Set(); for (const line of (r.stdout || "").split(/\r?\n/)) { if (!line.includes(`:${port}`) || !/LISTENING/i.test(line)) continue; const pid = line.trim().split(/\s+/).pop(); if (pid && /^\d+$/.test(pid)) pids.add(pid); } for (const pid of pids) { spawnSync("taskkill", ["/pid", pid, "/f", "/t"], { stdio: "ignore", shell: true }); } return; } spawnSync("sh", ["-c", `lsof -ti:${port} | xargs -r kill -9`], { stdio: "inherit" }); } let child = null; let stopping = false; let restartTimer = null; function startApi() { if (stopping) return; child = spawn(npm, ["exec", "tsx", "src/index.ts"], { cwd: SERVER, stdio: "inherit", shell: process.platform === "win32", env: { ...process.env, NODE_ENV: process.env.NODE_ENV || "development" }, }); child.on("exit", (code, signal) => { child = null; if (stopping) return; if (code === 0 && !signal) return; if (signal === "SIGTERM" || signal === "SIGINT") return; console.warn(`[dev-api] API exited (code=${code ?? "?"}, signal=${signal ?? "?"}), restart in 3s…`); restartTimer = setTimeout(() => { if (stopping) return; const r = spawnSync("netstat", ["-ano"], { encoding: "utf8", shell: true }); if (r.stdout?.includes(":3000") && /LISTENING/i.test(r.stdout)) { console.warn("[dev-api] :3000 already in use — skip restart (another API instance?)"); return; } startApi(); }, 3000); }); } console.log("[dev-api] Freeing :3000…"); if (!process.env.DEV_FROM_ALL) { killPort(3000); await new Promise((r) => setTimeout(r, 600)); } else { console.log("[dev-api] Port clear skipped (dev:all already freed :3000)"); } console.log("[dev-api] Starting API…"); startApi(); const shutdown = () => { stopping = true; if (restartTimer) clearTimeout(restartTimer); if (!child) process.exit(0); if (process.platform === "win32") { spawn("taskkill", ["/pid", String(child.pid), "/f", "/t"], { stdio: "ignore", shell: true }); } else { child.kill("SIGTERM"); } setTimeout(() => process.exit(0), 500); }; process.on("SIGINT", shutdown); process.on("SIGTERM", shutdown);