fix(zalo): keep packaged setup wizard loadable (#122902)

* fix(zalo): package setup runtime surface

* fix(tooling): track setup surface artifacts
This commit is contained in:
Peter Steinberger
2026-08-12 18:49:41 -07:00
committed by GitHub
parent 8b7c015fc9
commit 10a1a43f4b
4 changed files with 83 additions and 2 deletions
+2
View File
@@ -211,6 +211,8 @@ const rootEntries = [
const bundledPluginEntries = [ const bundledPluginEntries = [
"index.ts!", "index.ts!",
"setup-entry.ts!", "setup-entry.ts!",
// Setup APIs may lazy-load this top-level package artifact by string specifier.
"setup-surface.ts!",
// Core resolves these public plugin artifacts by basename rather than by a // Core resolves these public plugin artifacts by basename rather than by a
// static import from the plugin entry module. // static import from the plugin entry module.
"*-api.ts!", "*-api.ts!",
+2 -2
View File
@@ -1,7 +1,7 @@
// Zalo API module exposes the plugin public contract. // Zalo API module exposes the plugin public contract.
import { loadBundledEntryExportSync } from "openclaw/plugin-sdk/channel-entry-contract"; import { loadBundledEntryExportSync } from "openclaw/plugin-sdk/channel-entry-contract";
type SetupSurfaceModule = typeof import("./src/setup-surface.js"); type SetupSurfaceModule = typeof import("./setup-surface.js");
function createLazyObjectValue<T extends object>(load: () => T): T { function createLazyObjectValue<T extends object>(load: () => T): T {
return new Proxy({} as T, { return new Proxy({} as T, {
@@ -23,7 +23,7 @@ function createLazyObjectValue<T extends object>(load: () => T): T {
function loadSetupSurfaceModule(): SetupSurfaceModule { function loadSetupSurfaceModule(): SetupSurfaceModule {
return loadBundledEntryExportSync<SetupSurfaceModule>(import.meta.url, { return loadBundledEntryExportSync<SetupSurfaceModule>(import.meta.url, {
specifier: "./src/setup-surface.js", specifier: "./setup-surface.js",
}); });
} }
+2
View File
@@ -0,0 +1,2 @@
// Zalo API module exposes the plugin public contract.
export { zaloSetupAdapter, zaloSetupWizard } from "./src/setup-surface.js";
+77
View File
@@ -1,4 +1,5 @@
// Plugin npm runtime build tests validate plugin runtime package builds. // Plugin npm runtime build tests validate plugin runtime package builds.
import { spawnSync } from "node:child_process";
import { import {
existsSync, existsSync,
mkdirSync, mkdirSync,
@@ -9,12 +10,20 @@ import {
} from "node:fs"; } from "node:fs";
import path from "node:path"; import path from "node:path";
import { afterEach, describe, expect, it } from "vitest"; import { afterEach, describe, expect, it } from "vitest";
import {
resolvePluginNpmCommand,
withAugmentedPluginNpmManifestForPackage,
} from "../scripts/lib/plugin-npm-package-manifest.mts";
import { import {
buildPluginNpmRuntime, buildPluginNpmRuntime,
listMissingPluginNpmRuntimeHostExports, listMissingPluginNpmRuntimeHostExports,
listPublishablePluginPackageDirs, listPublishablePluginPackageDirs,
resolvePluginNpmRuntimeBuildPlan, resolvePluginNpmRuntimeBuildPlan,
} from "../scripts/lib/plugin-npm-runtime-build.mts"; } from "../scripts/lib/plugin-npm-runtime-build.mts";
import {
createPluginModuleLoaderCache,
getCachedPluginSourceModuleLoader,
} from "../src/plugins/plugin-module-loader-cache.js";
import { useAutoCleanupTempDirTracker } from "./helpers/temp-dir.js"; import { useAutoCleanupTempDirTracker } from "./helpers/temp-dir.js";
const repoRoot = path.resolve(import.meta.dirname, ".."); const repoRoot = path.resolve(import.meta.dirname, "..");
@@ -220,6 +229,74 @@ describe("plugin npm runtime build planning", () => {
expect(plan.runtimeBuildOutputs).toContain("./dist/setup-api.js"); expect(plan.runtimeBuildOutputs).toContain("./dist/setup-api.js");
}); });
it("packs the Zalo public setup API with its lazy runtime surface", async () => {
const packageDir = path.join(repoRoot, "extensions", "zalo");
const plan = expectPluginNpmRuntimeBuildPlan(
await buildPluginNpmRuntime({
repoRoot,
packageDir,
logLevel: "silent",
}),
);
const consumerDir = tempDirs.make("openclaw-zalo-packed-setup-");
let packedFiles: string[] = [];
let setupApiPath = "";
withAugmentedPluginNpmManifestForPackage(
{ repoRoot, packageDir, bundleDependencies: false },
() => {
const invocation = resolvePluginNpmCommand([
"pack",
"--json",
"--ignore-scripts",
"--pack-destination",
consumerDir,
]);
const pack = spawnSync(invocation.command, invocation.args, {
cwd: packageDir,
encoding: "utf8",
...(invocation.env ? { env: invocation.env } : {}),
...(invocation.shell !== undefined ? { shell: invocation.shell } : {}),
stdio: ["ignore", "pipe", "pipe"],
...(invocation.windowsVerbatimArguments !== undefined
? { windowsVerbatimArguments: invocation.windowsVerbatimArguments }
: {}),
});
expect(pack.status, pack.stderr).toBe(0);
const [packedPackage] = JSON.parse(pack.stdout) as [
{ filename: string; files: Array<{ path: string }> },
];
packedFiles = packedPackage.files.map((file) => file.path);
const extract = spawnSync(
"tar",
["-xzf", path.join(consumerDir, packedPackage.filename), "-C", consumerDir],
{
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
},
);
expect(extract.status, extract.stderr).toBe(0);
setupApiPath = path.join(consumerDir, "package", "dist", "setup-api.js");
},
);
expect(plan.runtimeBuildOutputs).toContain("./dist/setup-api.js");
const loadSetupApi = getCachedPluginSourceModuleLoader({
cache: createPluginModuleLoaderCache(),
modulePath: setupApiPath,
importerUrl: import.meta.url,
devSourceRoot: repoRoot,
});
const setupApi = loadSetupApi(setupApiPath) as {
zaloSetupWizard: { channel: string };
};
expect(setupApi.zaloSetupWizard.channel).toBe("zalo");
expect(plan.runtimeBuildOutputs).toContain("./dist/setup-surface.js");
expect(plan.runtimeBuildOutputs).not.toContain("./dist/src/setup-surface.js");
expect(packedFiles).toContain("dist/setup-surface.js");
expect(packedFiles).not.toContain("dist/src/setup-surface.js");
});
it("keeps published Codex runtime imports resolvable from the host package", async () => { it("keeps published Codex runtime imports resolvable from the host package", async () => {
const result = await buildPluginNpmRuntime({ const result = await buildPluginNpmRuntime({
repoRoot, repoRoot,