UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

163 lines (162 loc) • 8.58 kB
import "./src-BirUqOZp.mjs"; import { t as expectDefined } from "./expect-lbe3Hgrh.mjs"; import { c as isRecord } from "./record-coerce-TIsquoVR.mjs"; import { t as isBlockedObjectKey } from "./prototype-keys-CuYw53fZ.mjs"; import { t as parseConfigPathArrayIndex } from "./path-array-index-CvEcUJa-.mjs"; import { o as toDotPath, r as parseConcreteConfigPath } from "./dot-path-CVD5Jolm.mjs"; import { r as formatDeferredPluginMigration } from "./deferred-plugin-migrations-DiP5orVE.mjs"; import { t as collectPluginConfigContractMatches } from "./config-contract-matches-DIpj3R5X.mjs"; import { isDeepStrictEqual } from "node:util"; //#region src/config/config-path-mutation.ts const MANAGED_CONFIG_UNSET_PATHS = [["plugins", "installs"]]; const WRITE_PRUNED_OBJECT = Symbol("write-pruned-object"); function unsetPathForWriteAt(value, pathSegments, depth) { if (depth >= pathSegments.length) return value; const segment = expectDefined(pathSegments[depth], "path segments entry at depth"); const isLeaf = depth === pathSegments.length - 1; if (Array.isArray(value)) { const index = parseConfigPathArrayIndex(segment); if (index === void 0 || index >= value.length) return value; const child = isLeaf ? WRITE_PRUNED_OBJECT : unsetPathForWriteAt(value[index], pathSegments, depth + 1); if (Object.is(child, value[index])) return value; const next = value.slice(); if (child === WRITE_PRUNED_OBJECT) next.splice(index, 1); else next[index] = child; return next; } if (isBlockedObjectKey(segment) || !isRecord(value) || !Object.hasOwn(value, segment)) return value; const child = isLeaf ? WRITE_PRUNED_OBJECT : unsetPathForWriteAt(value[segment], pathSegments, depth + 1); if (Object.is(child, value[segment])) return value; const next = { ...value }; if (child === WRITE_PRUNED_OBJECT) delete next[segment]; else next[segment] = child; return Object.keys(next).length === 0 ? WRITE_PRUNED_OBJECT : next; } function applyUnsetPathsForWrite(root, unsetPaths) { let next = root; for (const unsetPath of unsetPaths ?? []) { if (!Array.isArray(unsetPath) || unsetPath.length === 0) continue; const unsetResult = unsetPathForWriteAt(next, unsetPath, 0); if (unsetResult === WRITE_PRUNED_OBJECT) next = {}; else if (isRecord(unsetResult)) next = unsetResult; } return next; } function resolveManagedUnsetPathsForWrite(unsetPaths) { const next = []; for (const managedPath of MANAGED_CONFIG_UNSET_PATHS) next.push(Array.from(managedPath)); for (const unsetPath of unsetPaths ?? []) { if (!Array.isArray(unsetPath) || unsetPath.length === 0) continue; if (next.some((existing) => isDeepStrictEqual(existing, unsetPath))) continue; next.push([...unsetPath]); } return next; } //#endregion //#region src/config/deferred-plugin-migration-config.ts const snapshotMigrationFacts = /* @__PURE__ */ new WeakMap(); /** Revalidation consumes the same pending generation that admitted this source snapshot. */ function setDeferredPluginMigrationConfigFacts(source, pending) { if (pending?.length) snapshotMigrationFacts.set(source, structuredClone(pending)); } function getDeferredPluginMigrationConfigFacts(source) { return isRecord(source) ? snapshotMigrationFacts.get(source) : void 0; } function readPathValue(value, segments) { let current = value; for (const segment of segments) { if (isBlockedObjectKey(segment)) return; if (Array.isArray(current)) { const index = parseConfigPathArrayIndex(segment); current = index === void 0 ? void 0 : current[index]; } else current = isRecord(current) && Object.hasOwn(current, segment) ? current[segment] : void 0; } return current; } function uniquePaths(paths) { return [...new Map(paths.map((path) => [JSON.stringify(path), path])).values()]; } /** Empty plugin config has no settings; opaque legacy values still belong to their owner. */ function hasDeferredPluginMigrationConfig(config, pending) { if ((pending.validationExcludedPaths ?? []).some((segments) => readPathValue(config, segments) !== void 0)) return true; const pluginConfigPath = [ "plugins", "entries", pending.pluginId, "config" ]; return [...pending.configPaths ?? [], pluginConfigPath].some((segments) => { const value = readPathValue(config, segments); return value !== void 0 && !(segments.length === pluginConfigPath.length && segments.every((segment, index) => segment === pluginConfigPath[index]) && isRecord(value) && Object.keys(value).length === 0); }); } /** Preserve only current source inputs owned by the deferred plugin or the shared session locator. */ function resolveDeferredPluginMigrationConfigPaths(params) { const compatibilityPaths = (params.compatibilityMigrationPaths ?? []).flatMap((pathPattern) => collectPluginConfigContractMatches({ root: params.config, pathPattern }).map(({ path }) => parseConcreteConfigPath(path))); const configPaths = uniquePaths([ [ "plugins", "entries", params.pluginId, "config" ], ["session", "store"], ...compatibilityPaths ]).filter((path) => readPathValue(params.config, path) !== void 0); return { ...configPaths.length > 0 ? { configPaths } : {}, ...compatibilityPaths.length > 0 ? { validationExcludedPaths: uniquePaths(compatibilityPaths) } : {} }; } function restorePath(source, candidate, segments) { const [segment, ...rest] = segments; if (segment === void 0) return structuredClone(source); if (isBlockedObjectKey(segment)) return candidate; if (Array.isArray(source)) { const index = parseConfigPathArrayIndex(segment); if (index === void 0 || index >= source.length) return candidate; const next = Array.isArray(candidate) ? [...candidate] : []; next[index] = restorePath(source[index], next[index], rest); return next; } if (!isRecord(source) || !Object.hasOwn(source, segment)) return candidate; const next = isRecord(candidate) ? { ...candidate } : {}; next[segment] = restorePath(source[segment], next[segment], rest); return next; } function retainedPluginPaths(pending, nextConfig, unsetPaths) { const entryPath = [ "plugins", "entries", pending.pluginId ]; const entryRemoved = unsetPaths?.some((path) => isDeepStrictEqual(path, entryPath)) && readPathValue(nextConfig, entryPath) === void 0; return (pending.configPaths ?? []).filter((path) => !entryRemoved || !entryPath.every((segment, index) => path[index] === segment)); } /** Explicit edits must not report success after preservation restores their old values. */ function assertDeferredPluginMigrationConfigEditAllowed(params) { for (const pending of params.pending) for (const retainedPath of retainedPluginPaths(pending, params.nextConfig, params.unsetPaths)) if (params.editedPaths.some((editedPath) => retainedPath.every((segment, index) => editedPath[index] === segment) || editedPath.every((segment, index) => retainedPath[index] === segment)) && !isDeepStrictEqual(readPathValue(params.sourceConfig, retainedPath), readPathValue(params.nextConfig, retainedPath))) throw new Error(`Cannot edit retained config at "${toDotPath(retainedPath)}". ${formatDeferredPluginMigration(pending)}`); } /** The current config snapshot owns retained values; migration receipts contain paths only. */ function preserveDeferredPluginMigrationConfig(params) { const { explicitSetPaths, unsetPaths, auditOrigin } = params.writeOptions ?? {}; const nextConfig = applyUnsetPathsForWrite(params.nextConfig, unsetPaths); if (params.pending.length > 0) assertDeferredPluginMigrationConfigEditAllowed({ ...params, nextConfig, unsetPaths, editedPaths: auditOrigin === "config-rpc" ? [[]] : [...explicitSetPaths ?? [], ...unsetPaths ?? []] }); let next = params.nextConfig; for (const pending of params.pending) for (const path of retainedPluginPaths(pending, nextConfig, unsetPaths)) if (path.length > 0) next = restorePath(params.sourceConfig, next, path); return isRecord(next) ? next : params.nextConfig; } /** Retained plugin-owned legacy fields are inert until their migration owner becomes available. */ function omitDeferredPluginMigrationConfig(raw, pending) { return isRecord(raw) ? applyUnsetPathsForWrite(raw, pending?.flatMap((entry) => entry.validationExcludedPaths ?? [])) : raw; } //#endregion export { preserveDeferredPluginMigrationConfig as a, applyUnsetPathsForWrite as c, omitDeferredPluginMigrationConfig as i, resolveManagedUnsetPathsForWrite as l, getDeferredPluginMigrationConfigFacts as n, resolveDeferredPluginMigrationConfigPaths as o, hasDeferredPluginMigrationConfig as r, setDeferredPluginMigrationConfigFacts as s, assertDeferredPluginMigrationConfigEditAllowed as t };