refactor: dedupe setup token readers

This commit is contained in:
Peter Steinberger
2026-04-07 05:31:45 +01:00
parent 9869941c06
commit 8d05bdda43
11 changed files with 43 additions and 28 deletions

View File

@@ -3,6 +3,7 @@ import type { DiscordGuildEntry, OpenClawConfig } from "openclaw/plugin-sdk/conf
import type { ChannelSetupDmPolicy, ChannelSetupWizard } from "openclaw/plugin-sdk/setup-runtime";
import { createStandardChannelSetupStatus } from "openclaw/plugin-sdk/setup-runtime";
import { formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import {
inspectDiscordSetupAccount,
resolveDiscordSetupAccountConfig,
@@ -113,10 +114,10 @@ export function createDiscordSetupWizardBase(handlers: {
return {
accountConfigured: account.configured,
hasConfiguredValue: account.tokenStatus !== "missing",
resolvedValue: account.token?.trim() || undefined,
resolvedValue: normalizeOptionalString(account.token),
envValue:
accountId === DEFAULT_ACCOUNT_ID
? process.env.DISCORD_BOT_TOKEN?.trim() || undefined
? normalizeOptionalString(process.env.DISCORD_BOT_TOKEN)
: undefined,
};
},

View File

@@ -3,6 +3,7 @@ import {
createStandardChannelSetupStatus,
mergeAllowFromEntries,
} from "openclaw/plugin-sdk/setup";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import { resolveDefaultLineAccountId } from "./accounts.js";
import {
isLineConfigured,
@@ -119,15 +120,17 @@ export const lineSetupWizard: ChannelSetupWizard = {
const resolved = resolveLineAccount({ cfg, accountId });
return {
accountConfigured: Boolean(
resolved.channelAccessToken.trim() && resolved.channelSecret.trim(),
normalizeOptionalString(resolved.channelAccessToken) &&
normalizeOptionalString(resolved.channelSecret),
),
hasConfiguredValue: Boolean(
resolved.config.channelAccessToken?.trim() || resolved.config.tokenFile?.trim(),
normalizeOptionalString(resolved.config.channelAccessToken) ??
normalizeOptionalString(resolved.config.tokenFile),
),
resolvedValue: resolved.channelAccessToken.trim() || undefined,
resolvedValue: normalizeOptionalString(resolved.channelAccessToken),
envValue:
accountId === DEFAULT_ACCOUNT_ID
? process.env.LINE_CHANNEL_ACCESS_TOKEN?.trim() || undefined
? normalizeOptionalString(process.env.LINE_CHANNEL_ACCESS_TOKEN)
: undefined,
};
},
@@ -163,15 +166,17 @@ export const lineSetupWizard: ChannelSetupWizard = {
const resolved = resolveLineAccount({ cfg, accountId });
return {
accountConfigured: Boolean(
resolved.channelAccessToken.trim() && resolved.channelSecret.trim(),
normalizeOptionalString(resolved.channelAccessToken) &&
normalizeOptionalString(resolved.channelSecret),
),
hasConfiguredValue: Boolean(
resolved.config.channelSecret?.trim() || resolved.config.secretFile?.trim(),
normalizeOptionalString(resolved.config.channelSecret) ??
normalizeOptionalString(resolved.config.secretFile),
),
resolvedValue: resolved.channelSecret.trim() || undefined,
resolvedValue: normalizeOptionalString(resolved.channelSecret),
envValue:
accountId === DEFAULT_ACCOUNT_ID
? process.env.LINE_CHANNEL_SECRET?.trim() || undefined
? normalizeOptionalString(process.env.LINE_CHANNEL_SECRET)
: undefined,
};
},

View File

@@ -6,6 +6,7 @@ import {
} from "openclaw/plugin-sdk/setup";
import type { ChannelSetupWizard } from "openclaw/plugin-sdk/setup";
import { formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import {
DEFAULT_ACCOUNT_ID,
listQQBotAccountIds,
@@ -111,7 +112,7 @@ export const qqbotSetupWizard: ChannelSetupWizard = {
resolvedValue: resolved.appId || undefined,
envValue:
accountId === DEFAULT_ACCOUNT_ID
? process.env.QQBOT_APP_ID?.trim() || undefined
? normalizeOptionalString(process.env.QQBOT_APP_ID)
: undefined,
};
},
@@ -144,7 +145,7 @@ export const qqbotSetupWizard: ChannelSetupWizard = {
resolvedValue: resolved.clientSecret || undefined,
envValue:
accountId === DEFAULT_ACCOUNT_ID
? process.env.QQBOT_CLIENT_SECRET?.trim() || undefined
? normalizeOptionalString(process.env.QQBOT_CLIENT_SECRET)
: undefined,
};
},

View File

@@ -11,6 +11,7 @@ import {
type ChannelSetupWizard,
type OpenClawConfig,
} from "openclaw/plugin-sdk/setup";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import { listAccountIds, resolveAccount } from "./accounts.js";
import type { SynologyChatAccountRaw, SynologyChatChannelConfig } from "./types.js";
@@ -212,11 +213,11 @@ export const synologyChatSetupWizard: ChannelSetupWizard = {
const raw = getRawAccountConfig(cfg, accountId);
return {
accountConfigured: isSynologyChatConfigured(cfg, accountId),
hasConfiguredValue: Boolean(raw.token?.trim()),
resolvedValue: account.token.trim() || undefined,
hasConfiguredValue: Boolean(normalizeOptionalString(raw.token)),
resolvedValue: normalizeOptionalString(account.token),
envValue:
accountId === DEFAULT_ACCOUNT_ID
? process.env.SYNOLOGY_CHAT_TOKEN?.trim() || undefined
? normalizeOptionalString(process.env.SYNOLOGY_CHAT_TOKEN)
: undefined,
};
},

View File

@@ -13,6 +13,7 @@ import {
} from "openclaw/plugin-sdk/setup";
import type { ChannelSetupWizard } from "openclaw/plugin-sdk/setup";
import { formatCliCommand, formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import { inspectTelegramAccount } from "./account-inspect.js";
import {
listTelegramAccountIds,
@@ -161,10 +162,10 @@ export const telegramSetupWizard: ChannelSetupWizard = {
return {
accountConfigured: Boolean(resolved.token) || hasConfiguredValue,
hasConfiguredValue,
resolvedValue: resolved.token?.trim() || undefined,
resolvedValue: normalizeOptionalString(resolved.token),
envValue:
accountId === DEFAULT_ACCOUNT_ID
? process.env.TELEGRAM_BOT_TOKEN?.trim() || undefined
? normalizeOptionalString(process.env.TELEGRAM_BOT_TOKEN)
: undefined,
};
},

View File

@@ -8,6 +8,7 @@ import {
type PortUsage,
} from "../../infra/ports.js";
import { killProcessTree } from "../../process/kill-tree.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { sleep } from "../../utils.js";
export const DEFAULT_RESTART_HEALTH_TIMEOUT_MS = 60_000;
@@ -66,8 +67,8 @@ function looksLikeAuthClose(code: number | undefined, reason: string | undefined
}
async function confirmGatewayReachable(port: number): Promise<boolean> {
const token = process.env.OPENCLAW_GATEWAY_TOKEN?.trim() || undefined;
const password = process.env.OPENCLAW_GATEWAY_PASSWORD?.trim() || undefined;
const token = normalizeOptionalString(process.env.OPENCLAW_GATEWAY_TOKEN);
const password = normalizeOptionalString(process.env.OPENCLAW_GATEWAY_PASSWORD);
const probe = await probeGateway({
url: `ws://127.0.0.1:${port}`,
auth: token || password ? { token, password } : undefined,

View File

@@ -21,6 +21,7 @@ import {
import { resolveGatewayService } from "../daemon/service.js";
import { uninstallLegacySystemdUnits } from "../daemon/systemd.js";
import type { RuntimeEnv } from "../runtime.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { note } from "../terminal/note.js";
import { buildGatewayInstallPlan } from "./daemon-install-helpers.js";
import { DEFAULT_GATEWAY_DAEMON_RUNTIME, type GatewayDaemonRuntime } from "./daemon-runtime.js";
@@ -334,7 +335,7 @@ export async function maybeRepairGatewayServiceConfig(
const gatewayTokenForRepair = expectedGatewayToken ?? serviceEmbeddedToken;
const configuredGatewayToken =
typeof cfg.gateway?.auth?.token === "string"
? cfg.gateway.auth.token.trim() || undefined
? normalizeOptionalString(cfg.gateway.auth.token)
: undefined;
let cfgForServiceInstall = cfg;
if (

View File

@@ -9,6 +9,7 @@ import { shouldRequireGatewayTokenForInstall } from "../gateway/auth-install-pol
import { hasAmbiguousGatewayAuthModeConfig } from "../gateway/auth-mode-policy.js";
import { resolveGatewayAuthToken } from "../gateway/auth-token-resolution.js";
import { resolveGatewayAuth } from "../gateway/auth.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { randomToken } from "./onboard-helpers.js";
type GatewayInstallTokenOptions = {
@@ -48,7 +49,7 @@ async function maybePersistAutoGeneratedGatewayInstallToken(params: {
const baseConfigToken =
existingTokenRef || typeof baseConfig.gateway?.auth?.token !== "string"
? undefined
: baseConfig.gateway.auth.token.trim() || undefined;
: normalizeOptionalString(baseConfig.gateway.auth.token);
if (!existingTokenRef && !baseConfigToken) {
await replaceConfigFile({
baseHash: snapshot.hash,

View File

@@ -3,6 +3,7 @@ import type { OpenClawConfig } from "../../config/config.js";
import { replaceConfigFile } from "../../config/config.js";
import { logConfigUpdated } from "../../config/logging.js";
import { type RuntimeEnv, writeRuntimeJson } from "../../runtime.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { applyWizardMetadata } from "../onboard-helpers.js";
import type { OnboardOptions } from "../onboard-types.js";
@@ -15,7 +16,7 @@ export async function runNonInteractiveRemoteSetup(params: {
const { opts, runtime, baseConfig, baseHash } = params;
const mode = "remote" as const;
const remoteUrl = opts.remoteUrl?.trim();
const remoteUrl = normalizeOptionalString(opts.remoteUrl);
if (!remoteUrl) {
runtime.error("Missing --remote-url for remote mode.");
runtime.exit(1);
@@ -29,7 +30,7 @@ export async function runNonInteractiveRemoteSetup(params: {
mode: "remote",
remote: {
url: remoteUrl,
token: opts.remoteToken?.trim() || undefined,
token: normalizeOptionalString(opts.remoteToken),
},
},
};

View File

@@ -1,5 +1,6 @@
import fs from "node:fs/promises";
import path from "node:path";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { resolveLaunchAgentPlistPath } from "./launchd.js";
import { isBunRuntime, isNodeRuntime } from "./runtime-binary.js";
import {
@@ -220,7 +221,7 @@ function auditGatewayToken(
detail: "Run `openclaw gateway install --force` to remove embedded service token.",
level: "recommended",
});
const expectedToken = expectedGatewayToken?.trim();
const expectedToken = normalizeOptionalString(expectedGatewayToken);
if (!expectedToken || serviceToken === expectedToken) {
return;
}
@@ -240,7 +241,7 @@ export function readEmbeddedGatewayToken(command: GatewayServiceCommand): string
if (command.environmentValueSources?.OPENCLAW_GATEWAY_TOKEN === "file") {
return undefined;
}
return command.environment?.OPENCLAW_GATEWAY_TOKEN?.trim() || undefined;
return normalizeOptionalString(command.environment?.OPENCLAW_GATEWAY_TOKEN);
}
function getPathModule(platform: NodeJS.Platform) {
@@ -378,8 +379,8 @@ export function checkTokenDrift(params: {
serviceToken: string | undefined;
configToken: string | undefined;
}): ServiceConfigIssue | null {
const serviceToken = params.serviceToken?.trim() || undefined;
const configToken = params.configToken?.trim() || undefined;
const serviceToken = normalizeOptionalString(params.serviceToken);
const configToken = normalizeOptionalString(params.configToken);
// Tokenless service units are canonical; no drift to report.
if (!serviceToken) {

View File

@@ -5,6 +5,7 @@ import {
resolveLinuxSystemCaBundle,
} from "../bootstrap/node-extra-ca-certs.js";
import { resolveNodeStartupTlsEnvironment } from "../bootstrap/node-startup-env.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { VERSION } from "../version.js";
import {
GATEWAY_SERVICE_KIND,
@@ -296,7 +297,7 @@ export function buildNodeServiceEnvironment(params: {
extraPathDirs,
params.execPath,
);
const gatewayToken = env.OPENCLAW_GATEWAY_TOKEN?.trim() || undefined;
const gatewayToken = normalizeOptionalString(env.OPENCLAW_GATEWAY_TOKEN);
return {
...buildCommonServiceEnvironment(env, sharedEnv),
OPENCLAW_GATEWAY_TOKEN: gatewayToken,