test(plugins): alias gateway workspace packages in plugin loader

This commit is contained in:
Peter Steinberger
2026-05-29 03:53:50 +01:00
parent 45892a6595
commit ee3efc0152
3 changed files with 205 additions and 20 deletions

View File

@@ -154,6 +154,21 @@ function createExtensionApiAliasFixture(params?: {
return { root, srcFile, distFile };
}
function writeWorkspacePackageEntry(params: {
root: string;
packageDir: string;
srcFile: string;
distFile: string;
}) {
const srcFile = path.join(params.root, "packages", params.packageDir, "src", params.srcFile);
const distFile = path.join(params.root, "packages", params.packageDir, "dist", params.distFile);
mkdirSafeDir(path.dirname(srcFile));
mkdirSafeDir(path.dirname(distFile));
fs.writeFileSync(srcFile, "export {};\n", "utf-8");
fs.writeFileSync(distFile, "export {};\n", "utf-8");
return { srcFile, distFile };
}
function createPluginRuntimeAliasFixture(params?: { srcBody?: string; distBody?: string }) {
const root = makeTempDir();
const srcFile = path.join(root, "src", "plugins", "runtime", "index.ts");
@@ -1331,6 +1346,90 @@ describe("plugin sdk alias helpers", () => {
});
});
it("aliases gateway workspace packages to source when dist artifacts are missing", () => {
const fixture = createPluginSdkAliasFixture();
const gatewayClient = writeWorkspacePackageEntry({
root: fixture.root,
packageDir: "gateway-client",
srcFile: "index.ts",
distFile: "index.mjs",
});
const gatewayClientTimeouts = writeWorkspacePackageEntry({
root: fixture.root,
packageDir: "gateway-client",
srcFile: "timeouts.ts",
distFile: "timeouts.mjs",
});
const gatewayProtocol = writeWorkspacePackageEntry({
root: fixture.root,
packageDir: "gateway-protocol",
srcFile: "index.ts",
distFile: "index.mjs",
});
const gatewayProtocolSchema = writeWorkspacePackageEntry({
root: fixture.root,
packageDir: "gateway-protocol",
srcFile: "schema.ts",
distFile: "schema.mjs",
});
fs.rmSync(gatewayClient.distFile);
fs.rmSync(gatewayClientTimeouts.distFile);
fs.rmSync(gatewayProtocol.distFile);
fs.rmSync(gatewayProtocolSchema.distFile);
const sourcePluginEntry = writePluginEntry(
fixture.root,
bundledPluginFile("demo", "src/index.ts"),
);
const aliases = withEnv({ NODE_ENV: undefined }, () =>
buildPluginLoaderAliasMap(sourcePluginEntry, undefined, undefined, "dist"),
);
expect(fs.realpathSync(aliases["@openclaw/gateway-client"] ?? "")).toBe(
fs.realpathSync(gatewayClient.srcFile),
);
expect(fs.realpathSync(aliases["@openclaw/gateway-client/timeouts"] ?? "")).toBe(
fs.realpathSync(gatewayClientTimeouts.srcFile),
);
expect(fs.realpathSync(aliases["@openclaw/gateway-protocol"] ?? "")).toBe(
fs.realpathSync(gatewayProtocol.srcFile),
);
expect(fs.realpathSync(aliases["@openclaw/gateway-protocol/schema"] ?? "")).toBe(
fs.realpathSync(gatewayProtocolSchema.srcFile),
);
});
it("aliases gateway workspace package subpaths to dist when available", () => {
const fixture = createPluginSdkAliasFixture();
const gatewayClient = writeWorkspacePackageEntry({
root: fixture.root,
packageDir: "gateway-client",
srcFile: "readiness.ts",
distFile: "readiness.mjs",
});
const gatewayProtocol = writeWorkspacePackageEntry({
root: fixture.root,
packageDir: "gateway-protocol",
srcFile: "connect-error-details.ts",
distFile: "connect-error-details.mjs",
});
const sourcePluginEntry = writePluginEntry(
fixture.root,
bundledPluginFile("demo", "src/index.ts"),
);
const aliases = withEnv({ NODE_ENV: undefined }, () =>
buildPluginLoaderAliasMap(sourcePluginEntry, undefined, undefined, "dist"),
);
expect(fs.realpathSync(aliases["@openclaw/gateway-client/readiness"] ?? "")).toBe(
fs.realpathSync(gatewayClient.distFile),
);
expect(fs.realpathSync(aliases["@openclaw/gateway-protocol/connect-error-details"] ?? "")).toBe(
fs.realpathSync(gatewayProtocol.distFile),
);
});
it("aliases bundled plugin package public surfaces for source plugin transforms", () => {
const { fixture, sourceApiPath, sourceRuntimeApiPath } =
createBundledPluginPackagePublicSurfaceAliasFixture();
@@ -2146,9 +2245,7 @@ describe("buildPluginLoaderJitiOptions", () => {
),
);
expect(guardedFsCache).toContain(
path.join("jiti", "openclaw", "1.2.3-beta.4") + path.sep,
);
expect(guardedFsCache).toContain(path.join("jiti", "openclaw", "1.2.3-beta.4") + path.sep);
expect(guardedFsCache.startsWith(path.join(root, "jiti") + path.sep)).toBe(false);
expect(respectedFsCache).toContain(
path.join(root, "jiti", "openclaw", "1.2.3-beta.4") + path.sep,

View File

@@ -42,11 +42,7 @@ function sanitizeJitiCachePathSegment(value: string): string {
function resolveJitiFsCacheTmpDir(): string {
let tmpDir = os.tmpdir();
if (
process.env.TMPDIR &&
tmpDir === process.cwd() &&
!process.env.JITI_RESPECT_TMPDIR_ENV
) {
if (process.env.TMPDIR && tmpDir === process.cwd() && !process.env.JITI_RESPECT_TMPDIR_ENV) {
const originalTmpDir = process.env.TMPDIR;
delete process.env.TMPDIR;
try {
@@ -497,6 +493,71 @@ const PLUGIN_SDK_SOURCE_CANDIDATE_EXTENSIONS = [
const BUNDLED_PLUGIN_PUBLIC_SURFACE_SOURCE_PATTERN = /^(?:api|runtime-api|test-api|.+-api)$/u;
const JS_STATIC_RELATIVE_DEPENDENCY_PATTERN =
/(?:\bfrom\s*["']|\bimport\s*\(\s*["']|\brequire\s*\(\s*["'])(\.{1,2}\/[^"']+)["']/g;
const WORKSPACE_PACKAGE_ALIAS_ENTRIES = [
{
packageName: "@openclaw/gateway-client",
packageDir: "gateway-client",
subpath: "",
srcFile: "index.ts",
distFile: "index.mjs",
},
{
packageName: "@openclaw/gateway-client",
packageDir: "gateway-client",
subpath: "readiness",
srcFile: "readiness.ts",
distFile: "readiness.mjs",
},
{
packageName: "@openclaw/gateway-client",
packageDir: "gateway-client",
subpath: "timeouts",
srcFile: "timeouts.ts",
distFile: "timeouts.mjs",
},
{
packageName: "@openclaw/gateway-protocol",
packageDir: "gateway-protocol",
subpath: "",
srcFile: "index.ts",
distFile: "index.mjs",
},
{
packageName: "@openclaw/gateway-protocol",
packageDir: "gateway-protocol",
subpath: "client-info",
srcFile: "client-info.ts",
distFile: "client-info.mjs",
},
{
packageName: "@openclaw/gateway-protocol",
packageDir: "gateway-protocol",
subpath: "connect-error-details",
srcFile: "connect-error-details.ts",
distFile: "connect-error-details.mjs",
},
{
packageName: "@openclaw/gateway-protocol",
packageDir: "gateway-protocol",
subpath: "schema",
srcFile: "schema.ts",
distFile: "schema.mjs",
},
{
packageName: "@openclaw/gateway-protocol",
packageDir: "gateway-protocol",
subpath: "startup-unavailable",
srcFile: "startup-unavailable.ts",
distFile: "startup-unavailable.mjs",
},
{
packageName: "@openclaw/gateway-protocol",
packageDir: "gateway-protocol",
subpath: "version",
srcFile: "version.ts",
distFile: "version.mjs",
},
] as const;
function isUsableDistPluginSdkArtifact(candidate: string): boolean {
if (!fs.existsSync(candidate)) {
@@ -683,6 +744,39 @@ function resolveBundledPluginPackagePublicSurfaceAliasMap(params: {
return aliasMap;
}
function resolveWorkspacePackageAliasMap(params: {
modulePath: string;
argv1?: string;
moduleUrl?: string;
pluginSdkResolution: PluginSdkResolutionPreference;
}): Record<string, string> {
const packageRoot = resolveLoaderPluginSdkPackageRoot(params);
if (!packageRoot) {
return {};
}
const orderedKinds = resolvePluginSdkAliasCandidateOrder({
modulePath: params.modulePath,
isProduction: process.env.NODE_ENV === "production",
pluginSdkResolution: params.pluginSdkResolution,
});
const aliasMap: Record<string, string> = {};
for (const entry of WORKSPACE_PACKAGE_ALIAS_ENTRIES) {
const alias = entry.subpath ? `${entry.packageName}/${entry.subpath}` : entry.packageName;
for (const kind of orderedKinds) {
const candidate =
kind === "dist"
? path.join(packageRoot, "packages", entry.packageDir, "dist", entry.distFile)
: path.join(packageRoot, "packages", entry.packageDir, "src", entry.srcFile);
if (!fs.existsSync(candidate)) {
continue;
}
aliasMap[alias] = normalizeJitiAliasTargetPath(candidate);
break;
}
}
return aliasMap;
}
function shouldIncludePrivateLocalOnlyPluginSdkSubpaths() {
return process.env.OPENCLAW_ENABLE_PRIVATE_QA_CLI === "1";
}
@@ -1162,6 +1256,12 @@ export function buildPluginLoaderAliasMap(
moduleUrl,
pluginSdkResolution,
}),
...resolveWorkspacePackageAliasMap({
modulePath,
argv1,
moduleUrl,
pluginSdkResolution,
}),
...(pluginSdkAlias
? Object.fromEntries(
PLUGIN_SDK_PACKAGE_NAMES.map((packageName) => [

View File

@@ -173,18 +173,6 @@ export const sharedVitestConfig = {
find: "@openclaw/whatsapp/api.js",
replacement: path.join(repoRoot, "extensions", "whatsapp", "api.ts"),
},
{
find: "@openclaw/gateway-client/readiness",
replacement: path.join(repoRoot, "packages", "gateway-client", "src", "readiness.ts"),
},
{
find: "@openclaw/gateway-client/timeouts",
replacement: path.join(repoRoot, "packages", "gateway-client", "src", "timeouts.ts"),
},
{
find: "@openclaw/gateway-client",
replacement: path.join(repoRoot, "packages", "gateway-client", "src", "index.ts"),
},
{
find: "@openclaw/gateway-protocol/client-info",
replacement: path.join(repoRoot, "packages", "gateway-protocol", "src", "client-info.ts"),