UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

108 lines (107 loc) 7.41 kB
import { n as isVitestRuntimeEnv } from "./env-Di49gJwo.js"; import { i as isLoopbackHost, l as isValidIPv4, p as resolveGatewayBindHost, t as defaultGatewayBindMode } from "./net-DTe7AQiu.js"; import { t as assertGatewayAuthConfigured } from "./auth-DXSWhsnk.js"; import { n as resolveGatewayAuth } from "./auth-resolve-BSKl_nHz.js"; import { n as isUnsafeGatewayTailscaleNoAuth, t as formatUnsafeGatewayTailscaleNoAuthMessage } from "./gateway-tailscale-auth-policy-DLytnhv-.js"; import { r as normalizeControlUiBasePath } from "./control-ui-shared-Clry3kRy.js"; import { r as mergeGatewayTailscaleConfig } from "./startup-auth-BtAuEBV-.js"; import { v as resolveHooksConfig } from "./hooks-BuwUpRxl.js"; //#region src/gateway/env-deprecation.ts const LEGACY_ENV_PREFIXES = ["CLAWDBOT_", "MOLTBOT_"]; let warned = false; /** Emits a one-time warning when ignored legacy CLAWDBOT_/MOLTBOT_ env vars are present. */ function warnLegacyOpenClawEnvVars(env = process.env) { if (warned || isVitestRuntimeEnv(env)) return; const prefixCounts = /* @__PURE__ */ new Map(); for (const key of Object.keys(env)) { const prefix = LEGACY_ENV_PREFIXES.find((candidate) => key.startsWith(candidate)); if (prefix) prefixCounts.set(prefix, (prefixCounts.get(prefix) ?? 0) + 1); } const legacyVarCount = [...prefixCounts.values()].reduce((total, count) => total + count, 0); if (legacyVarCount === 0) return; const detectedPrefixes = LEGACY_ENV_PREFIXES.filter((prefix) => prefixCounts.has(prefix)).map((prefix) => `${prefix}*`).join(", "); process.emitWarning([`Legacy ${detectedPrefixes} environment variables were detected (${legacyVarCount} total), but OpenClaw only reads OPENCLAW_* names now.`, "Rename them by replacing the legacy prefix with OPENCLAW_; the old names are ignored."].join("\n"), { code: "OPENCLAW_LEGACY_ENV_VARS", type: "DeprecationWarning" }); warned = true; } //#endregion //#region src/gateway/server-runtime-config.ts /** Resolves bind, auth, HTTP, Tailscale, and hook settings for one gateway start. */ async function resolveGatewayRuntimeConfig(params) { warnLegacyOpenClawEnvVars(); const tailscaleModeEarly = (params.tailscale?.mode ?? params.cfg.gateway?.tailscale?.mode) || "off"; const bindMode = params.bind ?? params.cfg.gateway?.bind ?? (tailscaleModeEarly !== "off" ? "loopback" : defaultGatewayBindMode()); const customBindHost = params.cfg.gateway?.customBindHost; const bindHost = params.host ?? await resolveGatewayBindHost(bindMode, customBindHost); if (bindMode === "loopback" && !isLoopbackHost(bindHost)) throw new Error(`gateway bind=loopback resolved to non-loopback host ${bindHost}; refusing fallback to a network bind`); if (bindMode === "custom") { const configuredCustomBindHost = customBindHost?.trim(); if (!configuredCustomBindHost) throw new Error("gateway.bind=custom requires gateway.customBindHost"); if (!isValidIPv4(configuredCustomBindHost)) throw new Error(`gateway.bind=custom requires a valid IPv4 customBindHost (got ${configuredCustomBindHost})`); if (bindHost !== configuredCustomBindHost) throw new Error(`gateway bind=custom requested ${configuredCustomBindHost} but resolved ${bindHost}; refusing fallback`); } const controlUiEnabled = params.controlUiEnabled ?? params.cfg.gateway?.controlUi?.enabled ?? true; const openAiChatCompletionsConfig = params.cfg.gateway?.http?.endpoints?.chatCompletions; const openAiChatCompletionsEnabled = params.openAiChatCompletionsEnabled ?? openAiChatCompletionsConfig?.enabled ?? false; const openResponsesConfig = params.cfg.gateway?.http?.endpoints?.responses; const openResponsesEnabled = params.openResponsesEnabled ?? openResponsesConfig?.enabled ?? false; const strictTransportSecurityConfig = params.cfg.gateway?.http?.securityHeaders?.strictTransportSecurity; const strictTransportSecurityHeader = strictTransportSecurityConfig === false ? void 0 : typeof strictTransportSecurityConfig === "string" && strictTransportSecurityConfig.trim().length > 0 ? strictTransportSecurityConfig.trim() : void 0; const controlUiBasePath = normalizeControlUiBasePath(params.cfg.gateway?.controlUi?.basePath); const controlUiRootRaw = params.cfg.gateway?.controlUi?.root; const controlUiRoot = typeof controlUiRootRaw === "string" && controlUiRootRaw.trim().length > 0 ? controlUiRootRaw.trim() : void 0; const tailscaleConfig = mergeGatewayTailscaleConfig(params.cfg.gateway?.tailscale ?? {}, params.tailscale ?? {}); const tailscaleMode = tailscaleConfig.mode ?? "off"; const resolvedAuth = resolveGatewayAuth({ authConfig: params.cfg.gateway?.auth, authOverride: params.auth, env: process.env, tailscaleMode }); const authMode = resolvedAuth.mode; const hasToken = typeof resolvedAuth.token === "string" && resolvedAuth.token.trim().length > 0; const hasPassword = typeof resolvedAuth.password === "string" && resolvedAuth.password.trim().length > 0; const hasSharedSecret = authMode === "token" && hasToken || authMode === "password" && hasPassword; const hooksConfig = resolveHooksConfig(params.cfg); const trustedProxies = params.cfg.gateway?.trustedProxies ?? []; const controlUiAllowedOrigins = (params.cfg.gateway?.controlUi?.allowedOrigins ?? []).map((value) => value.trim()).filter(Boolean); const dangerouslyAllowHostHeaderOriginFallback = params.cfg.gateway?.controlUi?.dangerouslyAllowHostHeaderOriginFallback === true; assertGatewayAuthConfigured(resolvedAuth, params.cfg.gateway?.auth); if (tailscaleMode === "funnel" && authMode !== "password") throw new Error("tailscale funnel requires gateway auth mode=password (set gateway.auth.password or OPENCLAW_GATEWAY_PASSWORD)"); if (isUnsafeGatewayTailscaleNoAuth({ authMode, tailscaleMode })) throw new Error(formatUnsafeGatewayTailscaleNoAuthMessage(tailscaleMode)); if (tailscaleMode !== "off" && !isLoopbackHost(bindHost)) throw new Error("tailscale serve/funnel requires gateway bind=loopback (127.0.0.1)"); if (!isLoopbackHost(bindHost) && !hasSharedSecret && authMode !== "trusted-proxy") throw new Error(`refusing to bind gateway to ${bindHost}:${params.port} without auth (set gateway.auth.token/password, or set OPENCLAW_GATEWAY_TOKEN/OPENCLAW_GATEWAY_PASSWORD; legacy CLAWDBOT_* and MOLTBOT_* environment variables are ignored)`); if (controlUiEnabled && !isLoopbackHost(bindHost) && controlUiAllowedOrigins.length === 0 && !dangerouslyAllowHostHeaderOriginFallback) throw new Error("non-loopback Control UI requires gateway.controlUi.allowedOrigins (set explicit origins), or set gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true to use Host-header origin fallback mode"); if (authMode === "trusted-proxy") { if (trustedProxies.length === 0) throw new Error("gateway auth mode=trusted-proxy requires gateway.trustedProxies to be configured with at least one proxy IP"); } return { bindHost, controlUiEnabled, openAiChatCompletionsEnabled, openAiChatCompletionsConfig: openAiChatCompletionsConfig ? { ...openAiChatCompletionsConfig, enabled: openAiChatCompletionsEnabled } : void 0, openResponsesEnabled, openResponsesConfig: openResponsesConfig ? { ...openResponsesConfig, enabled: openResponsesEnabled } : void 0, strictTransportSecurityHeader, controlUiBasePath, controlUiRoot, resolvedAuth, authMode, tailscaleConfig, tailscaleMode, hooksConfig }; } //#endregion export { resolveGatewayRuntimeConfig };