From fb597c677e12713221e7b6850a804c0e990a2ebb Mon Sep 17 00:00:00 2001 From: Steven Rafferty Date: Thu, 26 Feb 2026 15:15:35 +0000 Subject: [PATCH] feat: improve API configuration and script execution - Added API_HOST variable to .env.example for enhanced host configuration. - Updated package.json scripts to utilize a new run-next.mjs script for development and production. - Introduced run-next.mjs to manage Next.js server execution with dynamic port handling. - Enhanced route.ts files to normalize API base URLs and improve configuration checks. - Updated apiBridgeServer.ts to use API_HOST for server initialization. - Expanded global TypeScript definitions to include API_HOST. --- .env.example | 1 + package.json | 4 +- scripts/run-next.mjs | 41 +++++++++++++++++++ .../guide-settings/[toolId]/route.ts | 24 +++++++++-- src/app/api/cli-tools/status/route.ts | 10 ++++- src/lib/apiBridgeServer.ts | 4 +- src/types/global.d.ts | 1 + 7 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 scripts/run-next.mjs diff --git a/.env.example b/.env.example index 379c72b5f9..0ed1391ba2 100644 --- a/.env.example +++ b/.env.example @@ -27,6 +27,7 @@ SQLITE_CLEAN_LEGACY_FILES=true PORT=20128 # Optional split ports: # API_PORT=20128 +# API_HOST=0.0.0.0 # DASHBOARD_PORT=20128 NODE_ENV=production INSTANCE_NAME=omniroute diff --git a/package.json b/package.json index b57b582870..78532795e1 100644 --- a/package.json +++ b/package.json @@ -42,10 +42,10 @@ }, "homepage": "https://omniroute.online", "scripts": { - "dev": "OMNIROUTE_PORT=${PORT:-20128} next dev --webpack --port ${DASHBOARD_PORT:-${PORT:-20128}}", + "dev": "node scripts/run-next.mjs dev", "build": "next build --webpack", "build:cli": "node scripts/prepublish.mjs", - "start": "OMNIROUTE_PORT=${PORT:-20128} next start --port ${DASHBOARD_PORT:-${PORT:-20128}}", + "start": "node scripts/run-next.mjs start", "lint": "eslint .", "test": "node --test tests/unit/*.test.mjs", "test:unit": "node --import tsx/esm --test tests/unit/*.test.mjs", diff --git a/scripts/run-next.mjs b/scripts/run-next.mjs new file mode 100644 index 0000000000..0214bed3b3 --- /dev/null +++ b/scripts/run-next.mjs @@ -0,0 +1,41 @@ +#!/usr/bin/env node + +import { spawn } from "node:child_process"; + +function parsePort(value, fallback) { + const parsed = Number.parseInt(String(value), 10); + return Number.isFinite(parsed) && parsed > 0 && parsed <= 65535 ? parsed : fallback; +} + +const mode = process.argv[2] === "start" ? "start" : "dev"; + +const basePort = parsePort(process.env.PORT || "20128", 20128); +const apiPort = parsePort(process.env.API_PORT || String(basePort), basePort); +const dashboardPort = parsePort(process.env.DASHBOARD_PORT || String(basePort), basePort); + +const args = ["./node_modules/next/dist/bin/next", mode, "--port", String(dashboardPort)]; +if (mode === "dev") { + args.splice(2, 0, "--webpack"); +} + +const child = spawn(process.execPath, args, { + stdio: "inherit", + env: { + ...process.env, + OMNIROUTE_PORT: String(basePort), + PORT: String(dashboardPort), + DASHBOARD_PORT: String(dashboardPort), + API_PORT: String(apiPort), + }, +}); + +child.on("exit", (code, signal) => { + if (signal) { + process.kill(process.pid, signal); + return; + } + process.exit(code ?? 0); +}); + +process.on("SIGINT", () => child.kill("SIGINT")); +process.on("SIGTERM", () => child.kill("SIGTERM")); diff --git a/src/app/api/cli-tools/guide-settings/[toolId]/route.ts b/src/app/api/cli-tools/guide-settings/[toolId]/route.ts index 38fca04b98..fd52913c94 100644 --- a/src/app/api/cli-tools/guide-settings/[toolId]/route.ts +++ b/src/app/api/cli-tools/guide-settings/[toolId]/route.ts @@ -53,22 +53,40 @@ async function saveContinueConfig({ baseUrl, apiKey, model }) { } // Build the OmniRoute model entry + const normalizedBaseUrl = String(baseUrl || "") + .trim() + .replace(/\/+$/, ""); const routerModel = { - apiBase: baseUrl, + apiBase: normalizedBaseUrl, title: model, model: model, provider: "openai", apiKey: apiKey || "sk_omniroute", + omnirouteManaged: true, }; // Merge into existing models array const models = existingConfig.models || []; + function normalizeApiBase(value: unknown): string { + return String(value || "") + .trim() + .replace(/\/+$/, "") + .toLowerCase(); + } + // Check if OmniRoute entry already exists and update it, or add new const existingIdx = models.findIndex( (m) => - m.apiBase && - (m.apiBase.includes("localhost") || m.apiBase.includes("omniroute") || m.title === model) + m && + (m.omnirouteManaged === true || + normalizeApiBase(m.apiBase) === normalizedBaseUrl.toLowerCase() || + normalizeApiBase(m.apiBase).includes("omniroute") || + normalizeApiBase(m.apiBase).includes("localhost:20128") || + normalizeApiBase(m.apiBase).includes("127.0.0.1:20128") || + String(m.apiKey || "") + .toLowerCase() + .includes("sk_omniroute")) ); if (existingIdx >= 0) { diff --git a/src/app/api/cli-tools/status/route.ts b/src/app/api/cli-tools/status/route.ts index 1465d7f66d..aca9dcb80f 100644 --- a/src/app/api/cli-tools/status/route.ts +++ b/src/app/api/cli-tools/status/route.ts @@ -8,6 +8,9 @@ import { getCliPrimaryConfigPath, } from "@/shared/services/cliRuntime"; import { getAllCliToolLastConfigured } from "@/lib/db/cliToolState"; +import { getRuntimePorts } from "@/lib/runtime/ports"; + +const { apiPort } = getRuntimePorts(); // Check if a tool has OmniRoute configured by reading its config file directly // This replaces the expensive self-referential HTTP calls to /api/cli-tools/*-settings @@ -31,9 +34,12 @@ async function checkToolConfigStatus(toolId: string): Promise { case "openclaw": case "cline": case "kilo": - // Generic check: look for any OmniRoute-related URL in the config + // Generic check: look for OmniRoute-specific markers in the config const configStr = JSON.stringify(config).toLowerCase(); - return configStr.includes("omniroute") || configStr.includes("localhost") + return configStr.includes("omniroute") || + configStr.includes("sk_omniroute") || + configStr.includes(`localhost:${apiPort}`) || + configStr.includes(`127.0.0.1:${apiPort}`) ? "configured" : "not_configured"; default: diff --git a/src/lib/apiBridgeServer.ts b/src/lib/apiBridgeServer.ts index 1b57568d1d..1271481b9c 100644 --- a/src/lib/apiBridgeServer.ts +++ b/src/lib/apiBridgeServer.ts @@ -44,7 +44,7 @@ function proxyRequest(req: IncomingMessage, res: ServerResponse, dashboardPort: } declare global { - // eslint-disable-next-line no-var + var __omnirouteApiBridgeStarted: boolean | undefined; } @@ -54,7 +54,7 @@ export function initApiBridgeServer(): void { const { apiPort, dashboardPort } = getRuntimePorts(); if (apiPort === dashboardPort) return; - const host = process.env.HOSTNAME || "0.0.0.0"; + const host = process.env.API_HOST || "0.0.0.0"; const server = http.createServer((req, res) => { const rawUrl = req.url || "/"; diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 7a89d27969..b711270e5b 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -14,6 +14,7 @@ declare namespace NodeJS { PROMPT_CACHE_TTL_MS?: string; NEXT_PUBLIC_CLOUD_URL?: string; API_PORT?: string; + API_HOST?: string; DASHBOARD_PORT?: string; OMNIROUTE_PORT?: string; NODE_ENV?: "development" | "production" | "test";