147 lines · 3.8 KB · JavaScript
RawDownload
import { spawn } from "node:child_process"; const BASE_SERVER_PORT = 3773;const BASE_WEB_PORT = 5173;const MAX_HASH_OFFSET = 3000;const MODE_ARGS = {  dev: [    "run",    "dev",    "--ui=tui",    "--filter=@t3tools/contracts",    "--filter=@t3tools/web",    "--filter=t3",    "--parallel",  ],  "dev:server": ["run", "dev", "--filter=t3"],  "dev:web": ["run", "dev", "--filter=@t3tools/web"],  "dev:desktop": ["run", "dev", "--filter=@t3tools/desktop", "--filter=@t3tools/web", "--parallel"],}; function parseInteger(value, envName) {  const parsed = Number(value);  if (!Number.isInteger(parsed)) {    throw new Error(`Invalid ${envName}: ${value}`);  }  return parsed;} function hashSeed(seed) {  let hash = 0x811c9dc5;  for (let i = 0; i < seed.length; i += 1) {    hash ^= seed.charCodeAt(i);    hash = Math.imul(hash, 0x01000193);  }  return hash >>> 0;} function resolveOffset() {  const explicitOffset = process.env.T3CODE_PORT_OFFSET?.trim();  if (explicitOffset) {    const parsed = parseInteger(explicitOffset, "T3CODE_PORT_OFFSET");    if (parsed < 0) {      throw new Error(`Invalid T3CODE_PORT_OFFSET: ${explicitOffset}`);    }    return { offset: parsed, source: `T3CODE_PORT_OFFSET=${explicitOffset}` };  }   const seed = process.env.T3CODE_DEV_INSTANCE?.trim();  if (!seed) {    return { offset: 0, source: "default ports" };  }   if (/^\d+$/.test(seed)) {    return { offset: Number(seed), source: `numeric T3CODE_DEV_INSTANCE=${seed}` };  }   const offset = (hashSeed(seed) % MAX_HASH_OFFSET) + 1;  return { offset, source: `hashed T3CODE_DEV_INSTANCE=${seed}` };} function resolvePublicHost() {  const rawHost = process.env.T3CODE_PUBLIC_HOST?.trim();  if (!rawHost) return undefined;   if (rawHost.includes("://") || rawHost.includes("/")) {    throw new Error(      `Invalid T3CODE_PUBLIC_HOST: ${rawHost}. Use only a host or IP (no protocol/path).`,    );  }   return rawHost;} function main() {  const mode = process.argv[2];  const isDryRun = process.argv.includes("--dry-run");  if (!mode || !(mode in MODE_ARGS)) {    const supportedModes = Object.keys(MODE_ARGS).join(", ");    throw new Error(`Usage: bun scripts/dev-runner.mjs <mode>. Supported modes: ${supportedModes}`);  }   const { offset, source } = resolveOffset();  const serverPort = BASE_SERVER_PORT + offset;  const webPort = BASE_WEB_PORT + offset;  const publicHost = resolvePublicHost();  const wsHost = publicHost ?? "localhost";  const webHost = publicHost ?? "localhost";   if (serverPort > 65535 || webPort > 65535) {    throw new Error(      `Port offset too large (${offset}). Computed ports: server=${serverPort}, web=${webPort}`,    );  }   const env = {    ...process.env,    T3CODE_PORT: String(serverPort),    PORT: String(webPort),    ELECTRON_RENDERER_PORT: String(webPort),    VITE_WS_URL: `ws://${wsHost}:${serverPort}`,    VITE_DEV_SERVER_URL: `http://${webHost}:${webPort}`,  };   if (publicHost) {    env.VITE_DEV_SERVER_HOST = "0.0.0.0";    env.VITE_HMR_HOST = publicHost;  }   if (mode === "dev" && !env.T3CODE_LOG_WS_EVENTS) {    env.T3CODE_LOG_WS_EVENTS = "1";  }   console.info(    `[dev-runner] mode=${mode} source=${source} serverPort=${serverPort} webPort=${webPort}` +      `${publicHost ? ` publicHost=${publicHost}` : ""}`,  );   if (isDryRun) {    return;  }   const command = process.platform === "win32" ? "turbo.cmd" : "turbo";  const child = spawn(command, MODE_ARGS[mode], {    stdio: "inherit",    env,  });   child.on("exit", (code, signal) => {    if (signal) {      process.kill(process.pid, signal);      return;    }    process.exit(code ?? 0);  });   child.on("error", (error) => {    console.error("[dev-runner] failed to start turbo", error);    process.exit(1);  });} try {  main();} catch (error) {  console.error("[dev-runner]", error);  process.exit(1);}