UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

204 lines (203 loc) 8.29 kB
import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js"; import { p as normalizeTrimmedStringList } from "./string-normalization-DsCfAx8q.js"; import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import { t as createSubsystemLogger } from "./subsystem-Dy2tqXOS.js"; import { r as pluginCacheExistsSync } from "./plugin-cache-files-DLPF_Tw2.js"; import { p as isPluginSourceModulePath } from "./sdk-alias-BMTmaiMP.js"; import { h as isBundledSourceOverlayPath } from "./discovery-D_VDsZuY.js"; import { n as resolveExistingPluginModulePath, t as loadChannelPluginModule } from "./module-loader-VIb38139.js"; import { t as listChannelCatalogEntries } from "./channel-catalog-registry-B-pdGKSC.js"; import path from "node:path"; //#region src/secrets/channel-env-var-names.ts /** Ambient process env names that are too common to imply channel configuration. */ const UNSAFE_CHANNEL_ENV_VAR_TRIGGER_NAMES = /* @__PURE__ */ new Set([ "CI", "HOME", "LANG", "LC_ALL", "LC_CTYPE", "LOGNAME", "NODE_ENV", "OLDPWD", "PATH", "PWD", "SHELL", "SSH_AUTH_SOCK", "TEMP", "TERM", "TMP", "TMPDIR", "USER" ]); /** * Returns whether a channel env var name is safe to treat as a credential/config trigger. */ function isSafeChannelEnvVarTriggerName(key) { const normalized = key.trim().toUpperCase(); return /^[A-Z][A-Z0-9_]*$/.test(normalized) && !UNSAFE_CHANNEL_ENV_VAR_TRIGGER_NAMES.has(normalized); } //#endregion //#region src/channels/plugins/package-state-probes.ts /** * Bundled channel package-state probes. * * Resolves lightweight configured/auth state checkers from package metadata and source overlays. */ /** * Metadata keys that can declare a lightweight package-state checker. */ const CHANNEL_PACKAGE_STATE_METADATA_KEYS = ["configuredState", "persistedAuthState"]; const log = createSubsystemLogger("channels"); function hasNonEmptyEnvValue(env, key) { if (!env || !isSafeChannelEnvVarTriggerName(key)) return false; const normalized = key.trim(); const value = env[normalized] ?? env[normalized.toUpperCase()]; return typeof value === "string" && value.trim().length > 0; } function resolveSourceBundledPluginRoot(rootDir) { const pluginRoot = path.resolve(rootDir); const extensionsDir = path.dirname(pluginRoot); if (path.basename(extensionsDir) !== "extensions") return null; const packageRoot = path.dirname(extensionsDir); if (path.basename(packageRoot) === "dist" || path.basename(packageRoot) === "dist-runtime") return null; return { packageRoot, dirName: path.basename(pluginRoot) }; } function isBundledSourceOverlayPluginRoot(rootDir) { const pluginRoot = path.resolve(rootDir); return isBundledSourceOverlayPath({ sourcePath: pluginRoot }) || path.basename(path.dirname(pluginRoot)) === "extensions" && isBundledSourceOverlayPath({ sourcePath: path.dirname(pluginRoot) }); } function listBuiltBundledPackageStateModules(params) { if (isBundledSourceOverlayPluginRoot(params.rootDir)) return []; const sourceRoot = resolveSourceBundledPluginRoot(params.rootDir); if (!sourceRoot) return []; const locations = []; for (const rootDir of [path.join(sourceRoot.packageRoot, "dist", "extensions", sourceRoot.dirName), path.join(sourceRoot.packageRoot, "dist-runtime", "extensions", sourceRoot.dirName)]) { const modulePath = resolveExistingPluginModulePath(rootDir, params.specifier); if (pluginCacheExistsSync(modulePath) && !isPluginSourceModulePath(modulePath)) locations.push({ modulePath, rootDir }); } return locations; } function resolveChannelPackageStateModuleLocation(params) { return { modulePath: resolveExistingPluginModulePath(params.entry.rootDir, params.specifier), rootDir: params.entry.rootDir }; } function listChannelPackageStateModuleLocations(params) { const source = resolveChannelPackageStateModuleLocation(params); return [...listBuiltBundledPackageStateModules({ rootDir: params.entry.rootDir, specifier: params.specifier }).filter((location) => location.modulePath !== source.modulePath), source]; } function resolveChannelPackageStateMetadata(entry, metadataKey) { const metadata = entry.channel[metadataKey]; if (!metadata || typeof metadata !== "object") return null; const specifier = normalizeOptionalString(metadata.specifier) ?? ""; const exportName = normalizeOptionalString(metadata.exportName) ?? ""; const envMetadata = "env" in metadata ? metadata.env : void 0; const allOf = normalizeTrimmedStringList(envMetadata?.allOf); const anyOf = normalizeTrimmedStringList(envMetadata?.anyOf); const env = allOf.length > 0 || anyOf.length > 0 ? { allOf, anyOf } : void 0; if ((!specifier || !exportName) && !env) return null; return { ...specifier ? { specifier } : {}, ...exportName ? { exportName } : {}, ...env ? { env } : {} }; } function listChannelPackageStateCatalog(metadataKey, discovery) { return listChannelCatalogEntries({ origin: "bundled", discovery }).filter((entry) => Boolean(resolveChannelPackageStateMetadata(entry, metadataKey))); } function resolveChannelPackageStateChecker(params) { const metadata = resolveChannelPackageStateMetadata(params.entry, params.metadataKey); if (!metadata) return null; if (metadata.env && (!metadata.specifier || !metadata.exportName)) return ({ env }) => { const allOf = metadata.env?.allOf ?? []; const anyOf = metadata.env?.anyOf ?? []; return allOf.every((key) => hasNonEmptyEnvValue(env, key)) && (anyOf.length === 0 || anyOf.some((key) => hasNonEmptyEnvValue(env, key))); }; let loadError; for (const location of listChannelPackageStateModuleLocations({ entry: params.entry, specifier: metadata.specifier })) try { const checker = loadChannelPluginModule({ modulePath: location.modulePath, rootDir: location.rootDir })[metadata.exportName]; if (typeof checker !== "function") throw new Error(`missing ${params.metadataKey} export ${metadata.exportName}`); return checker; } catch (error) { loadError = error; } if (loadError) { const detail = formatErrorMessage(loadError); if (params.emitWarning !== false) log.warn(`[channels] failed to load ${params.metadataKey} checker for ${params.entry.pluginId}: ${detail}`); params.onLoadError?.(detail); } return null; } function resolvePackageStateChannelId(entry) { return normalizeOptionalString(entry.channel.id); } /** * Lists bundled channel ids that declare the requested package-state metadata. */ function listBundledChannelIdsForPackageState(metadataKey, discovery) { return listChannelPackageStateCatalog(metadataKey, discovery).map((entry) => resolvePackageStateChannelId(entry)).filter((channelId) => Boolean(channelId)).toSorted((left, right) => left.localeCompare(right)); } /** Reports declared bundled channel package-state modules that cannot load. */ function collectBundledChannelPackageStateLoadFailures(discovery) { const failures = []; for (const metadataKey of CHANNEL_PACKAGE_STATE_METADATA_KEYS) for (const entry of listChannelPackageStateCatalog(metadataKey, discovery)) resolveChannelPackageStateChecker({ entry, emitWarning: false, metadataKey, onLoadError: (detail) => failures.push({ detail, metadataKey, pluginId: entry.pluginId }) }); return failures; } /** * Returns whether a bundled channel reports configured/auth package state. */ function hasBundledChannelPackageState(params) { const requestedChannelId = normalizeOptionalString(params.channelId); const entry = listChannelPackageStateCatalog(params.metadataKey, params.discovery).find((candidate) => resolvePackageStateChannelId(candidate) === requestedChannelId); if (!entry) return false; return hasChannelPackageState({ entry, metadataKey: params.metadataKey, cfg: params.cfg, env: params.env }); } /** Evaluates the exact channel package owner already selected and trusted by its caller. */ function hasChannelPackageState(params) { const checker = resolveChannelPackageStateChecker({ entry: params.entry, metadataKey: params.metadataKey }); return checker ? checker({ cfg: params.cfg, env: params.env }) : false; } //#endregion export { isSafeChannelEnvVarTriggerName as a, listBundledChannelIdsForPackageState as i, hasBundledChannelPackageState as n, hasChannelPackageState as r, collectBundledChannelPackageStateLoadFailures as t };