UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

293 lines (292 loc) 12.6 kB
import { o as getPluginCacheRoot, s as getPluginCacheSource } from "./plugin-cache-DGWspMEc.js"; import { c as isRecord } from "./record-coerce-DItp3I4t.js"; import { c as readPluginCacheFile, n as parsePluginCacheJson } from "./plugin-cache-files-DLPF_Tw2.js"; import { i as resolveBundledPluginsDir, t as areBundledPluginsDisabled } from "./bundled-dir-BEfbEeCF.js"; import { a as resolvePluginRootPublicSurfacePath, i as resolveBundledPluginSourcePublicSurfacePath, n as normalizeBundledPluginArtifactSubpath, r as resolveBundledPluginPublicSurfacePath } from "./public-surface-runtime-DBNrrUv_.js"; import { i as loadPluginPublicSurfaceModuleSync, t as getCachedPluginModuleLoader } from "./plugin-module-loader-cache-lf3kAaBw.js"; import { s as resolveLoaderPackageRoot } from "./sdk-alias-BMTmaiMP.js"; import { t as shouldRejectHardlinkedPluginFiles } from "./hardlink-policy-CslDqyMD.js"; import { fileURLToPath } from "node:url"; import path from "node:path"; //#region src/plugin-sdk/facade-resolution-shared.ts /** * Shared resolver for bundled plugin facade module paths and registry fallbacks. */ function readBundledPluginManifestRecordFromDir(params) { const file = readPluginCacheFile({ rootDir: path.join(params.pluginsRoot, params.resolvedDirName), relativePath: "openclaw.plugin.json", rejectHardlinks: false }); if (!file.ok) return null; try { const parsed = parsePluginCacheJson(file, { json5: true }); if (!parsed.ok || !isRecord(parsed.value)) return null; const raw = parsed.value; if (typeof raw.id !== "string" || raw.id.trim().length === 0) return null; return { id: raw.id, origin: "bundled", enabledByDefault: raw.enabledByDefault === true, rootDir: path.join(params.pluginsRoot, params.resolvedDirName), channels: Array.isArray(raw.channels) ? raw.channels.filter((entry) => typeof entry === "string") : [] }; } catch { return null; } } /** Resolve bundled facade metadata without importing activation or registry runtime. */ function resolveBundledMetadataManifestRecord(params) { if (!params.location) return null; if (params.location.modulePath.startsWith(`${params.sourceExtensionsRoot}${path.sep}`)) { const resolvedDirName = path.relative(params.sourceExtensionsRoot, params.location.modulePath).split(path.sep)[0]; if (!resolvedDirName) return null; return readBundledPluginManifestRecordFromDir({ pluginsRoot: params.sourceExtensionsRoot, resolvedDirName }); } const bundledPluginsDir = resolveBundledPluginsDir(params.env ?? process.env); if (!bundledPluginsDir) return null; const normalizedBundledPluginsDir = path.resolve(bundledPluginsDir); if (!params.location.modulePath.startsWith(`${normalizedBundledPluginsDir}${path.sep}`)) return null; const resolvedDirName = path.relative(normalizedBundledPluginsDir, params.location.modulePath).split(path.sep)[0]; if (!resolvedDirName) return null; return readBundledPluginManifestRecordFromDir({ pluginsRoot: normalizedBundledPluginsDir, resolvedDirName }); } /** Builds the cache key for one facade lookup under the current bundled-plugin mode. */ function createFacadeResolutionKey(params) { const disabledKey = areBundledPluginsDisabled(params.env ?? process.env) ? "disabled" : "enabled"; return `${params.dirName}::${params.artifactBasename}::${params.bundledPluginsDir ? path.resolve(params.bundledPluginsDir) : "<default>"}::${disabledKey}`; } /** Chooses the boundary root that should constrain a resolved facade module. */ function resolveFacadeBoundaryRoot(params) { if (!params.bundledPluginsDir) return params.packageRoot; const resolvedBundledPluginsDir = path.resolve(params.bundledPluginsDir); return params.modulePath.startsWith(`${resolvedBundledPluginsDir}${path.sep}`) ? resolvedBundledPluginsDir : params.packageRoot; } /** Resolves a bundled facade from source in dev and built artifacts in dist installs. */ function resolveBundledFacadeModuleLocation(params) { const env = params.env ?? process.env; if (areBundledPluginsDisabled(env)) return null; const preferSource = !params.currentModulePath.includes(`${path.sep}dist${path.sep}`); const packageSourceRoot = path.resolve(params.packageRoot, "extensions"); const publicSurfaceParams = { rootDir: params.packageRoot, env: params.env, ...params.bundledPluginsDir ? { bundledPluginsDir: params.bundledPluginsDir } : {}, dirName: params.dirName, artifactBasename: params.artifactBasename }; const modulePath = preferSource ? resolveBundledPluginSourcePublicSurfacePath({ dirName: params.dirName, artifactBasename: params.artifactBasename, sourceRoot: params.bundledPluginsDir ?? packageSourceRoot }) ?? (params.bundledPluginsDir && !areBundledPluginsDisabled(env) ? resolveBundledPluginSourcePublicSurfacePath({ dirName: params.dirName, artifactBasename: params.artifactBasename, sourceRoot: packageSourceRoot }) : null) ?? resolveBundledPluginPublicSurfacePath(publicSurfaceParams) : resolveBundledPluginPublicSurfacePath(publicSurfaceParams); return modulePath ? { modulePath, boundaryRoot: resolveFacadeBoundaryRoot({ modulePath, bundledPluginsDir: params.bundledPluginsDir, packageRoot: params.packageRoot }) } : null; } /** Resolves a facade path from manifest registry records using id, folder, then channel matches. */ function resolveRegistryPluginModuleLocationFromRecords(params) { const tiers = [ (plugin) => plugin.id === params.dirName, (plugin) => path.basename(plugin.rootDir) === params.dirName, (plugin) => plugin.channels.includes(params.dirName) ]; const artifactBasename = normalizeBundledPluginArtifactSubpath(params.artifactBasename); for (const matchFn of tiers) for (const record of params.registry.filter(matchFn)) { const rootDir = path.resolve(record.rootDir); const modulePath = resolvePluginRootPublicSurfacePath({ pluginRoot: rootDir, artifactBasename }); if (modulePath) return { modulePath, boundaryRoot: rootDir }; } return null; } //#endregion //#region src/plugin-sdk/facade-loader.ts /** Error thrown when a bundled plugin public surface artifact cannot be resolved. */ var MissingPublicSurfaceError = class extends Error { constructor(message, options) { super(message, options); this.name = "MissingPublicSurfaceError"; } }; const CURRENT_MODULE_PATH = fileURLToPath(import.meta.url); const loadedFacadePluginIds = /* @__PURE__ */ new Set(); function getOpenClawPackageRoot() { return resolveLoaderPackageRoot({ modulePath: fileURLToPath(import.meta.url), moduleUrl: import.meta.url }) ?? fileURLToPath(new URL("../..", import.meta.url)); } function resolveFacadeModuleLocation(params) { const bundledPluginsDir = resolveBundledPluginsDir(params.env ?? process.env); const key = `facade:${createFacadeResolutionKey({ ...params, bundledPluginsDir })}`; const artifacts = getPluginCacheRoot(getOpenClawPackageRoot()).artifacts; const cached = artifacts.get(key); if (cached !== void 0) return cached; const location = resolveBundledFacadeModuleLocation({ ...params, currentModulePath: CURRENT_MODULE_PATH, packageRoot: getOpenClawPackageRoot(), bundledPluginsDir }); artifacts.set(key, location); return location; } function getModuleLoader(modulePath) { return getCachedPluginModuleLoader({ modulePath, importerUrl: import.meta.url, preferBuiltDist: true, loaderFilename: import.meta.url }); } /** Create an object proxy that loads the underlying facade only on first use. */ function createLazyFacadeObjectValue(load) { let resolvedValue; const resolve = () => resolvedValue ??= load(); const target = {}; const syncProperty = (property) => { const descriptor = Reflect.getOwnPropertyDescriptor(resolve(), property); if (descriptor) Object.defineProperty(target, property, descriptor); else Reflect.deleteProperty(target, property); return descriptor; }; const syncTarget = () => { const original = resolve(); const descriptors = Object.getOwnPropertyDescriptors(original); for (const property of Reflect.ownKeys(target)) if (!Object.hasOwn(descriptors, property)) Reflect.deleteProperty(target, property); Object.defineProperties(target, descriptors); Reflect.setPrototypeOf(target, Reflect.getPrototypeOf(original)); if (!Reflect.isExtensible(original)) Reflect.preventExtensions(target); }; return new Proxy(target, { defineProperty(_target, property, descriptor) { const defined = Reflect.defineProperty(resolve(), property, descriptor); if (defined) syncProperty(property); return defined; }, deleteProperty(_target, property) { return Reflect.deleteProperty(resolve(), property) && Reflect.deleteProperty(target, property); }, get(_target, property, receiver) { return Reflect.get(resolve(), property, receiver); }, getOwnPropertyDescriptor(_target, property) { return syncProperty(property); }, getPrototypeOf() { return Reflect.getPrototypeOf(resolve()); }, has(_target, property) { const present = Reflect.has(resolve(), property); if (!present) Reflect.deleteProperty(target, property); return present; }, isExtensible() { const extensible = Reflect.isExtensible(resolve()); if (!extensible) syncTarget(); return extensible; }, ownKeys() { syncTarget(); return Reflect.ownKeys(resolve()); }, preventExtensions() { if (!Reflect.preventExtensions(resolve())) return false; syncTarget(); return true; }, set(_target, property, value, receiver) { return Reflect.set(resolve(), property, value, receiver); }, setPrototypeOf(_target, prototype) { return Reflect.setPrototypeOf(resolve(), prototype) && Reflect.setPrototypeOf(target, prototype); } }); } function trackFacadeModule(modulePath, pluginId) { const source = getPluginCacheSource(modulePath); if (source.facadeTracked) return; source.facadeTracked = true; try { loadedFacadePluginIds.add(typeof pluginId === "function" ? pluginId() : pluginId); } catch (error) { delete source.facadeTracked; throw error; } } function isPathAtOrInside(target, root) { const resolvedRoot = path.resolve(root); const resolvedTarget = path.resolve(target); return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(resolvedRoot + path.sep); } function resolveFacadeBoundaryOpenParams(boundaryRoot) { const checked = getPluginCacheRoot(boundaryRoot).publicSurfaceBoundary; if (checked) return checked; if (isPathAtOrInside(boundaryRoot, getOpenClawPackageRoot())) return { boundaryLabel: "OpenClaw package root", rejectHardlinks: false }; const bundledDir = resolveBundledPluginsDir(); if (bundledDir && isPathAtOrInside(boundaryRoot, bundledDir)) return { boundaryLabel: "bundled plugin directory", rejectHardlinks: false }; return { boundaryLabel: "plugin root", rejectHardlinks: shouldRejectHardlinkedPluginFiles({ origin: "global", rootDir: boundaryRoot }) }; } /** Load and cache a facade module after verifying it is inside its declared boundary root. */ function loadFacadeModuleAtLocationSync(params) { const location = params.location; const loaded = loadPluginPublicSurfaceModuleSync({ ...location, ...resolveFacadeBoundaryOpenParams(location.boundaryRoot), surfaceLabel: `bundled plugin public surface ${location.modulePath}`, loadModule: params.loadModule ?? ((modulePath) => getModuleLoader(modulePath)(modulePath)) }); trackFacadeModule(location.modulePath, params.trackedPluginId); return loaded; } /** Resolve and synchronously load a bundled plugin public surface by plugin dir and artifact name. */ function loadBundledPluginPublicSurfaceModuleSyncCore(params) { const location = resolveFacadeModuleLocation(params); if (!location) throw new MissingPublicSurfaceError(`Unable to resolve bundled plugin public surface ${params.dirName}/${params.artifactBasename}`); return loadFacadeModuleAtLocationSync({ location, trackedPluginId: params.trackedPluginId ?? params.dirName }); } /** List plugin ids whose public facades have been loaded in this process. */ function listImportedBundledPluginFacadeIds() { return [...loadedFacadePluginIds].toSorted((left, right) => left.localeCompare(right)); } //#endregion export { loadFacadeModuleAtLocationSync as a, resolveBundledMetadataManifestRecord as c, loadBundledPluginPublicSurfaceModuleSyncCore as i, resolveRegistryPluginModuleLocationFromRecords as l, createLazyFacadeObjectValue as n, createFacadeResolutionKey as o, listImportedBundledPluginFacadeIds as r, resolveBundledFacadeModuleLocation as s, MissingPublicSurfaceError as t };