openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
64 lines (63 loc) • 3.3 kB
JavaScript
import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js";
import { i as resolveTailscalePublishedHost } from "./tailscale-status-D3cAZH54.js";
import { a as hasTailscaleFunnelRouteForPort, i as getTailnetHostnameAfterServe, r as getTailnetHostname, t as claimTailscaleRoute } from "./tailscale-Boe4Jx-9.js";
import { n as prepareTailscalePublishedOrigin } from "./tailscale-published-origin-BvNdSLZR.js";
//#region src/gateway/server-tailscale.ts
async function startGatewayTailscaleExposure(params) {
if (params.tailscaleMode === "off") return null;
if (!params.backend) throw new Error("Managed Tailscale ingress failed to start");
const backendTarget = params.backend.port;
const effectiveMode = params.tailscaleMode;
let clearPublishedOrigin;
if (params.tailscaleMode === "serve" && params.preserveFunnel === true) {
let preservedFunnel;
try {
preservedFunnel = await hasTailscaleFunnelRouteForPort(params.port);
} catch (error) {
params.logTailscale.warn(`serve not changed because external Funnel status could not be inspected: ${formatErrorMessage(error)}`);
throw error;
}
if (preservedFunnel) {
params.logTailscale.warn(`external Tailscale Funnel for port ${params.port} remains active only for plugin-authenticated webhook routes; Gateway-authenticated routes reject its unattributable ingress. First configure a durable gateway password (gateway.auth.password or OPENCLAW_GATEWAY_PASSWORD) and set gateway.auth.mode=password, then run \`openclaw config set gateway.tailscale.mode funnel\` and \`openclaw config unset gateway.tailscale.preserveFunnel\`; see https://docs.openclaw.ai/gateway/tailscale#public-internet-funnel--shared-password`);
return null;
}
}
let claim;
try {
claim = await claimTailscaleRoute(params.tailscaleMode, backendTarget, params.port, params.logTailscale.info);
const host = await (params.tailscaleMode === "serve" ? getTailnetHostnameAfterServe() : getTailnetHostname()).catch(() => null);
if (!claim.isActive()) throw new Error(`Managed Tailscale ${params.tailscaleMode} claim exited during startup`);
if (host) {
const uiPath = params.controlUiBasePath ? `${params.controlUiBasePath}/` : "/";
const publicHost = resolveTailscalePublishedHost({
tailscaleMode: effectiveMode,
tailnetHost: host
});
if (publicHost) {
clearPublishedOrigin = prepareTailscalePublishedOrigin({
origin: `https://${publicHost}`,
mode: effectiveMode
});
params.logTailscale.info(`${params.tailscaleMode} enabled: https://${publicHost}${uiPath} (WS via wss://${publicHost})`);
} else params.logTailscale.info(`${params.tailscaleMode} enabled`);
} else params.logTailscale.info(`${params.tailscaleMode} enabled`);
} catch (err) {
clearPublishedOrigin?.();
await claim?.stop();
params.logTailscale.warn(`${params.tailscaleMode} failed: ${formatErrorMessage(err)}`);
throw err;
}
let stopping = false;
claim.exited.then(() => {
if (stopping) return;
clearPublishedOrigin?.();
params.logTailscale.warn(`${params.tailscaleMode} route claim exited; managed Tailscale ingress is unavailable until the Gateway restarts`);
});
return async () => {
stopping = true;
clearPublishedOrigin?.();
await claim.stop();
};
}
//#endregion
export { startGatewayTailscaleExposure };