#!/usr/bin/env node // backend: 运行带 Air 热加载的 Go control-plane。 import { spawn } from "node:child_process"; import { readFileSync, existsSync } from "node:fs"; import { fileURLToPath } from "node:url"; import path from "node:path"; const root = path.dirname(path.dirname(fileURLToPath(import.meta.url))); const envPath = path.join(root, ".env"); // 简易 KEY=value 解析(与 compose 的 env_file 语法一致,无需处理引号)。 const overrides = {}; if (existsSync(envPath)) { for (const line of readFileSync(envPath, "utf8").split("\n")) { const m = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/.exec(line.trim()); if (m && !(m[1] in overrides)) overrides[m[1]] = m[2]; } } else { console.warn("[dev-backend] 未找到 .env,使用本地开发默认值。"); } if (!overrides.CONTROL_PLANE_USERNAME) overrides.CONTROL_PLANE_USERNAME = "admin"; if (!overrides.CONTROL_PLANE_PASSWORD) overrides.CONTROL_PLANE_PASSWORD = "admin123"; const devMasterKey = Buffer.from("creatorhub dev local master key", "utf8").toString("base64"); if (Buffer.from(overrides.CREATORHUB_CREDENTIAL_MASTER_KEY ?? "", "base64").length !== 32) { if (overrides.CREATORHUB_CREDENTIAL_MASTER_KEY) { console.error("[dev-backend] .env 的 CREATORHUB_CREDENTIAL_MASTER_KEY 不是 32 字节 base64,本地开发改用固定开发密钥。"); } overrides.CREATORHUB_CREDENTIAL_MASTER_KEY = devMasterKey; } if (!overrides.LISTEN_ADDR) overrides.LISTEN_ADDR = ":8082"; if (!overrides.DATABASE_URL) { const postgresPort = overrides.CREATORHUB_POSTGRES_PORT || "15433"; overrides.DATABASE_URL = `postgres://creatorhub@127.0.0.1:${postgresPort}/creatorhub?sslmode=disable`; } if (!overrides.CREATORHUB_CREDENTIAL_STORE_DIR) overrides.CREATORHUB_CREDENTIAL_STORE_DIR = path.join(root, ".dev-credentials"); if (!overrides.WEB_DIR) overrides.WEB_DIR = path.join(root, "web", "dist"); if (!overrides.LOG_LEVEL) overrides.LOG_LEVEL = "debug"; if (!overrides.NATIVE_GATEWAY_ENDPOINT) overrides.NATIVE_GATEWAY_ENDPOINT = "http://127.0.0.1:28187"; const env = { ...process.env, ...overrides }; const air = spawn("air", ["-c", ".air.toml", ...process.argv.slice(2)], { cwd: root, env, stdio: "inherit", }); air.on("exit", (code) => process.exit(code ?? 0));