mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-23 14:45:46 +00:00
perf(test): lazy-load bundled channel secrets
This commit is contained in:
@@ -9,6 +9,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "bluebubblesPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setBlueBubblesRuntime",
|
||||
|
||||
@@ -6,4 +6,8 @@ export default defineBundledChannelSetupEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "bluebubblesSetupPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -52,3 +52,8 @@ export function collectRuntimeConfigAssignments(params: {
|
||||
accountInactiveReason: "BlueBubbles account is disabled.",
|
||||
});
|
||||
}
|
||||
|
||||
export const channelSecrets = {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
};
|
||||
|
||||
@@ -9,6 +9,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "feishuPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setFeishuRuntime",
|
||||
|
||||
@@ -70,6 +70,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "feishuPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setFeishuRuntime",
|
||||
|
||||
@@ -6,4 +6,8 @@ export default defineBundledChannelSetupEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "feishuPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -138,3 +138,8 @@ export function collectRuntimeConfigAssignments(params: {
|
||||
accountInactiveReason: "Feishu account is disabled or not running in webhook mode.",
|
||||
});
|
||||
}
|
||||
|
||||
export const channelSecrets = {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
};
|
||||
|
||||
@@ -9,6 +9,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "googlechatPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setGoogleChatRuntime",
|
||||
|
||||
@@ -6,4 +6,8 @@ export default defineBundledChannelSetupEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "googlechatPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -154,3 +154,8 @@ export function collectRuntimeConfigAssignments(params: {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const channelSecrets = {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
};
|
||||
|
||||
@@ -9,6 +9,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./channel-plugin-api.js",
|
||||
exportName: "ircPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setIrcRuntime",
|
||||
|
||||
@@ -6,4 +6,8 @@ export default defineBundledChannelSetupEntry({
|
||||
specifier: "./channel-plugin-api.js",
|
||||
exportName: "ircPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -96,3 +96,8 @@ export function collectRuntimeConfigAssignments(params: {
|
||||
accountInactiveReason: "IRC account is disabled or NickServ is disabled for this account.",
|
||||
});
|
||||
}
|
||||
|
||||
export const channelSecrets = {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
};
|
||||
|
||||
@@ -10,6 +10,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./channel-plugin-api.js",
|
||||
exportName: "matrixPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setMatrixRuntime",
|
||||
|
||||
@@ -6,4 +6,8 @@ export default defineBundledChannelSetupEntry({
|
||||
specifier: "./channel-plugin-api.js",
|
||||
exportName: "matrixPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -167,3 +167,8 @@ export function collectRuntimeConfigAssignments(params: {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const channelSecrets = {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
};
|
||||
|
||||
@@ -21,6 +21,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./channel-plugin-api.js",
|
||||
exportName: "mattermostPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setMattermostRuntime",
|
||||
|
||||
@@ -6,4 +6,8 @@ export default defineBundledChannelSetupEntry({
|
||||
specifier: "./channel-plugin-api.js",
|
||||
exportName: "mattermostSetupPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -52,3 +52,8 @@ export function collectRuntimeConfigAssignments(params: {
|
||||
accountInactiveReason: "Mattermost account is disabled.",
|
||||
});
|
||||
}
|
||||
|
||||
export const channelSecrets = {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
};
|
||||
|
||||
@@ -9,6 +9,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "msteamsPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setMSTeamsRuntime",
|
||||
|
||||
@@ -6,4 +6,8 @@ export default defineBundledChannelSetupEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "msteamsPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -42,3 +42,8 @@ export function collectRuntimeConfigAssignments(params: {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const channelSecrets = {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
};
|
||||
|
||||
@@ -9,6 +9,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "nextcloudTalkPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setNextcloudTalkRuntime",
|
||||
|
||||
@@ -6,4 +6,8 @@ export default defineBundledChannelSetupEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "nextcloudTalkPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -96,3 +96,8 @@ export function collectRuntimeConfigAssignments(params: {
|
||||
accountInactiveReason: "Nextcloud Talk account is disabled.",
|
||||
});
|
||||
}
|
||||
|
||||
export const channelSecrets = {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
};
|
||||
|
||||
@@ -9,6 +9,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "slackPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setSlackRuntime",
|
||||
|
||||
@@ -21,6 +21,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./channel-plugin-api.js",
|
||||
exportName: "slackPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setSlackRuntime",
|
||||
|
||||
@@ -6,4 +6,8 @@ export default defineBundledChannelSetupEntry({
|
||||
specifier: "./channel-plugin-api.js",
|
||||
exportName: "slackSetupPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -156,3 +156,8 @@ export function collectRuntimeConfigAssignments(params: {
|
||||
accountInactiveReason: "Slack account is disabled or not running in HTTP mode.",
|
||||
});
|
||||
}
|
||||
|
||||
export const channelSecrets = {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
};
|
||||
|
||||
@@ -9,6 +9,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./channel-plugin-api.js",
|
||||
exportName: "telegramPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setTelegramRuntime",
|
||||
|
||||
@@ -6,4 +6,8 @@ export default defineBundledChannelSetupEntry({
|
||||
specifier: "./channel-plugin-api.js",
|
||||
exportName: "telegramSetupPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -115,3 +115,8 @@ export function collectRuntimeConfigAssignments(params: {
|
||||
"Telegram account is disabled or webhook mode is not active for this account.",
|
||||
});
|
||||
}
|
||||
|
||||
export const channelSecrets = {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
};
|
||||
|
||||
@@ -9,6 +9,10 @@ export default defineBundledChannelEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "zaloPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
runtime: {
|
||||
specifier: "./runtime-api.js",
|
||||
exportName: "setZaloRuntime",
|
||||
|
||||
@@ -6,4 +6,8 @@ export default defineBundledChannelSetupEntry({
|
||||
specifier: "./api.js",
|
||||
exportName: "zaloPlugin",
|
||||
},
|
||||
secrets: {
|
||||
specifier: "./src/secret-contract.js",
|
||||
exportName: "channelSecrets",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -102,3 +102,8 @@ export function collectRuntimeConfigAssignments(params: {
|
||||
"Zalo account is disabled or webhook mode is not active for this account.",
|
||||
});
|
||||
}
|
||||
|
||||
export const channelSecrets = {
|
||||
secretTargetRegistryEntries,
|
||||
collectRuntimeConfigAssignments,
|
||||
};
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { listBundledChannelPluginIds } from "./bundled-ids.js";
|
||||
import { getBundledChannelPlugin, getBundledChannelSetupPlugin } from "./bundled.js";
|
||||
import {
|
||||
getBundledChannelPlugin,
|
||||
getBundledChannelSecrets,
|
||||
getBundledChannelSetupPlugin,
|
||||
getBundledChannelSetupSecrets,
|
||||
} from "./bundled.js";
|
||||
import type { ChannelId, ChannelPlugin } from "./types.js";
|
||||
|
||||
type CachedBootstrapPlugins = {
|
||||
sortedIds: string[];
|
||||
byId: Map<string, ChannelPlugin>;
|
||||
secretsById: Map<string, ChannelPlugin["secrets"] | null>;
|
||||
missingIds: Set<string>;
|
||||
};
|
||||
|
||||
@@ -52,6 +58,7 @@ function buildBootstrapPlugins(): CachedBootstrapPlugins {
|
||||
return {
|
||||
sortedIds: listBundledChannelPluginIds(),
|
||||
byId: new Map(),
|
||||
secretsById: new Map(),
|
||||
missingIds: new Set(),
|
||||
};
|
||||
}
|
||||
@@ -105,6 +112,26 @@ export function getBootstrapChannelPlugin(id: ChannelId): ChannelPlugin | undefi
|
||||
return merged;
|
||||
}
|
||||
|
||||
export function getBootstrapChannelSecrets(id: ChannelId): ChannelPlugin["secrets"] | undefined {
|
||||
const resolvedId = String(id).trim();
|
||||
if (!resolvedId) {
|
||||
return undefined;
|
||||
}
|
||||
const registry = getBootstrapPlugins();
|
||||
const cached = registry.secretsById.get(resolvedId);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
if (registry.secretsById.has(resolvedId)) {
|
||||
return undefined;
|
||||
}
|
||||
const runtimeSecrets = getBundledChannelSecrets(resolvedId);
|
||||
const setupSecrets = getBundledChannelSetupSecrets(resolvedId);
|
||||
const merged = mergePluginSection(runtimeSecrets, setupSecrets);
|
||||
registry.secretsById.set(resolvedId, merged ?? null);
|
||||
return merged;
|
||||
}
|
||||
|
||||
export function clearBootstrapChannelPluginCache(): void {
|
||||
cachedBootstrapPlugins = null;
|
||||
}
|
||||
|
||||
@@ -191,6 +191,8 @@ type BundledChannelState = {
|
||||
sortedIds: readonly ChannelId[];
|
||||
pluginsById: Map<ChannelId, ChannelPlugin>;
|
||||
setupPluginsById: Map<ChannelId, ChannelPlugin>;
|
||||
secretsById: Map<ChannelId, ChannelPlugin["secrets"] | null>;
|
||||
setupSecretsById: Map<ChannelId, ChannelPlugin["secrets"] | null>;
|
||||
runtimeSettersById: Map<ChannelId, NonNullable<BundledChannelEntryContract["setChannelRuntime"]>>;
|
||||
};
|
||||
|
||||
@@ -201,6 +203,8 @@ const EMPTY_BUNDLED_CHANNEL_STATE: BundledChannelState = {
|
||||
sortedIds: [],
|
||||
pluginsById: new Map(),
|
||||
setupPluginsById: new Map(),
|
||||
secretsById: new Map(),
|
||||
setupSecretsById: new Map(),
|
||||
runtimeSettersById: new Map(),
|
||||
};
|
||||
|
||||
@@ -247,6 +251,8 @@ function getBundledChannelState(): BundledChannelState {
|
||||
sortedIds: [...entriesById.keys()].toSorted((left, right) => left.localeCompare(right)),
|
||||
pluginsById: new Map(),
|
||||
setupPluginsById: new Map(),
|
||||
secretsById: new Map(),
|
||||
setupSecretsById: new Map(),
|
||||
runtimeSettersById,
|
||||
};
|
||||
return cachedBundledChannelState;
|
||||
@@ -294,6 +300,20 @@ export function getBundledChannelPlugin(id: ChannelId): ChannelPlugin | undefine
|
||||
}
|
||||
}
|
||||
|
||||
export function getBundledChannelSecrets(id: ChannelId): ChannelPlugin["secrets"] | undefined {
|
||||
const state = getBundledChannelState();
|
||||
if (state.secretsById.has(id)) {
|
||||
return state.secretsById.get(id) ?? undefined;
|
||||
}
|
||||
const entry = state.entriesById.get(id);
|
||||
if (!entry) {
|
||||
return undefined;
|
||||
}
|
||||
const secrets = entry.loadChannelSecrets?.() ?? getBundledChannelPlugin(id)?.secrets;
|
||||
state.secretsById.set(id, secrets ?? null);
|
||||
return secrets;
|
||||
}
|
||||
|
||||
export function getBundledChannelSetupPlugin(id: ChannelId): ChannelPlugin | undefined {
|
||||
const state = getBundledChannelState();
|
||||
const cached = state.setupPluginsById.get(id);
|
||||
@@ -317,6 +337,20 @@ export function getBundledChannelSetupPlugin(id: ChannelId): ChannelPlugin | und
|
||||
}
|
||||
}
|
||||
|
||||
export function getBundledChannelSetupSecrets(id: ChannelId): ChannelPlugin["secrets"] | undefined {
|
||||
const state = getBundledChannelState();
|
||||
if (state.setupSecretsById.has(id)) {
|
||||
return state.setupSecretsById.get(id) ?? undefined;
|
||||
}
|
||||
const entry = state.setupEntriesById.get(id);
|
||||
if (!entry) {
|
||||
return undefined;
|
||||
}
|
||||
const secrets = entry.loadSetupSecrets?.() ?? getBundledChannelSetupPlugin(id)?.secrets;
|
||||
state.setupSecretsById.set(id, secrets ?? null);
|
||||
return secrets;
|
||||
}
|
||||
|
||||
export function requireBundledChannelPlugin(id: ChannelId): ChannelPlugin {
|
||||
const plugin = getBundledChannelPlugin(id);
|
||||
if (!plugin) {
|
||||
|
||||
@@ -32,6 +32,7 @@ type DefineBundledChannelEntryOptions<TPlugin = ChannelPlugin> = {
|
||||
description: string;
|
||||
importMetaUrl: string;
|
||||
plugin: BundledEntryModuleRef;
|
||||
secrets?: BundledEntryModuleRef;
|
||||
configSchema?: ChannelEntryConfigSchema<TPlugin> | (() => ChannelEntryConfigSchema<TPlugin>);
|
||||
runtime?: BundledEntryModuleRef;
|
||||
registerCliMetadata?: (api: OpenClawPluginApi) => void;
|
||||
@@ -41,6 +42,7 @@ type DefineBundledChannelEntryOptions<TPlugin = ChannelPlugin> = {
|
||||
type DefineBundledChannelSetupEntryOptions = {
|
||||
importMetaUrl: string;
|
||||
plugin: BundledEntryModuleRef;
|
||||
secrets?: BundledEntryModuleRef;
|
||||
};
|
||||
|
||||
export type BundledChannelEntryContract<TPlugin = ChannelPlugin> = {
|
||||
@@ -51,12 +53,14 @@ export type BundledChannelEntryContract<TPlugin = ChannelPlugin> = {
|
||||
configSchema: ChannelEntryConfigSchema<TPlugin>;
|
||||
register: (api: OpenClawPluginApi) => void;
|
||||
loadChannelPlugin: () => TPlugin;
|
||||
loadChannelSecrets?: () => ChannelPlugin["secrets"] | undefined;
|
||||
setChannelRuntime?: (runtime: PluginRuntime) => void;
|
||||
};
|
||||
|
||||
export type BundledChannelSetupEntryContract<TPlugin = ChannelPlugin> = {
|
||||
kind: "bundled-channel-setup-entry";
|
||||
loadSetupPlugin: () => TPlugin;
|
||||
loadSetupSecrets?: () => ChannelPlugin["secrets"] | undefined;
|
||||
};
|
||||
|
||||
const nodeRequire = createRequire(import.meta.url);
|
||||
@@ -172,6 +176,7 @@ export function defineBundledChannelEntry<TPlugin = ChannelPlugin>({
|
||||
description,
|
||||
importMetaUrl,
|
||||
plugin,
|
||||
secrets,
|
||||
configSchema,
|
||||
runtime,
|
||||
registerCliMetadata,
|
||||
@@ -182,6 +187,9 @@ export function defineBundledChannelEntry<TPlugin = ChannelPlugin>({
|
||||
? configSchema()
|
||||
: ((configSchema ?? emptyChannelConfigSchema()) as ChannelEntryConfigSchema<TPlugin>);
|
||||
const loadChannelPlugin = () => loadBundledEntryExportSync<TPlugin>(importMetaUrl, plugin);
|
||||
const loadChannelSecrets = secrets
|
||||
? () => loadBundledEntryExportSync<ChannelPlugin["secrets"] | undefined>(importMetaUrl, secrets)
|
||||
: undefined;
|
||||
const setChannelRuntime = runtime
|
||||
? (pluginRuntime: PluginRuntime) => {
|
||||
const setter = loadBundledEntryExportSync<(runtime: PluginRuntime) => void>(
|
||||
@@ -212,6 +220,7 @@ export function defineBundledChannelEntry<TPlugin = ChannelPlugin>({
|
||||
registerFull?.(api);
|
||||
},
|
||||
loadChannelPlugin,
|
||||
...(loadChannelSecrets ? { loadChannelSecrets } : {}),
|
||||
...(setChannelRuntime ? { setChannelRuntime } : {}),
|
||||
};
|
||||
}
|
||||
@@ -219,9 +228,19 @@ export function defineBundledChannelEntry<TPlugin = ChannelPlugin>({
|
||||
export function defineBundledChannelSetupEntry<TPlugin = ChannelPlugin>({
|
||||
importMetaUrl,
|
||||
plugin,
|
||||
secrets,
|
||||
}: DefineBundledChannelSetupEntryOptions): BundledChannelSetupEntryContract<TPlugin> {
|
||||
return {
|
||||
kind: "bundled-channel-setup-entry",
|
||||
loadSetupPlugin: () => loadBundledEntryExportSync<TPlugin>(importMetaUrl, plugin),
|
||||
...(secrets
|
||||
? {
|
||||
loadSetupSecrets: () =>
|
||||
loadBundledEntryExportSync<ChannelPlugin["secrets"] | undefined>(
|
||||
importMetaUrl,
|
||||
secrets,
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getBootstrapChannelPlugin } from "../channels/plugins/bootstrap-registry.js";
|
||||
import { getBootstrapChannelSecrets } from "../channels/plugins/bootstrap-registry.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { type ResolverContext, type SecretDefaults } from "./runtime-shared.js";
|
||||
|
||||
@@ -12,10 +12,10 @@ export function collectChannelConfigAssignments(params: {
|
||||
return;
|
||||
}
|
||||
for (const channelId of channelIds) {
|
||||
const plugin = getBootstrapChannelPlugin(channelId);
|
||||
if (!plugin) {
|
||||
const secrets = getBootstrapChannelSecrets(channelId);
|
||||
if (!secrets) {
|
||||
continue;
|
||||
}
|
||||
plugin.secrets?.collectRuntimeConfigAssignments?.(params);
|
||||
secrets.collectRuntimeConfigAssignments?.(params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,12 +50,14 @@ function loadCoverageRegistryEntries(): SecretRegistryEntry[] {
|
||||
}
|
||||
|
||||
const COVERAGE_REGISTRY_ENTRIES = loadCoverageRegistryEntries();
|
||||
const DEBUG_COVERAGE_BATCHES = process.env.OPENCLAW_DEBUG_RUNTIME_COVERAGE === "1";
|
||||
|
||||
let applyResolvedAssignments: typeof import("./runtime-shared.js").applyResolvedAssignments;
|
||||
let collectAuthStoreAssignments: typeof import("./runtime-auth-collectors.js").collectAuthStoreAssignments;
|
||||
let collectConfigAssignments: typeof import("./runtime-config-collectors.js").collectConfigAssignments;
|
||||
let createResolverContext: typeof import("./runtime-shared.js").createResolverContext;
|
||||
let resolveSecretRefValues: typeof import("./resolve.js").resolveSecretRefValues;
|
||||
let resolveRuntimeWebTools: typeof import("./runtime-web-tools.js").resolveRuntimeWebTools;
|
||||
|
||||
function toConcretePathSegments(pathPattern: string, wildcardToken = "sample"): string[] {
|
||||
const segments = pathPattern.split(".").filter(Boolean);
|
||||
@@ -75,7 +77,8 @@ function toConcretePathSegments(pathPattern: string, wildcardToken = "sample"):
|
||||
}
|
||||
|
||||
function resolveCoverageEnvId(entry: SecretRegistryEntry, fallbackEnvId: string): string {
|
||||
return entry.id === "plugins.entries.firecrawl.config.webFetch.apiKey"
|
||||
return entry.id === "plugins.entries.firecrawl.config.webFetch.apiKey" ||
|
||||
entry.id === "tools.web.fetch.firecrawl.apiKey"
|
||||
? "FIRECRAWL_API_KEY"
|
||||
: fallbackEnvId;
|
||||
}
|
||||
@@ -126,11 +129,15 @@ function resolveCoverageBatchKey(entry: SecretRegistryEntry): string {
|
||||
}
|
||||
if (entry.id.startsWith("channels.")) {
|
||||
const segments = entry.id.split(".");
|
||||
const channelId = segments[1] ?? "unknown";
|
||||
const field = segments.at(-1);
|
||||
if (field === "accessToken" || field === "password") {
|
||||
if (
|
||||
field === "accessToken" ||
|
||||
field === "password" ||
|
||||
(channelId === "slack" && field === "signingSecret")
|
||||
) {
|
||||
return entry.id;
|
||||
}
|
||||
const channelId = segments[1] ?? "unknown";
|
||||
const scope = segments[2] === "accounts" ? "accounts" : "root";
|
||||
return `channels.${channelId}.${scope}`;
|
||||
}
|
||||
@@ -169,6 +176,15 @@ function buildCoverageBatches(entries: readonly SecretRegistryEntry[]): SecretRe
|
||||
return [...batches.values()];
|
||||
}
|
||||
|
||||
function logCoverageBatch(label: string, batch: readonly SecretRegistryEntry[]): void {
|
||||
if (!DEBUG_COVERAGE_BATCHES || batch.length === 0) {
|
||||
return;
|
||||
}
|
||||
process.stderr.write(
|
||||
`[runtime.coverage] ${label} batch (${batch.length}): ${batch.map((entry) => entry.id).join(", ")}\n`,
|
||||
);
|
||||
}
|
||||
|
||||
function applyConfigForOpenClawTarget(
|
||||
config: OpenClawConfig,
|
||||
entry: SecretRegistryEntry,
|
||||
@@ -193,6 +209,12 @@ function applyConfigForOpenClawTarget(
|
||||
);
|
||||
setPathCreateStrict(config, ["models", "providers", wildcardToken, "models"], []);
|
||||
}
|
||||
if (entry.id.startsWith("plugins.entries.")) {
|
||||
const pluginId = entry.id.split(".")[2];
|
||||
if (pluginId) {
|
||||
setPathCreateStrict(config, ["plugins", "entries", pluginId, "enabled"], true);
|
||||
}
|
||||
}
|
||||
if (entry.id === "agents.defaults.memorySearch.remote.apiKey") {
|
||||
setPathCreateStrict(config, ["agents", "list", "0", "id"], "sample-agent");
|
||||
}
|
||||
@@ -382,6 +404,12 @@ async function prepareCoverageSnapshot(params: {
|
||||
});
|
||||
}
|
||||
|
||||
await resolveRuntimeWebTools({
|
||||
sourceConfig,
|
||||
resolvedConfig,
|
||||
context,
|
||||
});
|
||||
|
||||
return {
|
||||
config: resolvedConfig,
|
||||
authStores,
|
||||
@@ -391,16 +419,20 @@ async function prepareCoverageSnapshot(params: {
|
||||
|
||||
describe("secrets runtime target coverage", () => {
|
||||
beforeAll(async () => {
|
||||
const [sharedRuntime, authCollectors, configCollectors, resolver] = await Promise.all([
|
||||
import("./runtime-shared.js"),
|
||||
import("./runtime-auth-collectors.js"),
|
||||
import("./runtime-config-collectors.js"),
|
||||
import("./resolve.js"),
|
||||
]);
|
||||
const [sharedRuntime, authCollectors, configCollectors, resolver, webTools] = await Promise.all(
|
||||
[
|
||||
import("./runtime-shared.js"),
|
||||
import("./runtime-auth-collectors.js"),
|
||||
import("./runtime-config-collectors.js"),
|
||||
import("./resolve.js"),
|
||||
import("./runtime-web-tools.js"),
|
||||
],
|
||||
);
|
||||
({ applyResolvedAssignments, createResolverContext } = sharedRuntime);
|
||||
({ collectAuthStoreAssignments } = authCollectors);
|
||||
({ collectConfigAssignments } = configCollectors);
|
||||
({ resolveSecretRefValues } = resolver);
|
||||
({ resolveRuntimeWebTools } = webTools);
|
||||
});
|
||||
|
||||
it("handles every openclaw.json registry target when configured as active", async () => {
|
||||
@@ -408,6 +440,7 @@ describe("secrets runtime target coverage", () => {
|
||||
(entry) => entry.configFile === "openclaw.json",
|
||||
);
|
||||
for (const batch of buildCoverageBatches(entries)) {
|
||||
logCoverageBatch("openclaw.json", batch);
|
||||
const config = {} as OpenClawConfig;
|
||||
const env: Record<string, string> = {};
|
||||
for (const [index, entry] of batch.entries()) {
|
||||
@@ -440,6 +473,7 @@ describe("secrets runtime target coverage", () => {
|
||||
(entry) => entry.configFile === "auth-profiles.json",
|
||||
);
|
||||
for (const batch of buildCoverageBatches(entries)) {
|
||||
logCoverageBatch("auth-profiles.json", batch);
|
||||
const env: Record<string, string> = {};
|
||||
const authStore: AuthProfileStore = {
|
||||
version: 1,
|
||||
|
||||
@@ -2,5 +2,8 @@ export function canonicalizeSecretTargetCoverageId(id: string): string {
|
||||
if (id === "tools.web.x_search.apiKey") {
|
||||
return "plugins.entries.xai.config.webSearch.apiKey";
|
||||
}
|
||||
if (id === "tools.web.fetch.firecrawl.apiKey") {
|
||||
return "plugins.entries.firecrawl.config.webFetch.apiKey";
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user