import fs from "node:fs"; import { createRequire } from "node:module"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { createJiti } from "jiti"; import { openBoundaryFileSync } from "../infra/boundary-file-read.js"; import { resolveBundledPluginsDir } from "./bundled-dir.js"; import { resolveBundledPluginPublicSurfacePath } from "./public-surface-runtime.js"; import { buildPluginLoaderAliasMap, buildPluginLoaderJitiOptions, isBundledPluginExtensionPath, resolvePluginLoaderJitiConfig, resolveLoaderPackageRoot, } from "./sdk-alias.js"; const OPENCLAW_PACKAGE_ROOT = resolveLoaderPackageRoot({ modulePath: fileURLToPath(import.meta.url), moduleUrl: import.meta.url, }) ?? fileURLToPath(new URL("../..", import.meta.url)); const loadedPublicSurfaceModules = new Map(); const sourceArtifactRequire = createRequire(import.meta.url); const publicSurfaceLocations = new Map< string, { modulePath: string; boundaryRoot: string; } | null >(); const jitiLoaders = new Map>(); const sharedBundledPublicSurfaceJitiLoaders = new Map>(); function isSourceArtifactPath(modulePath: string): boolean { switch (path.extname(modulePath).toLowerCase()) { case ".ts": case ".tsx": case ".mts": case ".cts": case ".mtsx": case ".ctsx": return true; default: return false; } } function canUseSourceArtifactRequire(params: { modulePath: string; tryNative: boolean }): boolean { return ( !params.tryNative && isSourceArtifactPath(params.modulePath) && typeof sourceArtifactRequire.extensions?.[".ts"] === "function" ); } function createResolutionKey(params: { dirName: string; artifactBasename: string }): string { const bundledPluginsDir = resolveBundledPluginsDir(); return `${params.dirName}::${params.artifactBasename}::${bundledPluginsDir ? path.resolve(bundledPluginsDir) : ""}`; } function resolvePublicSurfaceLocationUncached(params: { dirName: string; artifactBasename: string; }): { modulePath: string; boundaryRoot: string } | null { const bundledPluginsDir = resolveBundledPluginsDir(); const modulePath = resolveBundledPluginPublicSurfacePath({ rootDir: OPENCLAW_PACKAGE_ROOT, ...(bundledPluginsDir ? { bundledPluginsDir } : {}), dirName: params.dirName, artifactBasename: params.artifactBasename, }); if (!modulePath) { return null; } return { modulePath, boundaryRoot: bundledPluginsDir && modulePath.startsWith(path.resolve(bundledPluginsDir) + path.sep) ? path.resolve(bundledPluginsDir) : OPENCLAW_PACKAGE_ROOT, }; } function resolvePublicSurfaceLocation(params: { dirName: string; artifactBasename: string; }): { modulePath: string; boundaryRoot: string } | null { const key = createResolutionKey(params); if (publicSurfaceLocations.has(key)) { return publicSurfaceLocations.get(key) ?? null; } const resolved = resolvePublicSurfaceLocationUncached(params); publicSurfaceLocations.set(key, resolved); return resolved; } function getJiti(modulePath: string) { const { tryNative, aliasMap, cacheKey } = resolvePluginLoaderJitiConfig({ modulePath, argv1: process.argv[1], moduleUrl: import.meta.url, preferBuiltDist: true, }); const sharedLoader = getSharedBundledPublicSurfaceJiti(modulePath, tryNative); if (sharedLoader) { return sharedLoader; } const cached = jitiLoaders.get(cacheKey); if (cached) { return cached; } const loader = createJiti(import.meta.url, { ...buildPluginLoaderJitiOptions(aliasMap), tryNative, }); jitiLoaders.set(cacheKey, loader); return loader; } function loadPublicSurfaceModule(modulePath: string): unknown { const { tryNative } = resolvePluginLoaderJitiConfig({ modulePath, argv1: process.argv[1], moduleUrl: import.meta.url, preferBuiltDist: true, }); if (canUseSourceArtifactRequire({ modulePath, tryNative })) { return sourceArtifactRequire(modulePath); } return getJiti(modulePath)(modulePath); } function getSharedBundledPublicSurfaceJiti( modulePath: string, tryNative: boolean, ): ReturnType | null { const bundledPluginsDir = resolveBundledPluginsDir(); if ( !isBundledPluginExtensionPath({ modulePath, openClawPackageRoot: OPENCLAW_PACKAGE_ROOT, ...(bundledPluginsDir ? { bundledPluginsDir } : {}), }) ) { return null; } const cacheKey = tryNative ? "bundled:native" : "bundled:source"; const cached = sharedBundledPublicSurfaceJitiLoaders.get(cacheKey); if (cached) { return cached; } const aliasMap = buildPluginLoaderAliasMap(modulePath, process.argv[1], import.meta.url); const loader = createJiti(import.meta.url, { ...buildPluginLoaderJitiOptions(aliasMap), tryNative, }); sharedBundledPublicSurfaceJitiLoaders.set(cacheKey, loader); return loader; } export function loadBundledPluginPublicArtifactModuleSync(params: { dirName: string; artifactBasename: string; }): T { const location = resolvePublicSurfaceLocation(params); if (!location) { throw new Error( `Unable to resolve bundled plugin public surface ${params.dirName}/${params.artifactBasename}`, ); } const cached = loadedPublicSurfaceModules.get(location.modulePath); if (cached) { return cached as T; } const opened = openBoundaryFileSync({ absolutePath: location.modulePath, rootPath: location.boundaryRoot, boundaryLabel: location.boundaryRoot === OPENCLAW_PACKAGE_ROOT ? "OpenClaw package root" : "bundled plugin directory", rejectHardlinks: false, }); if (!opened.ok) { throw new Error( `Unable to open bundled plugin public surface ${params.dirName}/${params.artifactBasename}`, { cause: opened.error }, ); } fs.closeSync(opened.fd); const sentinel = {} as T; loadedPublicSurfaceModules.set(location.modulePath, sentinel); try { const loaded = loadPublicSurfaceModule(location.modulePath) as T; Object.assign(sentinel, loaded); return sentinel; } catch (error) { loadedPublicSurfaceModules.delete(location.modulePath); throw error; } } export function resolveBundledPluginPublicArtifactPath(params: { dirName: string; artifactBasename: string; }): string | null { return resolvePublicSurfaceLocation(params)?.modulePath ?? null; } export function resetBundledPluginPublicArtifactLoaderForTest(): void { loadedPublicSurfaceModules.clear(); publicSurfaceLocations.clear(); jitiLoaders.clear(); sharedBundledPublicSurfaceJitiLoaders.clear(); }