mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-04 19:00:21 +00:00
refactor: tighten split-runtime live-state guardrails
This commit is contained in:
115
src/plugins/runtime-plugin-boundary.whatsapp.test.ts
Normal file
115
src/plugins/runtime-plugin-boundary.whatsapp.test.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { stageBundledPluginRuntime } from "../../scripts/stage-bundled-plugin-runtime.mjs";
|
||||
import { loadPluginBoundaryModuleWithJiti } from "./runtime/runtime-plugin-boundary.js";
|
||||
|
||||
type LightModule = {
|
||||
getActiveWebListener: (accountId?: string | null) => unknown;
|
||||
};
|
||||
|
||||
type HeavyModule = {
|
||||
setActiveWebListener: (
|
||||
accountId: string | null | undefined,
|
||||
listener: { sendMessage: () => Promise<{ messageId: string }> } | null,
|
||||
) => void;
|
||||
};
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
function createBundledWhatsAppRuntimeFixture() {
|
||||
const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-whatsapp-boundary-"));
|
||||
tempDirs.push(rootDir);
|
||||
const distRoot = path.join(rootDir, "dist");
|
||||
const whatsappDistDir = path.join(distRoot, "extensions", "whatsapp");
|
||||
fs.mkdirSync(whatsappDistDir, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(rootDir, "package.json"),
|
||||
JSON.stringify(
|
||||
{
|
||||
name: "openclaw",
|
||||
type: "module",
|
||||
bin: {
|
||||
openclaw: "openclaw.mjs",
|
||||
},
|
||||
exports: {
|
||||
"./plugin-sdk": {
|
||||
default: "./dist/plugin-sdk/index.js",
|
||||
},
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
"utf8",
|
||||
);
|
||||
fs.writeFileSync(path.join(rootDir, "openclaw.mjs"), "export {};\n", "utf8");
|
||||
fs.writeFileSync(path.join(whatsappDistDir, "index.js"), "export default {};\n", "utf8");
|
||||
fs.writeFileSync(
|
||||
path.join(whatsappDistDir, "light-runtime-api.js"),
|
||||
'export { getActiveWebListener } from "../../active-listener.js";\n',
|
||||
"utf8",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(whatsappDistDir, "runtime-api.js"),
|
||||
'export { getActiveWebListener, setActiveWebListener } from "../../active-listener.js";\n',
|
||||
"utf8",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(distRoot, "active-listener.js"),
|
||||
[
|
||||
'const key = Symbol.for("openclaw.whatsapp.activeListenerState");',
|
||||
"const g = globalThis;",
|
||||
"if (!g[key]) {",
|
||||
" g[key] = { listeners: new Map(), current: null };",
|
||||
"}",
|
||||
"const state = g[key];",
|
||||
"export function setActiveWebListener(accountIdOrListener, maybeListener) {",
|
||||
' const accountId = typeof accountIdOrListener === "string" ? accountIdOrListener : "default";',
|
||||
' const listener = typeof accountIdOrListener === "string" ? (maybeListener ?? null) : (accountIdOrListener ?? null);',
|
||||
" if (!listener) state.listeners.delete(accountId);",
|
||||
" else state.listeners.set(accountId, listener);",
|
||||
' if (accountId === "default") state.current = listener;',
|
||||
"}",
|
||||
"export function getActiveWebListener(accountId) {",
|
||||
' return state.listeners.get(accountId ?? "default") ?? null;',
|
||||
"}",
|
||||
"",
|
||||
].join("\n"),
|
||||
"utf8",
|
||||
);
|
||||
stageBundledPluginRuntime({ repoRoot: rootDir });
|
||||
|
||||
return path.join(rootDir, "dist-runtime", "extensions", "whatsapp");
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
for (const dir of tempDirs.splice(0, tempDirs.length)) {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
describe("runtime plugin boundary whatsapp seam", () => {
|
||||
it("shares listener state between staged light and heavy runtime modules", () => {
|
||||
const runtimePluginDir = createBundledWhatsAppRuntimeFixture();
|
||||
const loaders = new Map<boolean, ReturnType<typeof import("jiti").createJiti>>();
|
||||
const light = loadPluginBoundaryModuleWithJiti<LightModule>(
|
||||
path.join(runtimePluginDir, "light-runtime-api.js"),
|
||||
loaders,
|
||||
);
|
||||
const heavy = loadPluginBoundaryModuleWithJiti<HeavyModule>(
|
||||
path.join(runtimePluginDir, "runtime-api.js"),
|
||||
loaders,
|
||||
);
|
||||
const listener = {
|
||||
sendMessage: async () => ({ messageId: "msg-1" }),
|
||||
};
|
||||
|
||||
heavy.setActiveWebListener("work", listener);
|
||||
|
||||
expect(light.getActiveWebListener("work")).toBe(listener);
|
||||
|
||||
heavy.setActiveWebListener("work", null);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user