test(ci): reduce channel contract import cost

This commit is contained in:
Peter Steinberger
2026-04-21 00:39:21 +01:00
parent 92191d37e6
commit 982b1c9464
33 changed files with 127 additions and 60 deletions

View File

@@ -0,0 +1,55 @@
import { listBundledChannelPluginIds as listCatalogBundledChannelPluginIds } from "../../../src/channels/plugins/bundled-ids.js";
import type { ChannelId } from "../../../src/channels/plugins/channel-id.types.js";
import type { ChannelPlugin } from "../../../src/channels/plugins/types.js";
import {
listChannelCatalogEntries,
type PluginChannelCatalogEntry,
} from "../../../src/plugins/channel-catalog-registry.js";
import { loadBundledPluginPublicSurfaceSync } from "../../../src/test-utils/bundled-plugin-public-surface.js";
type ChannelPluginApiModule = Record<string, unknown>;
const channelPluginCache = new Map<ChannelId, ChannelPlugin | null>();
let channelCatalogEntries: PluginChannelCatalogEntry[] | undefined;
function isChannelPlugin(value: unknown): value is ChannelPlugin {
return (
Boolean(value) &&
typeof value === "object" &&
typeof (value as Partial<ChannelPlugin>).id === "string" &&
Boolean((value as Partial<ChannelPlugin>).meta) &&
Boolean((value as Partial<ChannelPlugin>).config)
);
}
export function listBundledChannelPluginIds(): readonly ChannelId[] {
return listCatalogBundledChannelPluginIds() as ChannelId[];
}
export function getBundledChannelCatalogEntry(
id: ChannelId,
): PluginChannelCatalogEntry | undefined {
channelCatalogEntries ??= listChannelCatalogEntries({ origin: "bundled" });
return channelCatalogEntries.find((entry) => entry.pluginId === id || entry.channel.id === id);
}
export function getBundledChannelPlugin(id: ChannelId): ChannelPlugin | undefined {
if (channelPluginCache.has(id)) {
return channelPluginCache.get(id) ?? undefined;
}
const loaded = loadBundledPluginPublicSurfaceSync<ChannelPluginApiModule>({
pluginId: id,
artifactBasename: "channel-plugin-api.js",
});
const plugin = Object.values(loaded).find(isChannelPlugin) ?? null;
channelPluginCache.set(id, plugin);
return plugin ?? undefined;
}
export function listBundledChannelPlugins(): readonly ChannelPlugin[] {
return listBundledChannelPluginIds().flatMap((id) => {
const plugin = getBundledChannelPlugin(id);
return plugin ? [plugin] : [];
});
}

View File

@@ -1,11 +1,12 @@
import {
getBundledChannelPlugin,
listBundledChannelPluginIds,
listBundledChannelPlugins,
} from "../../../src/channels/plugins/bundled.js";
import type { ChannelId } from "../../../src/channels/plugins/channel-id.types.js";
import { normalizeChannelMeta } from "../../../src/channels/plugins/meta-normalization.js";
import type { ChannelPlugin } from "../../../src/channels/plugins/types.js";
import {
getBundledChannelCatalogEntry,
getBundledChannelPlugin,
listBundledChannelPluginIds,
listBundledChannelPlugins,
} from "./bundled-channel-plugin-loader.js";
type PluginContractEntry = {
id: string;
@@ -13,11 +14,12 @@ type PluginContractEntry = {
};
function toPluginContractEntry(plugin: ChannelPlugin): PluginContractEntry {
const existingMeta = getBundledChannelCatalogEntry(plugin.id)?.channel;
return {
id: plugin.id,
plugin: {
...plugin,
meta: normalizeChannelMeta({ id: plugin.id, meta: plugin.meta }),
meta: normalizeChannelMeta({ id: plugin.id, meta: plugin.meta, existing: existingMeta }),
},
};
}

View File

@@ -1,17 +1,11 @@
import {
getBundledChannelPlugin,
listBundledChannelPluginIds,
listBundledChannelPlugins,
setBundledChannelRuntime,
} from "../../../src/channels/plugins/bundled.js";
import type { ChannelId } from "../../../src/channels/plugins/channel-id.types.js";
import type { ChannelPlugin } from "../../../src/channels/plugins/types.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import {
listLineAccountIds,
resolveDefaultLineAccountId,
resolveLineAccount,
} from "../../../src/plugin-sdk/line.js";
getBundledChannelPlugin,
listBundledChannelPluginIds,
listBundledChannelPlugins,
} from "./bundled-channel-plugin-loader.js";
import { channelPluginSurfaceKeys, type ChannelPluginSurface } from "./manifest.js";
type SurfaceContractEntry = {
@@ -44,17 +38,6 @@ type DirectoryContractEntry = {
accountId?: string;
};
setBundledChannelRuntime("line", {
channel: {
line: {
listLineAccountIds,
resolveDefaultLineAccountId,
resolveLineAccount: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId?: string }) =>
resolveLineAccount({ cfg, accountId }),
},
},
} as never);
let surfaceContractRegistryCache: SurfaceContractEntry[] | undefined;
const surfaceContractEntryCache = new Map<ChannelId, SurfaceContractEntry | null>();
let threadingContractRegistryCache: ThreadingContractEntry[] | undefined;

View File

@@ -7,9 +7,18 @@ import type {
} from "../../../src/channels/plugins/types.core.js";
import type { ChannelPlugin } from "../../../src/channels/plugins/types.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import { createNonExitingRuntime } from "../../../src/runtime.js";
import type { RuntimeEnv } from "../../../src/runtime.js";
const contractRuntime = createNonExitingRuntime();
let contractRuntime: RuntimeEnv | undefined;
async function getDirectoryContractRuntime(): Promise<RuntimeEnv> {
if (contractRuntime) {
return contractRuntime;
}
const { createNonExitingRuntime } = await import("../../../src/runtime.js");
contractRuntime = createNonExitingRuntime();
return contractRuntime;
}
function expectDirectoryEntryShape(entry: ChannelDirectoryEntry) {
expect(["user", "group", "channel"]).toContain(entry.kind);
@@ -177,10 +186,11 @@ export function installChannelDirectoryContractSuite(params: {
if (params.coverage === "presence") {
return;
}
const runtime = await getDirectoryContractRuntime();
const self = await directory?.self?.({
cfg: params.cfg ?? ({} as OpenClawConfig),
accountId: params.accountId ?? "default",
runtime: contractRuntime,
runtime,
});
if (self) {
expectDirectoryEntryShape(self);
@@ -192,7 +202,7 @@ export function installChannelDirectoryContractSuite(params: {
accountId: params.accountId ?? "default",
query: "",
limit: 5,
runtime: contractRuntime,
runtime,
})) ?? [];
expect(Array.isArray(peers)).toBe(true);
for (const peer of peers) {
@@ -205,7 +215,7 @@ export function installChannelDirectoryContractSuite(params: {
accountId: params.accountId ?? "default",
query: "",
limit: 5,
runtime: contractRuntime,
runtime,
})) ?? [];
expect(Array.isArray(groups)).toBe(true);
for (const group of groups) {
@@ -218,7 +228,7 @@ export function installChannelDirectoryContractSuite(params: {
accountId: params.accountId ?? "default",
groupId: groups[0].id,
limit: 5,
runtime: contractRuntime,
runtime,
});
expect(Array.isArray(members)).toBe(true);
for (const member of members) {