UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

289 lines (288 loc) 10.8 kB
import { c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js"; import { t as formatDocsLink } from "./links-CsLBrRff.js"; import { t as DEFAULT_ACCOUNT_ID } from "./account-id-Df9e41E6.js"; import "./string-coerce-runtime-CEGJWkQ_.js"; import { a as createSetupInputPresenceValidator } from "./setup-helpers-DO5nSeNy.js"; import { t as createSetupTranslator } from "./i18n-7g_f4oaD.js"; import { J as setSetupChannelEnabled, Q as splitSetupEntries, a as createAllowFromSection, f as createStandardChannelSetupStatus, v as mergeAllowFromEntries } from "./setup-wizard-helpers-Dv-t1nb8.js"; import "./setup-DHfdBmUU.js"; import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-9LM3JYQX.js"; //#region extensions/line/src/account-helpers.ts function hasLineCredentials(account) { return Boolean(account.channelAccessToken?.trim() && account.channelSecret?.trim()); } function parseLineAllowFromId(raw) { const trimmed = raw.trim().replace(/^line:(?:user:)?/i, ""); if (!/^U[a-f0-9]{32}$/i.test(trimmed)) return null; return trimmed; } //#endregion //#region extensions/line/src/setup-core.ts function patchLineAccountConfig(params) { const accountId = normalizeAccountId(params.accountId); const lineConfig = params.cfg.channels?.line ?? {}; const clearFields = params.clearFields ?? []; if (accountId === "default") { const nextLine = { ...lineConfig }; for (const field of clearFields) delete nextLine[field]; return { ...params.cfg, channels: { ...params.cfg.channels, line: { ...nextLine, ...params.enabled ? { enabled: true } : {}, ...params.patch } } }; } const nextAccount = { ...lineConfig.accounts?.[accountId] }; for (const field of clearFields) delete nextAccount[field]; return { ...params.cfg, channels: { ...params.cfg.channels, line: { ...lineConfig, ...params.enabled ? { enabled: true } : {}, accounts: { ...lineConfig.accounts, [accountId]: { ...nextAccount, ...params.enabled ? { enabled: true } : {}, ...params.patch } } } } }; } function isLineConfigured(cfg, accountId) { return hasLineCredentials(resolveLineAccount({ cfg, accountId })); } const lineSetupAdapter = { resolveAccountId: ({ accountId }) => normalizeAccountId(accountId), applyAccountName: ({ cfg, accountId, name }) => patchLineAccountConfig({ cfg, accountId, patch: name?.trim() ? { name: name.trim() } : {} }), validateInput: createSetupInputPresenceValidator({ defaultAccountOnlyEnvError: "LINE_CHANNEL_ACCESS_TOKEN can only be used for the default account.", whenNotUseEnv: [{ someOf: ["channelAccessToken", "tokenFile"], message: "LINE requires channelAccessToken or --token-file (or --use-env)." }, { someOf: ["channelSecret", "secretFile"], message: "LINE requires channelSecret or --secret-file (or --use-env)." }] }), applyAccountConfig: ({ cfg, accountId, input }) => { const typedInput = input; const normalizedAccountId = normalizeAccountId(accountId); if (normalizedAccountId === "default") return patchLineAccountConfig({ cfg, accountId: normalizedAccountId, enabled: true, clearFields: typedInput.useEnv ? [ "channelAccessToken", "channelSecret", "tokenFile", "secretFile" ] : void 0, patch: typedInput.useEnv ? {} : { ...typedInput.tokenFile ? { tokenFile: typedInput.tokenFile } : typedInput.channelAccessToken ? { channelAccessToken: typedInput.channelAccessToken } : {}, ...typedInput.secretFile ? { secretFile: typedInput.secretFile } : typedInput.channelSecret ? { channelSecret: typedInput.channelSecret } : {} } }); return patchLineAccountConfig({ cfg, accountId: normalizedAccountId, enabled: true, patch: { ...typedInput.tokenFile ? { tokenFile: typedInput.tokenFile } : typedInput.channelAccessToken ? { channelAccessToken: typedInput.channelAccessToken } : {}, ...typedInput.secretFile ? { secretFile: typedInput.secretFile } : typedInput.channelSecret ? { channelSecret: typedInput.channelSecret } : {} } }); } }; //#endregion //#region extensions/line/src/setup-surface.ts const t = createSetupTranslator(); const channel = "line"; const LINE_SETUP_HELP_LINES = [ t("wizard.line.helpOpenConsole"), t("wizard.line.helpCopyCredentials"), t("wizard.line.helpEnableWebhook"), t("wizard.line.helpWebhookUrl"), t("wizard.channels.docs", { link: formatDocsLink("/channels/line", "channels/line") }) ]; const LINE_ALLOW_FROM_HELP_LINES = [ t("wizard.line.allowlistIntro"), t("wizard.line.idsCaseSensitive"), t("wizard.line.examples"), "- U1234567890abcdef1234567890abcdef", "- line:user:U1234567890abcdef1234567890abcdef", t("wizard.line.multipleEntries"), t("wizard.channels.docs", { link: formatDocsLink("/channels/line", "channels/line") }) ]; const lineDmPolicy = { label: "LINE", channel, policyKey: "channels.line.dmPolicy", allowFromKey: "channels.line.allowFrom", resolveConfigKeys: (cfg, accountId) => (accountId ?? resolveDefaultLineAccountId(cfg)) !== "default" ? { policyKey: `channels.line.accounts.${accountId ?? resolveDefaultLineAccountId(cfg)}.dmPolicy`, allowFromKey: `channels.line.accounts.${accountId ?? resolveDefaultLineAccountId(cfg)}.allowFrom` } : { policyKey: "channels.line.dmPolicy", allowFromKey: "channels.line.allowFrom" }, getCurrent: (cfg, accountId) => resolveLineAccount({ cfg, accountId: accountId ?? resolveDefaultLineAccountId(cfg) }).config.dmPolicy ?? "pairing", setPolicy: (cfg, policy, accountId) => patchLineAccountConfig({ cfg, accountId: accountId ?? resolveDefaultLineAccountId(cfg), enabled: true, patch: policy === "open" ? { dmPolicy: "open", allowFrom: mergeAllowFromEntries(resolveLineAccount({ cfg, accountId: accountId ?? resolveDefaultLineAccountId(cfg) }).config.allowFrom, ["*"]) } : { dmPolicy: policy }, clearFields: policy === "pairing" || policy === "disabled" ? ["allowFrom"] : void 0 }) }; const lineSetupWizard = { channel, status: createStandardChannelSetupStatus({ channelLabel: "LINE", configuredLabel: t("wizard.channels.statusConfigured"), unconfiguredLabel: t("wizard.channels.statusNeedsTokenSecret"), configuredHint: t("wizard.channels.statusConfigured"), unconfiguredHint: t("wizard.channels.statusNeedsTokenSecret"), configuredScore: 1, unconfiguredScore: 0, includeStatusLine: true, resolveConfigured: ({ cfg, accountId }) => isLineConfigured(cfg, accountId ?? resolveDefaultLineAccountId(cfg)), resolveExtraStatusLines: ({ cfg }) => [`Accounts: ${listLineAccountIds(cfg).length || 0}`] }), introNote: { title: t("wizard.line.messagingApiTitle"), lines: LINE_SETUP_HELP_LINES, shouldShow: ({ cfg, accountId }) => !isLineConfigured(cfg, accountId ?? resolveDefaultLineAccountId(cfg)) }, credentials: [{ inputKey: "token", providerHint: channel, credentialLabel: t("wizard.line.channelAccessToken"), preferredEnvVar: "LINE_CHANNEL_ACCESS_TOKEN", helpTitle: t("wizard.line.messagingApiTitle"), helpLines: LINE_SETUP_HELP_LINES, envPrompt: t("wizard.line.tokenEnvPrompt"), keepPrompt: t("wizard.line.tokenKeepPrompt"), inputPrompt: t("wizard.line.tokenInputPrompt"), allowEnv: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID, inspect: ({ cfg, accountId }) => { const resolved = resolveLineAccount({ cfg, accountId }); return { accountConfigured: Boolean(normalizeOptionalString(resolved.channelAccessToken) && normalizeOptionalString(resolved.channelSecret)), hasConfiguredValue: Boolean(normalizeOptionalString(resolved.config.channelAccessToken) ?? normalizeOptionalString(resolved.config.tokenFile)), resolvedValue: normalizeOptionalString(resolved.channelAccessToken), envValue: accountId === "default" ? normalizeOptionalString(process.env.LINE_CHANNEL_ACCESS_TOKEN) : void 0 }; }, applyUseEnv: ({ cfg, accountId }) => patchLineAccountConfig({ cfg, accountId, enabled: true, clearFields: ["channelAccessToken", "tokenFile"], patch: {} }), applySet: ({ cfg, accountId, resolvedValue }) => patchLineAccountConfig({ cfg, accountId, enabled: true, clearFields: ["tokenFile"], patch: { channelAccessToken: resolvedValue } }) }, { inputKey: "password", providerHint: "line-secret", credentialLabel: t("wizard.line.channelSecret"), preferredEnvVar: "LINE_CHANNEL_SECRET", helpTitle: t("wizard.line.messagingApiTitle"), helpLines: LINE_SETUP_HELP_LINES, envPrompt: t("wizard.line.secretEnvPrompt"), keepPrompt: t("wizard.line.secretKeepPrompt"), inputPrompt: t("wizard.line.secretInputPrompt"), allowEnv: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID, inspect: ({ cfg, accountId }) => { const resolved = resolveLineAccount({ cfg, accountId }); return { accountConfigured: Boolean(normalizeOptionalString(resolved.channelAccessToken) && normalizeOptionalString(resolved.channelSecret)), hasConfiguredValue: Boolean(normalizeOptionalString(resolved.config.channelSecret) ?? normalizeOptionalString(resolved.config.secretFile)), resolvedValue: normalizeOptionalString(resolved.channelSecret), envValue: accountId === "default" ? normalizeOptionalString(process.env.LINE_CHANNEL_SECRET) : void 0 }; }, applyUseEnv: ({ cfg, accountId }) => patchLineAccountConfig({ cfg, accountId, enabled: true, clearFields: ["channelSecret", "secretFile"], patch: {} }), applySet: ({ cfg, accountId, resolvedValue }) => patchLineAccountConfig({ cfg, accountId, enabled: true, clearFields: ["secretFile"], patch: { channelSecret: resolvedValue } }) }], allowFrom: createAllowFromSection({ helpTitle: t("wizard.line.allowlistTitle"), helpLines: LINE_ALLOW_FROM_HELP_LINES, message: t("wizard.line.allowFromPrompt"), placeholder: "U1234567890abcdef1234567890abcdef", invalidWithoutCredentialNote: t("wizard.line.allowFromInvalid"), parseInputs: splitSetupEntries, parseId: parseLineAllowFromId, apply: ({ cfg, accountId, allowFrom }) => patchLineAccountConfig({ cfg, accountId, enabled: true, patch: { dmPolicy: "allowlist", allowFrom } }) }), dmPolicy: lineDmPolicy, completionNote: { title: t("wizard.line.webhookTitle"), lines: [ t("wizard.line.completionEnableWebhook"), t("wizard.line.completionDefaultWebhook"), t("wizard.line.completionWebhookPath"), t("wizard.channels.docs", { link: formatDocsLink("/channels/line", "channels/line") }) ] }, disable: (cfg) => setSetupChannelEnabled(cfg, channel, false) }; //#endregion export { lineSetupAdapter as n, hasLineCredentials as r, lineSetupWizard as t };