openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
84 lines (83 loc) • 3.21 kB
JavaScript
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-1VuiLaaR.mjs";
import "./src-CdRlGRnW.mjs";
import { t as expectDefined } from "./expect-lbe3Hgrh.mjs";
import { n as parseTcpPort } from "./tcp-port-8uSpDbMY.mjs";
import { l as isIpv6Address, v as parseCanonicalIpAddress } from "./ip-jvtZlu_y.mjs";
import { a as resolveControlUiAllowedOrigins } from "./gateway-control-ui-origins-WhL6Lrby.mjs";
import { o as formatPortRangeHint } from "./error-format-BaRMqGR7.mjs";
import { i as getTailnetHostname } from "./tailscale-Cbb5rWvi.mjs";
//#region src/gateway/gateway-config-prompts.shared.ts
function validateGatewayPortInput(value) {
return parseTcpPort(value) === null ? formatPortRangeHint() : void 0;
}
const TAILSCALE_EXPOSURE_OPTIONS = [
{
value: "off",
label: "Off",
hint: "No Tailscale exposure"
},
{
value: "serve",
label: "Serve",
hint: "Private HTTPS for your tailnet (devices on Tailscale)"
},
{
value: "funnel",
label: "Funnel",
hint: "Public HTTPS via Tailscale Funnel (internet)"
}
];
const TAILSCALE_MISSING_BIN_NOTE_LINES = [
"Tailscale binary not found in PATH or /Applications.",
"Ensure Tailscale is installed from:",
" https://tailscale.com/download/mac",
"",
"You can continue setup, but serve/funnel will fail at runtime."
];
const TAILSCALE_DOCS_LINES = [
"Docs:",
"https://docs.openclaw.ai/gateway/tailscale",
"https://docs.openclaw.ai/web"
];
function normalizeTailnetHostForUrl(rawHost) {
const trimmed = rawHost.trim().replace(/\.$/, "");
if (!trimmed) return null;
const parsed = parseCanonicalIpAddress(trimmed);
if (parsed && isIpv6Address(parsed)) return `[${normalizeLowercaseStringOrEmpty(parsed.toString())}]`;
return trimmed;
}
function buildTailnetHttpsOrigin(rawHost) {
const normalizedHost = normalizeTailnetHostForUrl(rawHost);
if (!normalizedHost) return null;
try {
return new URL(`https://${normalizedHost}`).origin;
} catch {
return null;
}
}
function appendAllowedOrigin(existing, origin) {
const current = existing ?? [];
const normalized = normalizeLowercaseStringOrEmpty(origin);
if (current.some((entry) => normalizeLowercaseStringOrEmpty(entry) === normalized)) return current;
return [...current, origin];
}
async function maybeAddTailnetOriginToControlUiAllowedOrigins(params) {
if (params.tailscaleMode !== "serve" && params.tailscaleMode !== "funnel") return params.config;
const tsOrigin = await getTailnetHostname(void 0, params.tailscaleBin ?? void 0).then((host) => buildTailnetHttpsOrigin(expectDefined(host, "gateway config prompts.shared host"))).catch(() => null);
if (!tsOrigin) return params.config;
const existing = resolveControlUiAllowedOrigins(params.config);
const updatedOrigins = appendAllowedOrigin(existing, tsOrigin);
if (updatedOrigins === existing) return params.config;
return {
...params.config,
gateway: {
...params.config.gateway,
controlUi: {
...params.config.gateway?.controlUi,
allowedOrigins: updatedOrigins
}
}
};
}
//#endregion
export { validateGatewayPortInput as a, maybeAddTailnetOriginToControlUiAllowedOrigins as i, TAILSCALE_EXPOSURE_OPTIONS as n, TAILSCALE_MISSING_BIN_NOTE_LINES as r, TAILSCALE_DOCS_LINES as t };