mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-01 15:30:22 +00:00
test: trim plugin-sdk import-heavy startup
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import type {
|
||||
BaseProbeResult as ContractBaseProbeResult,
|
||||
BaseTokenResolution as ContractBaseTokenResolution,
|
||||
@@ -46,11 +47,11 @@ import { pluginSdkSubpaths } from "./entrypoints.js";
|
||||
|
||||
const ROOT_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const PLUGIN_SDK_DIR = resolve(ROOT_DIR, "plugin-sdk");
|
||||
const requireFromHere = createRequire(import.meta.url);
|
||||
const sourceCache = new Map<string, string>();
|
||||
const representativeRuntimeSmokeSubpaths = [
|
||||
"channel-runtime",
|
||||
"conversation-runtime",
|
||||
"core",
|
||||
"discord",
|
||||
"provider-auth",
|
||||
"provider-setup",
|
||||
@@ -58,7 +59,8 @@ const representativeRuntimeSmokeSubpaths = [
|
||||
"webhook-ingress",
|
||||
] as const;
|
||||
|
||||
const importPluginSdkSubpath = (specifier: string) => import(/* @vite-ignore */ specifier);
|
||||
const importResolvedPluginSdkSubpath = async (specifier: string) =>
|
||||
import(pathToFileURL(requireFromHere.resolve(specifier)).href);
|
||||
|
||||
function readPluginSdkSource(subpath: string): string {
|
||||
const file = resolve(PLUGIN_SDK_DIR, `${subpath}.ts`);
|
||||
@@ -100,18 +102,25 @@ function sourceMentionsIdentifier(source: string, name: string): boolean {
|
||||
|
||||
function expectSourceMentions(subpath: string, names: readonly string[]) {
|
||||
const source = readPluginSdkSource(subpath);
|
||||
for (const name of names) {
|
||||
expect(sourceMentionsIdentifier(source, name), `${subpath} should mention ${name}`).toBe(true);
|
||||
}
|
||||
const missing = names.filter((name) => !sourceMentionsIdentifier(source, name));
|
||||
expect(missing, `${subpath} missing exports`).toEqual([]);
|
||||
}
|
||||
|
||||
function expectSourceOmits(subpath: string, names: readonly string[]) {
|
||||
const source = readPluginSdkSource(subpath);
|
||||
for (const name of names) {
|
||||
expect(sourceMentionsIdentifier(source, name), `${subpath} should not mention ${name}`).toBe(
|
||||
false,
|
||||
);
|
||||
}
|
||||
const present = names.filter((name) => sourceMentionsIdentifier(source, name));
|
||||
expect(present, `${subpath} leaked exports`).toEqual([]);
|
||||
}
|
||||
|
||||
function expectSourceContract(
|
||||
subpath: string,
|
||||
params: { mentions?: readonly string[]; omits?: readonly string[] },
|
||||
) {
|
||||
const source = readPluginSdkSource(subpath);
|
||||
const missing = (params.mentions ?? []).filter((name) => !sourceMentionsIdentifier(source, name));
|
||||
const present = (params.omits ?? []).filter((name) => sourceMentionsIdentifier(source, name));
|
||||
expect(missing, `${subpath} missing exports`).toEqual([]);
|
||||
expect(present, `${subpath} leaked exports`).toEqual([]);
|
||||
}
|
||||
|
||||
describe("plugin-sdk subpath exports", () => {
|
||||
@@ -154,16 +163,15 @@ describe("plugin-sdk subpath exports", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("re-exports the canonical plugin entry helper from core", async () => {
|
||||
const [coreSdk, pluginEntrySdk] = await Promise.all([
|
||||
importPluginSdkSubpath("openclaw/plugin-sdk/core"),
|
||||
importPluginSdkSubpath("openclaw/plugin-sdk/plugin-entry"),
|
||||
]);
|
||||
expect(coreSdk.definePluginEntry).toBe(pluginEntrySdk.definePluginEntry);
|
||||
});
|
||||
|
||||
it("keeps generic helper subpaths aligned", () => {
|
||||
expectSourceMentions("routing", ["buildAgentSessionKey", "resolveThreadSessionKeys"]);
|
||||
expectSourceContract("routing", {
|
||||
mentions: [
|
||||
"buildAgentSessionKey",
|
||||
"resolveThreadSessionKeys",
|
||||
"normalizeMessageChannel",
|
||||
"resolveGatewayMessageChannel",
|
||||
],
|
||||
});
|
||||
expectSourceMentions("reply-payload", [
|
||||
"buildMediaPayload",
|
||||
"deliverTextOrMediaReply",
|
||||
@@ -183,12 +191,14 @@ describe("plugin-sdk subpath exports", () => {
|
||||
"clearHistoryEntriesIfEnabled",
|
||||
"recordPendingHistoryEntryIfEnabled",
|
||||
]);
|
||||
expectSourceOmits("reply-runtime", [
|
||||
"buildPendingHistoryContextFromMap",
|
||||
"clearHistoryEntriesIfEnabled",
|
||||
"recordPendingHistoryEntryIfEnabled",
|
||||
"DEFAULT_GROUP_HISTORY_LIMIT",
|
||||
]);
|
||||
expectSourceContract("reply-runtime", {
|
||||
omits: [
|
||||
"buildPendingHistoryContextFromMap",
|
||||
"clearHistoryEntriesIfEnabled",
|
||||
"recordPendingHistoryEntryIfEnabled",
|
||||
"DEFAULT_GROUP_HISTORY_LIMIT",
|
||||
],
|
||||
});
|
||||
expectSourceMentions("account-helpers", ["createAccountListHelpers"]);
|
||||
expectSourceMentions("device-bootstrap", [
|
||||
"approveDevicePairing",
|
||||
@@ -199,23 +209,23 @@ describe("plugin-sdk subpath exports", () => {
|
||||
"buildDmGroupAccountAllowlistAdapter",
|
||||
"createNestedAllowlistOverrideResolver",
|
||||
]);
|
||||
expectSourceMentions("allow-from", [
|
||||
"addAllowlistUserEntriesFromConfigEntry",
|
||||
"buildAllowlistResolutionSummary",
|
||||
"canonicalizeAllowlistWithResolvedIds",
|
||||
"mapAllowlistResolutionInputs",
|
||||
"mergeAllowlist",
|
||||
"patchAllowlistUsersInConfigEntries",
|
||||
"summarizeMapping",
|
||||
]);
|
||||
expectSourceMentions("allow-from", [
|
||||
"compileAllowlist",
|
||||
"firstDefined",
|
||||
"formatAllowlistMatchMeta",
|
||||
"isSenderIdAllowed",
|
||||
"mergeDmAllowFromSources",
|
||||
"resolveAllowlistMatchSimple",
|
||||
]);
|
||||
expectSourceContract("allow-from", {
|
||||
mentions: [
|
||||
"addAllowlistUserEntriesFromConfigEntry",
|
||||
"buildAllowlistResolutionSummary",
|
||||
"canonicalizeAllowlistWithResolvedIds",
|
||||
"mapAllowlistResolutionInputs",
|
||||
"mergeAllowlist",
|
||||
"patchAllowlistUsersInConfigEntries",
|
||||
"summarizeMapping",
|
||||
"compileAllowlist",
|
||||
"firstDefined",
|
||||
"formatAllowlistMatchMeta",
|
||||
"isSenderIdAllowed",
|
||||
"mergeDmAllowFromSources",
|
||||
"resolveAllowlistMatchSimple",
|
||||
],
|
||||
});
|
||||
expectSourceMentions("runtime", ["createLoggerBackedRuntime"]);
|
||||
expectSourceMentions("discord", [
|
||||
"buildDiscordComponentMessage",
|
||||
@@ -223,7 +233,6 @@ describe("plugin-sdk subpath exports", () => {
|
||||
"registerBuiltDiscordComponentMessage",
|
||||
"resolveDiscordAccount",
|
||||
]);
|
||||
expectSourceMentions("routing", ["normalizeMessageChannel", "resolveGatewayMessageChannel"]);
|
||||
expectSourceMentions("conversation-runtime", [
|
||||
"recordInboundSession",
|
||||
"recordInboundSessionMetaSafe",
|
||||
@@ -237,12 +246,6 @@ describe("plugin-sdk subpath exports", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("exports infra runtime helpers from the dedicated subpath", async () => {
|
||||
const infraRuntimeSdk = await importPluginSdkSubpath("openclaw/plugin-sdk/infra-runtime");
|
||||
expect(typeof infraRuntimeSdk.createRuntimeOutboundDelegates).toBe("function");
|
||||
expect(typeof infraRuntimeSdk.resolveOutboundSendDep).toBe("function");
|
||||
});
|
||||
|
||||
it("exports channel runtime helpers from the dedicated subpath", () => {
|
||||
expectSourceOmits("channel-runtime", [
|
||||
"applyChannelMatchMeta",
|
||||
@@ -366,26 +369,43 @@ describe("plugin-sdk subpath exports", () => {
|
||||
"shouldDebounceTextInbound",
|
||||
"toLocationContext",
|
||||
]);
|
||||
expectSourceOmits("reply-runtime", [
|
||||
"buildMentionRegexes",
|
||||
"createInboundDebouncer",
|
||||
"formatInboundEnvelope",
|
||||
"formatInboundFromLabel",
|
||||
"matchesMentionPatterns",
|
||||
"matchesMentionWithExplicit",
|
||||
"normalizeMentionText",
|
||||
"resolveEnvelopeFormatOptions",
|
||||
"resolveInboundDebounceMs",
|
||||
]);
|
||||
expectSourceContract("reply-runtime", {
|
||||
omits: [
|
||||
"buildMentionRegexes",
|
||||
"createInboundDebouncer",
|
||||
"formatInboundEnvelope",
|
||||
"formatInboundFromLabel",
|
||||
"matchesMentionPatterns",
|
||||
"matchesMentionWithExplicit",
|
||||
"normalizeMentionText",
|
||||
"resolveEnvelopeFormatOptions",
|
||||
"resolveInboundDebounceMs",
|
||||
"hasControlCommand",
|
||||
"buildCommandTextFromArgs",
|
||||
"buildCommandsPaginationKeyboard",
|
||||
"buildModelsProviderData",
|
||||
"listNativeCommandSpecsForConfig",
|
||||
"listSkillCommandsForAgents",
|
||||
"normalizeCommandBody",
|
||||
"resolveCommandAuthorization",
|
||||
"resolveStoredModelOverride",
|
||||
"shouldComputeCommandAuthorized",
|
||||
"shouldHandleTextCommands",
|
||||
],
|
||||
});
|
||||
expectSourceMentions("channel-setup", [
|
||||
"createOptionalChannelSetupSurface",
|
||||
"createTopLevelChannelDmPolicy",
|
||||
]);
|
||||
expectSourceMentions("channel-actions", [
|
||||
"createUnionActionGate",
|
||||
"listTokenSourcedAccounts",
|
||||
"resolveReactionMessageId",
|
||||
]);
|
||||
expectSourceContract("channel-actions", {
|
||||
mentions: [
|
||||
"createUnionActionGate",
|
||||
"listTokenSourcedAccounts",
|
||||
"resolveReactionMessageId",
|
||||
"createMessageToolButtonsSchema",
|
||||
"createMessageToolCardSchema",
|
||||
],
|
||||
});
|
||||
expectSourceMentions("channel-targets", [
|
||||
"applyChannelMatchMeta",
|
||||
"buildChannelKeyCandidates",
|
||||
@@ -419,10 +439,6 @@ describe("plugin-sdk subpath exports", () => {
|
||||
"isRecord",
|
||||
"resolveEnabledConfiguredAccountId",
|
||||
]);
|
||||
expectSourceMentions("channel-actions", [
|
||||
"createMessageToolButtonsSchema",
|
||||
"createMessageToolCardSchema",
|
||||
]);
|
||||
expectSourceMentions("command-auth", [
|
||||
"buildCommandTextFromArgs",
|
||||
"buildCommandsPaginationKeyboard",
|
||||
@@ -440,19 +456,6 @@ describe("plugin-sdk subpath exports", () => {
|
||||
"shouldComputeCommandAuthorized",
|
||||
"shouldHandleTextCommands",
|
||||
]);
|
||||
expectSourceOmits("reply-runtime", [
|
||||
"hasControlCommand",
|
||||
"buildCommandTextFromArgs",
|
||||
"buildCommandsPaginationKeyboard",
|
||||
"buildModelsProviderData",
|
||||
"listNativeCommandSpecsForConfig",
|
||||
"listSkillCommandsForAgents",
|
||||
"normalizeCommandBody",
|
||||
"resolveCommandAuthorization",
|
||||
"resolveStoredModelOverride",
|
||||
"shouldComputeCommandAuthorized",
|
||||
"shouldHandleTextCommands",
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps channel contract types on the dedicated subpath", () => {
|
||||
@@ -470,39 +473,6 @@ describe("plugin-sdk subpath exports", () => {
|
||||
expectTypeOf<ContractChannelThreadingToolContext>().toMatchTypeOf<ChannelThreadingToolContext>();
|
||||
});
|
||||
|
||||
it("exports channel lifecycle helpers from the dedicated subpath", async () => {
|
||||
const channelLifecycleSdk = await importPluginSdkSubpath(
|
||||
"openclaw/plugin-sdk/channel-lifecycle",
|
||||
);
|
||||
expect(typeof channelLifecycleSdk.createDraftStreamLoop).toBe("function");
|
||||
expect(typeof channelLifecycleSdk.createFinalizableDraftLifecycle).toBe("function");
|
||||
expect(typeof channelLifecycleSdk.runPassiveAccountLifecycle).toBe("function");
|
||||
expect(typeof channelLifecycleSdk.createRunStateMachine).toBe("function");
|
||||
expect(typeof channelLifecycleSdk.createArmableStallWatchdog).toBe("function");
|
||||
});
|
||||
|
||||
it("exports channel pairing helpers from the dedicated subpath", async () => {
|
||||
const channelPairingSdk = await importPluginSdkSubpath("openclaw/plugin-sdk/channel-pairing");
|
||||
expectSourceMentions("channel-pairing", [
|
||||
"createChannelPairingController",
|
||||
"createChannelPairingChallengeIssuer",
|
||||
"createLoggedPairingApprovalNotifier",
|
||||
"createPairingPrefixStripper",
|
||||
"createTextPairingAdapter",
|
||||
]);
|
||||
expect("createScopedPairingAccess" in channelPairingSdk).toBe(false);
|
||||
});
|
||||
|
||||
it("exports channel reply pipeline helpers from the dedicated subpath", async () => {
|
||||
const channelReplyPipelineSdk = await importPluginSdkSubpath(
|
||||
"openclaw/plugin-sdk/channel-reply-pipeline",
|
||||
);
|
||||
expectSourceMentions("channel-reply-pipeline", ["createChannelReplyPipeline"]);
|
||||
expect("createTypingCallbacks" in channelReplyPipelineSdk).toBe(false);
|
||||
expect("createReplyPrefixContext" in channelReplyPipelineSdk).toBe(false);
|
||||
expect("createReplyPrefixOptions" in channelReplyPipelineSdk).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps source-only helper subpaths aligned", () => {
|
||||
expectSourceMentions("channel-send-result", [
|
||||
"attachChannelToResult",
|
||||
@@ -551,17 +521,15 @@ describe("plugin-sdk subpath exports", () => {
|
||||
"toFormUrlEncoded",
|
||||
]);
|
||||
expectSourceOmits("core", ["buildOauthProviderAuthResult"]);
|
||||
expectSourceMentions("provider-models", [
|
||||
"applyOpenAIConfig",
|
||||
"buildKilocodeModelDefinition",
|
||||
"discoverHuggingfaceModels",
|
||||
]);
|
||||
expectSourceOmits("provider-models", [
|
||||
"buildMinimaxModelDefinition",
|
||||
"buildMoonshotProvider",
|
||||
"QIANFAN_BASE_URL",
|
||||
"resolveZaiBaseUrl",
|
||||
]);
|
||||
expectSourceContract("provider-models", {
|
||||
mentions: ["applyOpenAIConfig", "buildKilocodeModelDefinition", "discoverHuggingfaceModels"],
|
||||
omits: [
|
||||
"buildMinimaxModelDefinition",
|
||||
"buildMoonshotProvider",
|
||||
"QIANFAN_BASE_URL",
|
||||
"resolveZaiBaseUrl",
|
||||
],
|
||||
});
|
||||
|
||||
expectSourceMentions("setup", [
|
||||
"DEFAULT_ACCOUNT_ID",
|
||||
@@ -589,7 +557,6 @@ describe("plugin-sdk subpath exports", () => {
|
||||
"normalizeResolvedSecretInputString",
|
||||
"normalizeSecretInputString",
|
||||
]);
|
||||
|
||||
expectSourceMentions("webhook-ingress", [
|
||||
"registerPluginHttpRoute",
|
||||
"resolveWebhookPath",
|
||||
@@ -613,10 +580,55 @@ describe("plugin-sdk subpath exports", () => {
|
||||
expectTypeOf<CoreChannelMessageActionContext>().toMatchTypeOf<SharedChannelMessageActionContext>();
|
||||
});
|
||||
|
||||
it("resolves representative curated public subpaths", async () => {
|
||||
it("keeps runtime entry subpaths importable", async () => {
|
||||
const [
|
||||
coreSdk,
|
||||
pluginEntrySdk,
|
||||
infraRuntimeSdk,
|
||||
channelLifecycleSdk,
|
||||
channelPairingSdk,
|
||||
channelReplyPipelineSdk,
|
||||
...representativeModules
|
||||
] = await Promise.all([
|
||||
importResolvedPluginSdkSubpath("openclaw/plugin-sdk/core"),
|
||||
importResolvedPluginSdkSubpath("openclaw/plugin-sdk/plugin-entry"),
|
||||
importResolvedPluginSdkSubpath("openclaw/plugin-sdk/infra-runtime"),
|
||||
importResolvedPluginSdkSubpath("openclaw/plugin-sdk/channel-lifecycle"),
|
||||
importResolvedPluginSdkSubpath("openclaw/plugin-sdk/channel-pairing"),
|
||||
importResolvedPluginSdkSubpath("openclaw/plugin-sdk/channel-reply-pipeline"),
|
||||
...representativeRuntimeSmokeSubpaths.map((id) =>
|
||||
importResolvedPluginSdkSubpath(`openclaw/plugin-sdk/${id}`),
|
||||
),
|
||||
]);
|
||||
|
||||
expect(coreSdk.definePluginEntry).toBe(pluginEntrySdk.definePluginEntry);
|
||||
|
||||
expect(typeof infraRuntimeSdk.createRuntimeOutboundDelegates).toBe("function");
|
||||
expect(typeof infraRuntimeSdk.resolveOutboundSendDep).toBe("function");
|
||||
|
||||
expect(typeof channelLifecycleSdk.createDraftStreamLoop).toBe("function");
|
||||
expect(typeof channelLifecycleSdk.createFinalizableDraftLifecycle).toBe("function");
|
||||
expect(typeof channelLifecycleSdk.runPassiveAccountLifecycle).toBe("function");
|
||||
expect(typeof channelLifecycleSdk.createRunStateMachine).toBe("function");
|
||||
expect(typeof channelLifecycleSdk.createArmableStallWatchdog).toBe("function");
|
||||
|
||||
expectSourceMentions("channel-pairing", [
|
||||
"createChannelPairingController",
|
||||
"createChannelPairingChallengeIssuer",
|
||||
"createLoggedPairingApprovalNotifier",
|
||||
"createPairingPrefixStripper",
|
||||
"createTextPairingAdapter",
|
||||
]);
|
||||
expect("createScopedPairingAccess" in channelPairingSdk).toBe(false);
|
||||
|
||||
expectSourceMentions("channel-reply-pipeline", ["createChannelReplyPipeline"]);
|
||||
expect("createTypingCallbacks" in channelReplyPipelineSdk).toBe(false);
|
||||
expect("createReplyPrefixContext" in channelReplyPipelineSdk).toBe(false);
|
||||
expect("createReplyPrefixOptions" in channelReplyPipelineSdk).toBe(false);
|
||||
|
||||
expect(pluginSdkSubpaths.length).toBeGreaterThan(representativeRuntimeSmokeSubpaths.length);
|
||||
for (const id of representativeRuntimeSmokeSubpaths) {
|
||||
const mod = await importPluginSdkSubpath(`openclaw/plugin-sdk/${id}`);
|
||||
for (const [index, id] of representativeRuntimeSmokeSubpaths.entries()) {
|
||||
const mod = representativeModules[index];
|
||||
expect(typeof mod).toBe("object");
|
||||
expect(mod, `subpath ${id} should resolve`).toBeTruthy();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user