
























@@ -1,5 +1,6 @@
11import fs from "node:fs";
22import path from "node:path";
3+import { fileURLToPath, pathToFileURL } from "node:url";
34import { afterEach, describe, expect, it, vi } from "vitest";
45import {
56clearBundledRuntimeDependencyNodePaths,
@@ -8,6 +9,7 @@ import {
89import { shouldExpectNativeJitiForJavaScriptTestRuntime } from "../test-utils/jiti-runtime.js";
910import {
1011listImportedBundledPluginFacadeIds,
12+loadBundledPluginPublicSurfaceModule,
1113loadBundledPluginPublicSurfaceModuleSync,
1214resetFacadeLoaderStateForTest,
1315setFacadeLoaderJitiFactoryForTest,
@@ -24,6 +26,7 @@ const originalBundledPluginsDir = process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
2426const originalDisableBundledPlugins = process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS;
2527const originalPluginStageDir = process.env.OPENCLAW_PLUGIN_STAGE_DIR;
2628const FACADE_LOADER_GLOBAL = "__openclawTestLoadBundledPluginPublicSurfaceModuleSync";
29+const STAGED_RUNTIME_DEP_NAME = "openclaw-facade-loader-runtime-dep";
2730type FacadeLoaderJitiFactory = NonNullable<Parameters<typeof setFacadeLoaderJitiFactoryForTest>[0]>;
28312932function forceNodeRuntimeVersionsForTest(): () => void {
@@ -82,74 +85,84 @@ function createCircularPluginDir(prefix: string): string {
8285return rootDir;
8386}
848785-function createPackagedBundledPluginDirWithStagedRuntimeDep(prefix: string): {
88+function writeJsonFile(filePath: string, value: unknown): void {
89+fs.mkdirSync(path.dirname(filePath), { recursive: true });
90+fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
91+}
92+93+function createPackagedBundledPluginDirWithStagedRuntimeDep(params: {
94+marker: string;
95+prefix: string;
96+}): {
8697bundledPluginsDir: string;
98+env: NodeJS.ProcessEnv;
99+installRoot: string;
100+modulePath: string;
87101packageRoot: string;
88102pluginRoot: string;
89103stageRoot: string;
90104} {
91-const packageRoot = createTempDirSync(prefix);
105+const packageRoot = createTempDirSync(params.prefix);
92106const pluginRoot = path.join(packageRoot, "dist", "extensions", "demo");
93107const stageRoot = path.join(packageRoot, "stage");
108+const env = {
109+ ...process.env,
110+OPENCLAW_BUNDLED_PLUGINS_DIR: path.join(packageRoot, "dist", "extensions"),
111+OPENCLAW_PLUGIN_STAGE_DIR: stageRoot,
112+};
94113fs.mkdirSync(pluginRoot, { recursive: true });
114+115+writeJsonFile(path.join(packageRoot, "package.json"), {
116+name: "openclaw",
117+version: "0.0.0",
118+type: "module",
119+});
120+writeJsonFile(path.join(pluginRoot, "package.json"), {
121+name: "@openclaw/plugin-demo",
122+version: "0.0.0",
123+type: "module",
124+dependencies: {
125+[STAGED_RUNTIME_DEP_NAME]: "1.0.0",
126+},
127+});
128+const modulePath = path.join(pluginRoot, "api.js");
95129fs.writeFileSync(
96-path.join(packageRoot, "package.json"),
97-JSON.stringify({ name: "openclaw", version: "0.0.0", type: "module" }, null, 2),
98-"utf8",
99-);
100-fs.writeFileSync(
101-path.join(pluginRoot, "package.json"),
102-JSON.stringify(
103-{
104-name: "@openclaw/plugin-demo",
105-version: "0.0.0",
106-type: "module",
107-dependencies: {
108-"facade-runtime-dep": "1.0.0",
109-},
110-},
111-null,
112-2,
113-),
114-"utf8",
115-);
116-fs.writeFileSync(
117-path.join(pluginRoot, "api.js"),
130+modulePath,
118131[
119-'import { marker as depMarker } from "facade-runtime-dep";',
132+`import { marker as depMarker } from ${JSON.stringify(STAGED_RUNTIME_DEP_NAME)};`,
120133"export const marker = `facade:${depMarker}`;",
134+"export const moduleUrl = import.meta.url;",
121135"",
122136].join("\n"),
123137"utf8",
124138);
125139126140const installRoot = resolveBundledRuntimeDependencyInstallRoot(pluginRoot, {
127-env: {
128- ...process.env,
129-OPENCLAW_PLUGIN_STAGE_DIR: stageRoot,
130-},
141+ env,
142+});
143+const depRoot = path.join(installRoot, "node_modules", STAGED_RUNTIME_DEP_NAME);
144+writeJsonFile(path.join(depRoot, "package.json"), {
145+name: STAGED_RUNTIME_DEP_NAME,
146+version: "1.0.0",
147+type: "module",
148+exports: "./index.js",
131149});
132-const depRoot = path.join(installRoot, "node_modules", "facade-runtime-dep");
133-fs.mkdirSync(depRoot, { recursive: true });
134150fs.writeFileSync(
135-path.join(depRoot, "package.json"),
136-JSON.stringify(
137-{ name: "facade-runtime-dep", version: "1.0.0", type: "module", exports: "./index.js" },
138-null,
139-2,
140-),
151+path.join(depRoot, "index.js"),
152+`export const marker = ${JSON.stringify(params.marker)};\n`,
141153"utf8",
142154);
143-fs.writeFileSync(path.join(depRoot, "index.js"), 'export const marker = "staged";\n', "utf8");
144155145156return {
146157bundledPluginsDir: path.join(packageRoot, "dist", "extensions"),
158+ env,
159+ installRoot,
160+ modulePath,
147161 packageRoot,
148162 pluginRoot,
149163 stageRoot,
150164};
151165}
152-153166afterEach(() => {
154167vi.restoreAllMocks();
155168resetFacadeLoaderStateForTest();
@@ -278,20 +291,52 @@ describe("plugin-sdk facade loader", () => {
278291}
279292});
280293281-it("loads built bundled public surfaces through staged runtime deps", () => {
282-const fixture = createPackagedBundledPluginDirWithStagedRuntimeDep(
283-"openclaw-facade-loader-runtime-deps-",
284-);
294+it("loads built bundled sync public surfaces through staged runtime deps", async () => {
295+const fixture = createPackagedBundledPluginDirWithStagedRuntimeDep({
296+marker: "staged",
297+prefix: "openclaw-facade-loader-runtime-deps-",
298+});
285299process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = fixture.bundledPluginsDir;
286300process.env.OPENCLAW_PLUGIN_STAGE_DIR = fixture.stageRoot;
287301288-const loaded = loadBundledPluginPublicSurfaceModuleSync<{ marker: string }>({
302+await expect(import(pathToFileURL(fixture.modulePath).href)).rejects.toMatchObject({
303+code: "ERR_MODULE_NOT_FOUND",
304+});
305+306+const loaded = loadBundledPluginPublicSurfaceModuleSync<{
307+marker: string;
308+moduleUrl: string;
309+}>({
289310dirName: "demo",
290311artifactBasename: "api.js",
291312});
292313293314expect(loaded.marker).toBe("facade:staged");
294315expect(fs.existsSync(path.join(fixture.pluginRoot, "node_modules"))).toBe(false);
316+expect(fs.realpathSync(fileURLToPath(loaded.moduleUrl))).toBe(
317+fs.realpathSync(path.join(fixture.installRoot, "dist", "extensions", "demo", "api.js")),
318+);
319+});
320+321+it("loads built bundled async public surfaces through staged runtime deps", async () => {
322+const fixture = createPackagedBundledPluginDirWithStagedRuntimeDep({
323+marker: "async-staged",
324+prefix: "openclaw-facade-loader-built-async-",
325+});
326+327+const loaded = await loadBundledPluginPublicSurfaceModule<{
328+marker: string;
329+moduleUrl: string;
330+}>({
331+dirName: "demo",
332+artifactBasename: "api.js",
333+env: fixture.env,
334+});
335+336+expect(loaded.marker).toBe("facade:async-staged");
337+expect(fs.realpathSync(fileURLToPath(loaded.moduleUrl))).toBe(
338+fs.realpathSync(path.join(fixture.installRoot, "dist", "extensions", "demo", "api.js")),
339+);
295340});
296341297342it("breaks circular facade re-entry during module evaluation", () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。