refactor: share bundled loader Jiti config helpers

This commit is contained in:
Peter Steinberger
2026-04-07 14:12:46 +01:00
parent 2e0354e725
commit df993291b6
7 changed files with 155 additions and 61 deletions

View File

@@ -4,9 +4,8 @@ import path from "node:path";
import { createJiti } from "jiti";
import { openBoundaryFileSync } from "../../infra/boundary-file-read.js";
import {
buildPluginLoaderAliasMap,
buildPluginLoaderJitiOptions,
resolvePluginLoaderJitiTryNative,
resolvePluginLoaderJitiConfig,
} from "../../plugins/sdk-alias.js";
const nodeRequire = createRequire(import.meta.url);
@@ -15,14 +14,12 @@ function createModuleLoader() {
const jitiLoaders = new Map<string, ReturnType<typeof createJiti>>();
return (modulePath: string) => {
const tryNative = resolvePluginLoaderJitiTryNative(modulePath, {
const { tryNative, aliasMap, cacheKey } = resolvePluginLoaderJitiConfig({
modulePath,
argv1: process.argv[1],
moduleUrl: import.meta.url,
preferBuiltDist: true,
});
const aliasMap = buildPluginLoaderAliasMap(modulePath, process.argv[1], import.meta.url);
const cacheKey = JSON.stringify({
tryNative,
aliasMap: Object.entries(aliasMap).toSorted(([left], [right]) => left.localeCompare(right)),
});
const cached = jitiLoaders.get(cacheKey);
if (cached) {
return cached;

View File

@@ -8,10 +8,9 @@ import type { ChannelConfigSchema, ChannelPlugin } from "../channels/plugins/typ
import { openBoundaryFileSync } from "../infra/boundary-file-read.js";
import type { PluginRuntime } from "../plugins/runtime/types.js";
import {
buildPluginLoaderAliasMap,
buildPluginLoaderJitiOptions,
resolveLoaderPackageRoot,
resolvePluginLoaderJitiTryNative,
resolvePluginLoaderJitiConfig,
} from "../plugins/sdk-alias.js";
import type { AnyAgentTool, OpenClawPluginApi, PluginCommandContext } from "../plugins/types.js";
@@ -252,14 +251,12 @@ function resolveBundledEntryModulePath(importMetaUrl: string, specifier: string)
}
function getJiti(modulePath: string) {
const tryNative = resolvePluginLoaderJitiTryNative(modulePath, {
const { tryNative, aliasMap, cacheKey } = resolvePluginLoaderJitiConfig({
modulePath,
argv1: process.argv[1],
moduleUrl: import.meta.url,
preferBuiltDist: true,
});
const aliasMap = buildPluginLoaderAliasMap(modulePath, process.argv[1], import.meta.url);
const cacheKey = JSON.stringify({
tryNative,
aliasMap: Object.entries(aliasMap).toSorted(([left], [right]) => left.localeCompare(right)),
});
const cached = jitiLoaders.get(cacheKey);
if (cached) {
return cached;

View File

@@ -6,9 +6,8 @@ import { openBoundaryFileSync } from "../infra/boundary-file-read.js";
import { resolveBundledPluginsDir } from "../plugins/bundled-dir.js";
import { resolveBundledPluginPublicSurfacePath } from "../plugins/public-surface-runtime.js";
import {
buildPluginLoaderAliasMap,
buildPluginLoaderJitiOptions,
resolvePluginLoaderJitiTryNative,
resolvePluginLoaderJitiConfig,
resolveLoaderPackageRoot,
} from "../plugins/sdk-alias.js";
@@ -137,14 +136,12 @@ function resolveFacadeModuleLocation(params: {
}
function getJiti(modulePath: string) {
const tryNative = resolvePluginLoaderJitiTryNative(modulePath, {
const { tryNative, aliasMap, cacheKey } = resolvePluginLoaderJitiConfig({
modulePath,
argv1: process.argv[1],
moduleUrl: import.meta.url,
preferBuiltDist: true,
});
const aliasMap = buildPluginLoaderAliasMap(modulePath, process.argv[1], import.meta.url);
const cacheKey = JSON.stringify({
tryNative,
aliasMap: Object.entries(aliasMap).toSorted(([left], [right]) => left.localeCompare(right)),
});
const cached = jitiLoaders.get(cacheKey);
if (cached) {
return cached;

View File

@@ -12,11 +12,7 @@ import type {
PluginManifest,
PluginManifestChannelConfig,
} from "./manifest.js";
import {
buildPluginLoaderAliasMap,
buildPluginLoaderJitiOptions,
resolvePluginLoaderJitiTryNative,
} from "./sdk-alias.js";
import { buildPluginLoaderJitiOptions, resolvePluginLoaderJitiConfig } from "./sdk-alias.js";
import type { PluginConfigUiHint } from "./types.js";
const PUBLIC_SURFACE_SOURCE_EXTENSIONS = [".ts", ".mts", ".js", ".mjs", ".cts", ".cjs"] as const;
@@ -75,14 +71,12 @@ function resolveConfigSchemaExport(imported: Record<string, unknown>): ChannelCo
}
function getJiti(modulePath: string) {
const tryNative = resolvePluginLoaderJitiTryNative(modulePath, {
const { tryNative, aliasMap, cacheKey } = resolvePluginLoaderJitiConfig({
modulePath,
argv1: process.argv[1],
moduleUrl: import.meta.url,
preferBuiltDist: true,
});
const aliasMap = buildPluginLoaderAliasMap(modulePath, process.argv[1], import.meta.url);
const cacheKey = JSON.stringify({
tryNative,
aliasMap: Object.entries(aliasMap).toSorted(([left], [right]) => left.localeCompare(right)),
});
const cached = jitiLoaders.get(cacheKey);
if (cached) {
return cached;

View File

@@ -8,7 +8,8 @@ import { resolveBundledPluginPublicSurfacePath } from "./public-surface-runtime.
import {
buildPluginLoaderAliasMap,
buildPluginLoaderJitiOptions,
resolvePluginLoaderJitiTryNative,
isBundledPluginExtensionPath,
resolvePluginLoaderJitiConfig,
resolveLoaderPackageRoot,
} from "./sdk-alias.js";
@@ -70,18 +71,16 @@ function resolvePublicSurfaceLocation(params: {
}
function getJiti(modulePath: string) {
const tryNative = resolvePluginLoaderJitiTryNative(modulePath, {
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 aliasMap = buildPluginLoaderAliasMap(modulePath, process.argv[1], import.meta.url);
const cacheKey = JSON.stringify({
tryNative,
aliasMap: Object.entries(aliasMap).toSorted(([left], [right]) => left.localeCompare(right)),
});
const cached = jitiLoaders.get(cacheKey);
if (cached) {
return cached;
@@ -99,18 +98,13 @@ function getSharedBundledPublicSurfaceJiti(
tryNative: boolean,
): ReturnType<typeof createJiti> | null {
const bundledPluginsDir = resolveBundledPluginsDir();
const normalizedModulePath = path.resolve(modulePath);
const sharedRoots = [
bundledPluginsDir ? path.resolve(bundledPluginsDir) : null,
path.join(OPENCLAW_PACKAGE_ROOT, "extensions"),
path.join(OPENCLAW_PACKAGE_ROOT, "dist", "extensions"),
path.join(OPENCLAW_PACKAGE_ROOT, "dist-runtime", "extensions"),
].filter((root): root is string => typeof root === "string");
const isBundledPublicSurface = sharedRoots.some(
(root) =>
normalizedModulePath === root || normalizedModulePath.startsWith(`${root}${path.sep}`),
);
if (!isBundledPublicSurface) {
if (
!isBundledPluginExtensionPath({
modulePath,
openClawPackageRoot: OPENCLAW_PACKAGE_ROOT,
...(bundledPluginsDir ? { bundledPluginsDir } : {}),
})
) {
return null;
}
const cacheKey = tryNative ? "bundled:native" : "bundled:source";

View File

@@ -10,10 +10,13 @@ import {
import { withEnv } from "../test-utils/env.js";
import {
buildPluginLoaderAliasMap,
createPluginLoaderJitiCacheKey,
buildPluginLoaderJitiOptions,
isBundledPluginExtensionPath,
listPluginSdkAliasCandidates,
listPluginSdkExportedSubpaths,
normalizeJitiAliasTargetPath,
resolvePluginLoaderJitiConfig,
resolvePluginLoaderJitiTryNative,
resolveExtensionApiAlias,
resolvePluginRuntimeModulePath,
@@ -732,6 +735,64 @@ describe("plugin sdk alias helpers", () => {
).toBe(true);
});
it("keeps plugin loader Jiti cache keys stable across alias insertion order", () => {
expect(
createPluginLoaderJitiCacheKey({
tryNative: true,
aliasMap: {
zeta: "/repo/zeta.js",
alpha: "/repo/alpha.js",
},
}),
).toBe(
createPluginLoaderJitiCacheKey({
tryNative: true,
aliasMap: {
alpha: "/repo/alpha.js",
zeta: "/repo/zeta.js",
},
}),
);
});
it("returns plugin loader Jiti config with stable cache keys", () => {
const first = resolvePluginLoaderJitiConfig({
modulePath: `/repo/${bundledDistPluginFile("browser", "index.js")}`,
argv1: "/repo/openclaw.mjs",
moduleUrl: "file:///repo/src/plugins/public-surface-loader.ts",
preferBuiltDist: true,
});
const second = resolvePluginLoaderJitiConfig({
modulePath: `/repo/${bundledDistPluginFile("browser", "index.js")}`,
argv1: "/repo/openclaw.mjs",
moduleUrl: "file:///repo/src/plugins/public-surface-loader.ts",
preferBuiltDist: true,
});
expect(second).toEqual(first);
});
it("detects bundled plugin extension paths across source and dist roots", () => {
expect(
isBundledPluginExtensionPath({
modulePath: "/repo/extensions/demo/api.js",
openClawPackageRoot: "/repo",
}),
).toBe(true);
expect(
isBundledPluginExtensionPath({
modulePath: "/repo/dist/extensions/demo/api.js",
openClawPackageRoot: "/repo",
}),
).toBe(true);
expect(
isBundledPluginExtensionPath({
modulePath: "/repo/vendor/demo/api.js",
openClawPackageRoot: "/repo",
}),
).toBe(false);
});
it("normalizes Windows alias targets before handing them to Jiti", () => {
const originalPlatform = process.platform;
Object.defineProperty(process, "platform", {

View File

@@ -441,13 +441,13 @@ export function buildPluginLoaderJitiOptions(aliasMap: Record<string, string>) {
};
}
function isNativeJitiDisabledByRuntime(): boolean {
function supportsNativeJitiRuntime(): boolean {
const versions = process.versions as { bun?: string };
return typeof versions.bun === "string" || process.platform === "win32";
return typeof versions.bun !== "string" && process.platform !== "win32";
}
export function shouldPreferNativeJiti(modulePath: string): boolean {
if (isNativeJitiDisabledByRuntime()) {
if (!supportsNativeJitiRuntime()) {
return false;
}
switch (path.extname(modulePath).toLowerCase()) {
@@ -467,11 +467,65 @@ export function resolvePluginLoaderJitiTryNative(
preferBuiltDist?: boolean;
},
): boolean {
if (isNativeJitiDisabledByRuntime()) {
return false;
}
return (
shouldPreferNativeJiti(modulePath) ||
(options?.preferBuiltDist === true && modulePath.includes(`${path.sep}dist${path.sep}`))
(supportsNativeJitiRuntime() &&
options?.preferBuiltDist === true &&
modulePath.includes(`${path.sep}dist${path.sep}`))
);
}
export function createPluginLoaderJitiCacheKey(params: {
tryNative: boolean;
aliasMap: Record<string, string>;
}): string {
return JSON.stringify({
tryNative: params.tryNative,
aliasMap: Object.entries(params.aliasMap).toSorted(([left], [right]) =>
left.localeCompare(right),
),
});
}
export function resolvePluginLoaderJitiConfig(params: {
modulePath: string;
argv1?: string;
moduleUrl: string;
preferBuiltDist?: boolean;
}): {
tryNative: boolean;
aliasMap: Record<string, string>;
cacheKey: string;
} {
const tryNative = resolvePluginLoaderJitiTryNative(
params.modulePath,
params.preferBuiltDist ? { preferBuiltDist: true } : {},
);
const aliasMap = buildPluginLoaderAliasMap(params.modulePath, params.argv1, params.moduleUrl);
return {
tryNative,
aliasMap,
cacheKey: createPluginLoaderJitiCacheKey({
tryNative,
aliasMap,
}),
};
}
export function isBundledPluginExtensionPath(params: {
modulePath: string;
openClawPackageRoot: string;
bundledPluginsDir?: string;
}): boolean {
const normalizedModulePath = path.resolve(params.modulePath);
const roots = [
params.bundledPluginsDir ? path.resolve(params.bundledPluginsDir) : null,
path.join(params.openClawPackageRoot, "extensions"),
path.join(params.openClawPackageRoot, "dist", "extensions"),
path.join(params.openClawPackageRoot, "dist-runtime", "extensions"),
].filter((root): root is string => typeof root === "string");
return roots.some(
(root) =>
normalizedModulePath === root || normalizedModulePath.startsWith(`${root}${path.sep}`),
);
}