Files
openclaw/src/plugin-sdk/facade-runtime.ts
Altay 554bc0a9fd fix(plugins): keep test helpers out of contract barrels (#63311)
Merged via squash.

Prepared head SHA: 769e90c6af
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-04-08 22:59:05 +01:00

339 lines
12 KiB
TypeScript

import fs from "node:fs";
import { createRequire } from "node:module";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { resolveBundledPluginsDir } from "../plugins/bundled-dir.js";
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
import {
normalizeBundledPluginArtifactSubpath,
resolveBundledPluginPublicSurfacePath,
} from "../plugins/public-surface-runtime.js";
import { resolveLoaderPackageRoot } from "../plugins/sdk-alias.js";
import {
loadBundledPluginPublicSurfaceModuleSync as loadBundledPluginPublicSurfaceModuleSyncLight,
loadFacadeModuleAtLocationSync as loadFacadeModuleAtLocationSyncShared,
resetFacadeLoaderStateForTest,
type FacadeModuleLocation,
} from "./facade-loader.js";
export {
createLazyFacadeArrayValue,
createLazyFacadeObjectValue,
listImportedBundledPluginFacadeIds,
} from "./facade-loader.js";
const OPENCLAW_PACKAGE_ROOT =
resolveLoaderPackageRoot({
modulePath: fileURLToPath(import.meta.url),
moduleUrl: import.meta.url,
}) ?? fileURLToPath(new URL("../..", import.meta.url));
const CURRENT_MODULE_PATH = fileURLToPath(import.meta.url);
const PUBLIC_SURFACE_SOURCE_EXTENSIONS = [".ts", ".mts", ".js", ".mjs", ".cts", ".cjs"] as const;
const OPENCLAW_SOURCE_EXTENSIONS_ROOT = path.resolve(OPENCLAW_PACKAGE_ROOT, "extensions");
const cachedFacadeModuleLocationsByKey = new Map<
string,
{
modulePath: string;
boundaryRoot: string;
} | null
>();
function createFacadeResolutionKey(params: { dirName: string; artifactBasename: string }): string {
const bundledPluginsDir = resolveBundledPluginsDir();
return `${params.dirName}::${params.artifactBasename}::${bundledPluginsDir ? path.resolve(bundledPluginsDir) : "<default>"}`;
}
function resolveSourceFirstPublicSurfacePath(params: {
bundledPluginsDir?: string;
dirName: string;
artifactBasename: string;
}): string | null {
const artifactBasename = normalizeBundledPluginArtifactSubpath(params.artifactBasename);
const sourceBaseName = artifactBasename.replace(/\.js$/u, "");
const sourceRoot = params.bundledPluginsDir ?? path.resolve(OPENCLAW_PACKAGE_ROOT, "extensions");
for (const ext of PUBLIC_SURFACE_SOURCE_EXTENSIONS) {
const candidate = path.resolve(sourceRoot, params.dirName, `${sourceBaseName}${ext}`);
if (fs.existsSync(candidate)) {
return candidate;
}
}
return null;
}
function resolveRegistryPluginModuleLocationFromRegistry(params: {
registry: readonly Pick<PluginManifestRecord, "id" | "rootDir" | "channels">[];
dirName: string;
artifactBasename: string;
}): { modulePath: string; boundaryRoot: string } | null {
type RegistryRecord = (typeof params.registry)[number];
const tiers: Array<(plugin: RegistryRecord) => boolean> = [
(plugin) => plugin.id === params.dirName,
(plugin) => path.basename(plugin.rootDir) === params.dirName,
(plugin) => plugin.channels.includes(params.dirName),
];
const artifactBasename = normalizeBundledPluginArtifactSubpath(params.artifactBasename);
const sourceBaseName = artifactBasename.replace(/\.js$/u, "");
for (const matchFn of tiers) {
for (const record of params.registry.filter(matchFn)) {
const rootDir = path.resolve(record.rootDir);
const builtCandidate = path.join(rootDir, artifactBasename);
if (fs.existsSync(builtCandidate)) {
return { modulePath: builtCandidate, boundaryRoot: rootDir };
}
for (const ext of PUBLIC_SURFACE_SOURCE_EXTENSIONS) {
const sourceCandidate = path.join(rootDir, `${sourceBaseName}${ext}`);
if (fs.existsSync(sourceCandidate)) {
return { modulePath: sourceCandidate, boundaryRoot: rootDir };
}
}
}
}
return null;
}
function resolveRegistryPluginModuleLocation(params: {
dirName: string;
artifactBasename: string;
}): { modulePath: string; boundaryRoot: string } | null {
return loadFacadeActivationCheckRuntime().resolveRegistryPluginModuleLocation({
...params,
resolutionKey: createFacadeResolutionKey(params),
});
}
function resolveFacadeModuleLocationUncached(params: {
dirName: string;
artifactBasename: string;
}): { modulePath: string; boundaryRoot: string } | null {
const bundledPluginsDir = resolveBundledPluginsDir();
const preferSource = !CURRENT_MODULE_PATH.includes(`${path.sep}dist${path.sep}`);
if (preferSource) {
const modulePath =
resolveSourceFirstPublicSurfacePath({
...params,
...(bundledPluginsDir ? { bundledPluginsDir } : {}),
}) ??
resolveSourceFirstPublicSurfacePath(params) ??
resolveBundledPluginPublicSurfacePath({
rootDir: OPENCLAW_PACKAGE_ROOT,
...(bundledPluginsDir ? { bundledPluginsDir } : {}),
dirName: params.dirName,
artifactBasename: params.artifactBasename,
});
if (modulePath) {
return {
modulePath,
boundaryRoot:
bundledPluginsDir && modulePath.startsWith(path.resolve(bundledPluginsDir) + path.sep)
? path.resolve(bundledPluginsDir)
: OPENCLAW_PACKAGE_ROOT,
};
}
return resolveRegistryPluginModuleLocation(params);
}
const modulePath = resolveBundledPluginPublicSurfacePath({
rootDir: OPENCLAW_PACKAGE_ROOT,
...(bundledPluginsDir ? { bundledPluginsDir } : {}),
dirName: params.dirName,
artifactBasename: params.artifactBasename,
});
if (modulePath) {
return {
modulePath,
boundaryRoot:
bundledPluginsDir && modulePath.startsWith(path.resolve(bundledPluginsDir) + path.sep)
? path.resolve(bundledPluginsDir)
: OPENCLAW_PACKAGE_ROOT,
};
}
return resolveRegistryPluginModuleLocation(params);
}
function resolveFacadeModuleLocation(params: {
dirName: string;
artifactBasename: string;
}): { modulePath: string; boundaryRoot: string } | null {
const key = createFacadeResolutionKey(params);
if (cachedFacadeModuleLocationsByKey.has(key)) {
return cachedFacadeModuleLocationsByKey.get(key) ?? null;
}
const resolved = resolveFacadeModuleLocationUncached(params);
cachedFacadeModuleLocationsByKey.set(key, resolved);
return resolved;
}
type BundledPluginPublicSurfaceParams = {
dirName: string;
artifactBasename: string;
};
type FacadeActivationCheckRuntimeModule = typeof import("./facade-activation-check.runtime.js");
type JitiLoader = ReturnType<(typeof import("jiti"))["createJiti"]>;
const nodeRequire = createRequire(import.meta.url);
const FACADE_ACTIVATION_CHECK_RUNTIME_CANDIDATES = [
"./facade-activation-check.runtime.js",
"./facade-activation-check.runtime.ts",
] as const;
let facadeActivationCheckRuntimeModule: FacadeActivationCheckRuntimeModule | undefined;
let facadeActivationCheckRuntimeJiti: JitiLoader | undefined;
function getFacadeActivationCheckRuntimeJiti(): JitiLoader {
if (facadeActivationCheckRuntimeJiti) {
return facadeActivationCheckRuntimeJiti;
}
const { createJiti } = nodeRequire("jiti") as typeof import("jiti");
facadeActivationCheckRuntimeJiti = createJiti(import.meta.url, { tryNative: false });
return facadeActivationCheckRuntimeJiti;
}
function loadFacadeActivationCheckRuntime(): FacadeActivationCheckRuntimeModule {
if (facadeActivationCheckRuntimeModule) {
return facadeActivationCheckRuntimeModule;
}
for (const candidate of FACADE_ACTIVATION_CHECK_RUNTIME_CANDIDATES) {
try {
facadeActivationCheckRuntimeModule = nodeRequire(
candidate,
) as FacadeActivationCheckRuntimeModule;
return facadeActivationCheckRuntimeModule;
} catch {
// Try source/runtime candidates in order.
}
}
const jiti = getFacadeActivationCheckRuntimeJiti();
for (const candidate of FACADE_ACTIVATION_CHECK_RUNTIME_CANDIDATES) {
try {
facadeActivationCheckRuntimeModule = jiti(candidate) as FacadeActivationCheckRuntimeModule;
return facadeActivationCheckRuntimeModule;
} catch {
// Try source/runtime candidates in order.
}
}
throw new Error("Unable to load facade activation check runtime");
}
function loadFacadeModuleAtLocationSync<T extends object>(params: {
location: FacadeModuleLocation;
trackedPluginId: string | (() => string);
loadModule?: (modulePath: string) => T;
}): T {
return loadFacadeModuleAtLocationSyncShared(params);
}
function buildFacadeActivationCheckParams(
params: BundledPluginPublicSurfaceParams,
location: FacadeModuleLocation | null = resolveFacadeModuleLocation(params),
) {
return {
...params,
location,
sourceExtensionsRoot: OPENCLAW_SOURCE_EXTENSIONS_ROOT,
resolutionKey: createFacadeResolutionKey(params),
};
}
export function loadBundledPluginPublicSurfaceModuleSync<T extends object>(
params: BundledPluginPublicSurfaceParams,
): T {
const location = resolveFacadeModuleLocation(params);
const trackedPluginId = () =>
loadFacadeActivationCheckRuntime().resolveTrackedFacadePluginId(
buildFacadeActivationCheckParams(params, location),
);
if (!location) {
return loadBundledPluginPublicSurfaceModuleSyncLight<T>({
...params,
trackedPluginId,
});
}
return loadFacadeModuleAtLocationSync<T>({
location,
trackedPluginId,
});
}
export function canLoadActivatedBundledPluginPublicSurface(params: {
dirName: string;
artifactBasename: string;
}): boolean {
return loadFacadeActivationCheckRuntime().resolveBundledPluginPublicSurfaceAccess(
buildFacadeActivationCheckParams(params),
).allowed;
}
export function loadActivatedBundledPluginPublicSurfaceModuleSync<T extends object>(params: {
dirName: string;
artifactBasename: string;
}): T {
loadFacadeActivationCheckRuntime().resolveActivatedBundledPluginPublicSurfaceAccessOrThrow(
buildFacadeActivationCheckParams(params),
);
return loadBundledPluginPublicSurfaceModuleSync<T>(params);
}
export function tryLoadActivatedBundledPluginPublicSurfaceModuleSync<T extends object>(params: {
dirName: string;
artifactBasename: string;
}): T | null {
const access = loadFacadeActivationCheckRuntime().resolveBundledPluginPublicSurfaceAccess(
buildFacadeActivationCheckParams(params),
);
if (!access.allowed) {
return null;
}
return loadBundledPluginPublicSurfaceModuleSync<T>(params);
}
export function resetFacadeRuntimeStateForTest(): void {
resetFacadeLoaderStateForTest();
facadeActivationCheckRuntimeModule?.resetFacadeActivationCheckRuntimeStateForTest();
facadeActivationCheckRuntimeModule = undefined;
facadeActivationCheckRuntimeJiti = undefined;
cachedFacadeModuleLocationsByKey.clear();
}
export const __testing = {
loadFacadeModuleAtLocationSync,
resolveRegistryPluginModuleLocationFromRegistry,
resolveFacadeModuleLocation,
evaluateBundledPluginPublicSurfaceAccess: ((
...args: Parameters<
FacadeActivationCheckRuntimeModule["evaluateBundledPluginPublicSurfaceAccess"]
>
) =>
loadFacadeActivationCheckRuntime().evaluateBundledPluginPublicSurfaceAccess(
...args,
)) as FacadeActivationCheckRuntimeModule["evaluateBundledPluginPublicSurfaceAccess"],
throwForBundledPluginPublicSurfaceAccess: ((
...args: Parameters<
FacadeActivationCheckRuntimeModule["throwForBundledPluginPublicSurfaceAccess"]
>
) =>
loadFacadeActivationCheckRuntime().throwForBundledPluginPublicSurfaceAccess(
...args,
)) as FacadeActivationCheckRuntimeModule["throwForBundledPluginPublicSurfaceAccess"],
resolveActivatedBundledPluginPublicSurfaceAccessOrThrow: ((
params: BundledPluginPublicSurfaceParams,
) =>
loadFacadeActivationCheckRuntime().resolveActivatedBundledPluginPublicSurfaceAccessOrThrow(
buildFacadeActivationCheckParams(params),
)) as (params: BundledPluginPublicSurfaceParams) => {
allowed: boolean;
pluginId?: string;
reason?: string;
},
resolveBundledPluginPublicSurfaceAccess: ((params: BundledPluginPublicSurfaceParams) =>
loadFacadeActivationCheckRuntime().resolveBundledPluginPublicSurfaceAccess(
buildFacadeActivationCheckParams(params),
)) as (params: BundledPluginPublicSurfaceParams) => {
allowed: boolean;
pluginId?: string;
reason?: string;
},
resolveTrackedFacadePluginId: ((params: BundledPluginPublicSurfaceParams) =>
loadFacadeActivationCheckRuntime().resolveTrackedFacadePluginId(
buildFacadeActivationCheckParams(params),
)) as (params: BundledPluginPublicSurfaceParams) => string,
};