mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 15:20:44 +00:00
refactor: add plugin lookup table
This commit is contained in:
@@ -20,8 +20,14 @@ const repairBundledRuntimeDepsInstallRootAsync = vi.hoisted(() =>
|
||||
const resolveBundledRuntimeDependencyPackageInstallRoot = vi.hoisted(() =>
|
||||
vi.fn((_packageRoot: string, _params: unknown) => "/runtime"),
|
||||
);
|
||||
const resolveConfiguredDeferredChannelPluginIds = vi.hoisted(() => vi.fn((_params: unknown) => []));
|
||||
const resolveGatewayStartupPluginIds = vi.hoisted(() => vi.fn((_params: unknown) => ["telegram"]));
|
||||
const loadPluginLookUpTable = vi.hoisted(() =>
|
||||
vi.fn((_params: unknown) => ({
|
||||
startup: {
|
||||
configuredDeferredChannelPluginIds: [],
|
||||
pluginIds: ["telegram"],
|
||||
},
|
||||
})),
|
||||
);
|
||||
const resolveOpenClawPackageRootSync = vi.hoisted(() => vi.fn((_params: unknown) => "/package"));
|
||||
const runChannelPluginStartupMaintenance = vi.hoisted(() =>
|
||||
vi.fn(async (_params: unknown) => undefined),
|
||||
@@ -65,10 +71,8 @@ vi.mock("../plugins/bundled-runtime-deps.js", () => ({
|
||||
scanBundledPluginRuntimeDeps: (params: unknown) => scanBundledPluginRuntimeDeps(params),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/channel-plugin-ids.js", () => ({
|
||||
resolveConfiguredDeferredChannelPluginIds: (params: unknown) =>
|
||||
resolveConfiguredDeferredChannelPluginIds(params),
|
||||
resolveGatewayStartupPluginIds: (params: unknown) => resolveGatewayStartupPluginIds(params),
|
||||
vi.mock("../plugins/plugin-lookup-table.js", () => ({
|
||||
loadPluginLookUpTable: (params: unknown) => loadPluginLookUpTable(params),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/registry.js", () => ({
|
||||
@@ -112,8 +116,12 @@ describe("prepareGatewayPluginBootstrap runtime-deps staging", () => {
|
||||
loadGatewayStartupPlugins.mockClear();
|
||||
repairBundledRuntimeDepsInstallRootAsync.mockReset().mockResolvedValue({});
|
||||
resolveBundledRuntimeDependencyPackageInstallRoot.mockClear();
|
||||
resolveConfiguredDeferredChannelPluginIds.mockClear();
|
||||
resolveGatewayStartupPluginIds.mockClear().mockReturnValue(["telegram"]);
|
||||
loadPluginLookUpTable.mockClear().mockReturnValue({
|
||||
startup: {
|
||||
configuredDeferredChannelPluginIds: [],
|
||||
pluginIds: ["telegram"],
|
||||
},
|
||||
});
|
||||
resolveOpenClawPackageRootSync.mockClear().mockReturnValue("/package");
|
||||
runChannelPluginStartupMaintenance.mockClear();
|
||||
runStartupSessionMigration.mockClear();
|
||||
@@ -143,6 +151,7 @@ describe("prepareGatewayPluginBootstrap runtime-deps staging", () => {
|
||||
});
|
||||
|
||||
expect(loadGatewayStartupPlugins).toHaveBeenCalledOnce();
|
||||
expect(loadPluginLookUpTable).toHaveBeenCalledOnce();
|
||||
expect(scanBundledPluginRuntimeDeps).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
selectedPluginIds: ["telegram"],
|
||||
|
||||
@@ -9,10 +9,7 @@ import {
|
||||
resolveBundledRuntimeDependencyPackageInstallRoot,
|
||||
scanBundledPluginRuntimeDeps,
|
||||
} from "../plugins/bundled-runtime-deps.js";
|
||||
import {
|
||||
resolveConfiguredDeferredChannelPluginIds,
|
||||
resolveGatewayStartupPluginIds,
|
||||
} from "../plugins/channel-plugin-ids.js";
|
||||
import { loadPluginLookUpTable } from "../plugins/plugin-lookup-table.js";
|
||||
import { createEmptyPluginRegistry } from "../plugins/registry.js";
|
||||
import { getActivePluginRegistry, setActivePluginRegistry } from "../plugins/runtime.js";
|
||||
import { listGatewayMethods } from "./server-methods-list.js";
|
||||
@@ -139,21 +136,18 @@ export async function prepareGatewayPluginBootstrap(params: {
|
||||
}).config;
|
||||
const defaultAgentId = resolveDefaultAgentId(gatewayPluginConfigAtStart);
|
||||
const defaultWorkspaceDir = resolveAgentWorkspaceDir(gatewayPluginConfigAtStart, defaultAgentId);
|
||||
const deferredConfiguredChannelPluginIds = params.minimalTestGateway
|
||||
? []
|
||||
: resolveConfiguredDeferredChannelPluginIds({
|
||||
config: gatewayPluginConfigAtStart,
|
||||
workspaceDir: defaultWorkspaceDir,
|
||||
env: process.env,
|
||||
});
|
||||
const startupPluginIds = params.minimalTestGateway
|
||||
? []
|
||||
: resolveGatewayStartupPluginIds({
|
||||
const pluginLookUpTable = params.minimalTestGateway
|
||||
? undefined
|
||||
: loadPluginLookUpTable({
|
||||
config: gatewayPluginConfigAtStart,
|
||||
activationSourceConfig: params.cfgAtStart,
|
||||
workspaceDir: defaultWorkspaceDir,
|
||||
env: process.env,
|
||||
});
|
||||
const deferredConfiguredChannelPluginIds = [
|
||||
...(pluginLookUpTable?.startup.configuredDeferredChannelPluginIds ?? []),
|
||||
];
|
||||
const startupPluginIds = [...(pluginLookUpTable?.startup.pluginIds ?? [])];
|
||||
|
||||
const baseMethods = listGatewayMethods();
|
||||
const emptyPluginRegistry = createEmptyPluginRegistry();
|
||||
|
||||
@@ -14,6 +14,9 @@ export {
|
||||
|
||||
export {
|
||||
resolveChannelPluginIds,
|
||||
resolveChannelPluginIdsFromRegistry,
|
||||
resolveConfiguredDeferredChannelPluginIds,
|
||||
resolveConfiguredDeferredChannelPluginIdsFromRegistry,
|
||||
resolveGatewayStartupPluginIds,
|
||||
resolveGatewayStartupPluginIdsFromRegistry,
|
||||
} from "./gateway-startup-plugin-ids.js";
|
||||
|
||||
@@ -190,26 +190,63 @@ export function resolveChannelPluginIds(params: {
|
||||
env: params.env,
|
||||
includeDisabled: true,
|
||||
});
|
||||
return resolveChannelPluginIdsFromRegistry({ manifestRegistry });
|
||||
}
|
||||
|
||||
export function resolveChannelPluginIdsFromRegistry(params: {
|
||||
manifestRegistry: PluginManifestRegistry;
|
||||
}): string[] {
|
||||
const { manifestRegistry } = params;
|
||||
return manifestRegistry.plugins
|
||||
.filter((plugin) => plugin.channels.length > 0)
|
||||
.map((plugin) => plugin.id);
|
||||
}
|
||||
|
||||
export function resolveConfiguredDeferredChannelPluginIdsFromRegistry(params: {
|
||||
config: OpenClawConfig;
|
||||
env: NodeJS.ProcessEnv;
|
||||
index: ReturnType<typeof loadPluginRegistrySnapshot>;
|
||||
manifestRegistry: PluginManifestRegistry;
|
||||
}): string[] {
|
||||
const configuredChannelIds = new Set(listPotentialEnabledChannelIds(params.config, params.env));
|
||||
if (configuredChannelIds.size === 0) {
|
||||
return [];
|
||||
}
|
||||
const pluginsConfig = normalizePluginsConfigWithRegistry(params.config.plugins, params.index);
|
||||
const activationSource = {
|
||||
plugins: pluginsConfig,
|
||||
rootConfig: params.config,
|
||||
};
|
||||
return params.index.plugins
|
||||
.filter(
|
||||
(plugin) =>
|
||||
hasConfiguredStartupChannel({
|
||||
plugin,
|
||||
manifestRegistry: params.manifestRegistry,
|
||||
configuredChannelIds,
|
||||
}) &&
|
||||
plugin.startup.deferConfiguredChannelFullLoadUntilAfterListen &&
|
||||
canStartConfiguredChannelPlugin({
|
||||
plugin,
|
||||
config: params.config,
|
||||
pluginsConfig,
|
||||
activationSource,
|
||||
manifestRegistry: params.manifestRegistry,
|
||||
}),
|
||||
)
|
||||
.map((plugin) => plugin.pluginId);
|
||||
}
|
||||
|
||||
export function resolveConfiguredDeferredChannelPluginIds(params: {
|
||||
config: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
}): string[] {
|
||||
const configuredChannelIds = new Set(listPotentialEnabledChannelIds(params.config, params.env));
|
||||
if (configuredChannelIds.size === 0) {
|
||||
return [];
|
||||
}
|
||||
const index = loadPluginRegistrySnapshot({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
});
|
||||
const pluginsConfig = normalizePluginsConfigWithRegistry(params.config.plugins, index);
|
||||
const manifestRegistry = loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
config: params.config,
|
||||
@@ -217,53 +254,30 @@ export function resolveConfiguredDeferredChannelPluginIds(params: {
|
||||
env: params.env,
|
||||
includeDisabled: true,
|
||||
});
|
||||
const activationSource = {
|
||||
plugins: pluginsConfig,
|
||||
rootConfig: params.config,
|
||||
};
|
||||
return index.plugins
|
||||
.filter(
|
||||
(plugin) =>
|
||||
hasConfiguredStartupChannel({ plugin, manifestRegistry, configuredChannelIds }) &&
|
||||
plugin.startup.deferConfiguredChannelFullLoadUntilAfterListen &&
|
||||
canStartConfiguredChannelPlugin({
|
||||
plugin,
|
||||
config: params.config,
|
||||
pluginsConfig,
|
||||
activationSource,
|
||||
manifestRegistry,
|
||||
}),
|
||||
)
|
||||
.map((plugin) => plugin.pluginId);
|
||||
return resolveConfiguredDeferredChannelPluginIdsFromRegistry({
|
||||
config: params.config,
|
||||
env: params.env,
|
||||
index,
|
||||
manifestRegistry,
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveGatewayStartupPluginIds(params: {
|
||||
export function resolveGatewayStartupPluginIdsFromRegistry(params: {
|
||||
config: OpenClawConfig;
|
||||
activationSourceConfig?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
index: ReturnType<typeof loadPluginRegistrySnapshot>;
|
||||
manifestRegistry: PluginManifestRegistry;
|
||||
}): string[] {
|
||||
const configuredChannelIds = new Set(listPotentialEnabledChannelIds(params.config, params.env));
|
||||
const index = loadPluginRegistrySnapshot({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
});
|
||||
const pluginsConfig = normalizePluginsConfigWithRegistry(params.config.plugins, index);
|
||||
const manifestRegistry = loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
includeDisabled: true,
|
||||
});
|
||||
const pluginsConfig = normalizePluginsConfigWithRegistry(params.config.plugins, params.index);
|
||||
// Startup must classify allowlist exceptions against the raw config snapshot,
|
||||
// not the auto-enabled effective snapshot, or configured-only channels can be
|
||||
// misclassified as explicit enablement.
|
||||
const activationSourceConfig = params.activationSourceConfig ?? params.config;
|
||||
const activationSourcePlugins = normalizePluginsConfigWithRegistry(
|
||||
activationSourceConfig.plugins,
|
||||
index,
|
||||
params.index,
|
||||
);
|
||||
const activationSource = {
|
||||
plugins: activationSourcePlugins,
|
||||
@@ -276,17 +290,23 @@ export function resolveGatewayStartupPluginIds(params: {
|
||||
const memorySlotStartupPluginId = resolveMemorySlotStartupPluginId({
|
||||
activationSourceConfig,
|
||||
activationSourcePlugins,
|
||||
normalizePluginId: createPluginRegistryIdNormalizer(index),
|
||||
normalizePluginId: createPluginRegistryIdNormalizer(params.index),
|
||||
});
|
||||
return index.plugins
|
||||
return params.index.plugins
|
||||
.filter((plugin) => {
|
||||
if (hasConfiguredStartupChannel({ plugin, manifestRegistry, configuredChannelIds })) {
|
||||
if (
|
||||
hasConfiguredStartupChannel({
|
||||
plugin,
|
||||
manifestRegistry: params.manifestRegistry,
|
||||
configuredChannelIds,
|
||||
})
|
||||
) {
|
||||
return canStartConfiguredChannelPlugin({
|
||||
plugin,
|
||||
config: params.config,
|
||||
pluginsConfig,
|
||||
activationSource,
|
||||
manifestRegistry,
|
||||
manifestRegistry: params.manifestRegistry,
|
||||
});
|
||||
}
|
||||
if (
|
||||
@@ -329,3 +349,32 @@ export function resolveGatewayStartupPluginIds(params: {
|
||||
})
|
||||
.map((plugin) => plugin.pluginId);
|
||||
}
|
||||
|
||||
export function resolveGatewayStartupPluginIds(params: {
|
||||
config: OpenClawConfig;
|
||||
activationSourceConfig?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
}): string[] {
|
||||
const index = loadPluginRegistrySnapshot({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
});
|
||||
const manifestRegistry = loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
includeDisabled: true,
|
||||
});
|
||||
return resolveGatewayStartupPluginIdsFromRegistry({
|
||||
config: params.config,
|
||||
...(params.activationSourceConfig !== undefined
|
||||
? { activationSourceConfig: params.activationSourceConfig }
|
||||
: {}),
|
||||
env: params.env,
|
||||
index,
|
||||
manifestRegistry,
|
||||
});
|
||||
}
|
||||
|
||||
139
src/plugins/plugin-lookup-table.test.ts
Normal file
139
src/plugins/plugin-lookup-table.test.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import type { PluginManifestRecord, PluginManifestRegistry } from "./manifest-registry.js";
|
||||
import type { PluginRegistrySnapshot } from "./plugin-registry.js";
|
||||
|
||||
const listPotentialConfiguredChannelIds = vi.hoisted(() => vi.fn());
|
||||
const loadPluginManifestRegistryForInstalledIndex = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../channels/config-presence.js", () => ({
|
||||
hasMeaningfulChannelConfig: (value: unknown) =>
|
||||
Boolean(
|
||||
value &&
|
||||
typeof value === "object" &&
|
||||
!Array.isArray(value) &&
|
||||
Object.keys(value).some((key) => key !== "enabled"),
|
||||
),
|
||||
listPotentialConfiguredChannelIds: (
|
||||
config: OpenClawConfig,
|
||||
env: NodeJS.ProcessEnv,
|
||||
options?: { includePersistedAuthState?: boolean },
|
||||
) => listPotentialConfiguredChannelIds(config, env, options),
|
||||
}));
|
||||
|
||||
vi.mock("./manifest-registry-installed.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("./manifest-registry-installed.js")>();
|
||||
return {
|
||||
...actual,
|
||||
loadPluginManifestRegistryForInstalledIndex: (params: unknown) =>
|
||||
loadPluginManifestRegistryForInstalledIndex(params),
|
||||
};
|
||||
});
|
||||
|
||||
function createManifestRecord(
|
||||
plugin: Partial<PluginManifestRecord> & Pick<PluginManifestRecord, "id" | "origin">,
|
||||
): PluginManifestRecord {
|
||||
return {
|
||||
name: plugin.id,
|
||||
channels: [],
|
||||
providers: [],
|
||||
cliBackends: [],
|
||||
skills: [],
|
||||
hooks: [],
|
||||
rootDir: `/plugins/${plugin.id}`,
|
||||
source: `/plugins/${plugin.id}/index.js`,
|
||||
manifestPath: `/plugins/${plugin.id}/openclaw.plugin.json`,
|
||||
...plugin,
|
||||
};
|
||||
}
|
||||
|
||||
function createIndex(plugins: readonly PluginManifestRecord[]): PluginRegistrySnapshot {
|
||||
return {
|
||||
version: 1,
|
||||
hostContractVersion: "test",
|
||||
compatRegistryVersion: "test",
|
||||
migrationVersion: 1,
|
||||
policyHash: "policy",
|
||||
generatedAtMs: 1,
|
||||
installRecords: {},
|
||||
diagnostics: [],
|
||||
plugins: plugins.map((plugin) => ({
|
||||
pluginId: plugin.id,
|
||||
manifestPath: plugin.manifestPath,
|
||||
manifestHash: `${plugin.id}-hash`,
|
||||
rootDir: plugin.rootDir,
|
||||
origin: plugin.origin,
|
||||
enabled: true,
|
||||
...(plugin.enabledByDefault !== undefined
|
||||
? { enabledByDefault: plugin.enabledByDefault }
|
||||
: {}),
|
||||
startup: {
|
||||
sidecar: false,
|
||||
memory: false,
|
||||
deferConfiguredChannelFullLoadUntilAfterListen: Boolean(
|
||||
plugin.startupDeferConfiguredChannelFullLoadUntilAfterListen,
|
||||
),
|
||||
agentHarnesses: [],
|
||||
},
|
||||
compat: [],
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
describe("loadPluginLookUpTable", () => {
|
||||
beforeEach(() => {
|
||||
listPotentialConfiguredChannelIds
|
||||
.mockReset()
|
||||
.mockImplementation((config: OpenClawConfig) => Object.keys(config.channels ?? {}));
|
||||
loadPluginManifestRegistryForInstalledIndex.mockReset();
|
||||
});
|
||||
|
||||
it("builds owner maps and startup ids from one installed manifest registry", async () => {
|
||||
const plugins = [
|
||||
createManifestRecord({
|
||||
id: "telegram",
|
||||
origin: "bundled",
|
||||
channels: ["telegram"],
|
||||
}),
|
||||
createManifestRecord({
|
||||
id: "openai",
|
||||
origin: "bundled",
|
||||
providers: ["openai"],
|
||||
cliBackends: ["codex-cli"],
|
||||
setup: {
|
||||
providers: [{ id: "openai" }],
|
||||
},
|
||||
}),
|
||||
];
|
||||
const index = createIndex(plugins);
|
||||
const manifestRegistry: PluginManifestRegistry = {
|
||||
plugins,
|
||||
diagnostics: [],
|
||||
};
|
||||
loadPluginManifestRegistryForInstalledIndex.mockReturnValue(manifestRegistry);
|
||||
const { loadPluginLookUpTable } = await import("./plugin-lookup-table.js");
|
||||
|
||||
const table = loadPluginLookUpTable({
|
||||
config: {
|
||||
channels: {
|
||||
telegram: { token: "configured" },
|
||||
},
|
||||
plugins: {
|
||||
slots: { memory: "none" },
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
env: {},
|
||||
index,
|
||||
});
|
||||
|
||||
expect(table.manifestRegistry).toBe(manifestRegistry);
|
||||
expect(table.byPluginId.get("telegram")?.id).toBe("telegram");
|
||||
expect(table.owners.channels.get("telegram")).toEqual(["telegram"]);
|
||||
expect(table.owners.providers.get("openai")).toEqual(["openai"]);
|
||||
expect(table.owners.cliBackends.get("codex-cli")).toEqual(["openai"]);
|
||||
expect(table.owners.setupProviders.get("openai")).toEqual(["openai"]);
|
||||
expect(table.startup.channelPluginIds).toEqual(["telegram"]);
|
||||
expect(table.startup.configuredDeferredChannelPluginIds).toEqual([]);
|
||||
expect(table.startup.pluginIds).toEqual(["telegram"]);
|
||||
});
|
||||
});
|
||||
153
src/plugins/plugin-lookup-table.ts
Normal file
153
src/plugins/plugin-lookup-table.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import {
|
||||
resolveChannelPluginIdsFromRegistry,
|
||||
resolveConfiguredDeferredChannelPluginIdsFromRegistry,
|
||||
resolveGatewayStartupPluginIdsFromRegistry,
|
||||
} from "./channel-plugin-ids.js";
|
||||
import { hashJson } from "./installed-plugin-index-hash.js";
|
||||
import { loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed.js";
|
||||
import type { PluginManifestRecord, PluginManifestRegistry } from "./manifest-registry.js";
|
||||
import type { PluginDiagnostic } from "./manifest-types.js";
|
||||
import {
|
||||
loadPluginRegistrySnapshotWithMetadata,
|
||||
type PluginRegistrySnapshot,
|
||||
type PluginRegistrySnapshotDiagnostic,
|
||||
} from "./plugin-registry.js";
|
||||
|
||||
export type PluginLookUpTableOwnerMaps = {
|
||||
channels: ReadonlyMap<string, readonly string[]>;
|
||||
providers: ReadonlyMap<string, readonly string[]>;
|
||||
cliBackends: ReadonlyMap<string, readonly string[]>;
|
||||
setupProviders: ReadonlyMap<string, readonly string[]>;
|
||||
};
|
||||
|
||||
export type PluginLookUpTableStartupPlan = {
|
||||
channelPluginIds: readonly string[];
|
||||
configuredDeferredChannelPluginIds: readonly string[];
|
||||
pluginIds: readonly string[];
|
||||
};
|
||||
|
||||
export type PluginLookUpTable = {
|
||||
key: string;
|
||||
index: PluginRegistrySnapshot;
|
||||
registryDiagnostics: readonly PluginRegistrySnapshotDiagnostic[];
|
||||
manifestRegistry: PluginManifestRegistry;
|
||||
plugins: readonly PluginManifestRecord[];
|
||||
diagnostics: readonly PluginDiagnostic[];
|
||||
byPluginId: ReadonlyMap<string, PluginManifestRecord>;
|
||||
owners: PluginLookUpTableOwnerMaps;
|
||||
startup: PluginLookUpTableStartupPlan;
|
||||
};
|
||||
|
||||
export type LoadPluginLookUpTableParams = {
|
||||
config: OpenClawConfig;
|
||||
activationSourceConfig?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
index?: PluginRegistrySnapshot;
|
||||
};
|
||||
|
||||
function appendOwner(owners: Map<string, string[]>, ownedId: string, pluginId: string): void {
|
||||
const existing = owners.get(ownedId);
|
||||
if (existing) {
|
||||
existing.push(pluginId);
|
||||
return;
|
||||
}
|
||||
owners.set(ownedId, [pluginId]);
|
||||
}
|
||||
|
||||
function freezeOwnerMap(owners: Map<string, string[]>): ReadonlyMap<string, readonly string[]> {
|
||||
return new Map(
|
||||
[...owners.entries()].map(([ownedId, pluginIds]) => [ownedId, Object.freeze([...pluginIds])]),
|
||||
);
|
||||
}
|
||||
|
||||
function buildOwnerMaps(plugins: readonly PluginManifestRecord[]): PluginLookUpTableOwnerMaps {
|
||||
const channels = new Map<string, string[]>();
|
||||
const providers = new Map<string, string[]>();
|
||||
const cliBackends = new Map<string, string[]>();
|
||||
const setupProviders = new Map<string, string[]>();
|
||||
|
||||
for (const plugin of plugins) {
|
||||
for (const channelId of plugin.channels) {
|
||||
appendOwner(channels, channelId, plugin.id);
|
||||
}
|
||||
for (const providerId of plugin.providers) {
|
||||
appendOwner(providers, providerId, plugin.id);
|
||||
}
|
||||
for (const cliBackendId of plugin.cliBackends) {
|
||||
appendOwner(cliBackends, cliBackendId, plugin.id);
|
||||
}
|
||||
for (const setupProvider of plugin.setup?.providers ?? []) {
|
||||
appendOwner(setupProviders, setupProvider.id, plugin.id);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
channels: freezeOwnerMap(channels),
|
||||
providers: freezeOwnerMap(providers),
|
||||
cliBackends: freezeOwnerMap(cliBackends),
|
||||
setupProviders: freezeOwnerMap(setupProviders),
|
||||
};
|
||||
}
|
||||
|
||||
export function loadPluginLookUpTable(params: LoadPluginLookUpTableParams): PluginLookUpTable {
|
||||
const registryResult = loadPluginRegistrySnapshotWithMetadata({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
...(params.index ? { index: params.index } : {}),
|
||||
});
|
||||
const index = registryResult.snapshot;
|
||||
const manifestRegistry = loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
includeDisabled: true,
|
||||
});
|
||||
const channelPluginIds = resolveChannelPluginIdsFromRegistry({ manifestRegistry });
|
||||
const configuredDeferredChannelPluginIds = resolveConfiguredDeferredChannelPluginIdsFromRegistry({
|
||||
config: params.config,
|
||||
env: params.env,
|
||||
index,
|
||||
manifestRegistry,
|
||||
});
|
||||
const pluginIds = resolveGatewayStartupPluginIdsFromRegistry({
|
||||
config: params.config,
|
||||
...(params.activationSourceConfig !== undefined
|
||||
? { activationSourceConfig: params.activationSourceConfig }
|
||||
: {}),
|
||||
env: params.env,
|
||||
index,
|
||||
manifestRegistry,
|
||||
});
|
||||
const byPluginId = new Map(manifestRegistry.plugins.map((plugin) => [plugin.id, plugin]));
|
||||
const owners = buildOwnerMaps(manifestRegistry.plugins);
|
||||
const startup = {
|
||||
channelPluginIds,
|
||||
configuredDeferredChannelPluginIds,
|
||||
pluginIds,
|
||||
};
|
||||
|
||||
return {
|
||||
key: hashJson({
|
||||
policyHash: index.policyHash,
|
||||
generatedAtMs: index.generatedAtMs,
|
||||
plugins: index.plugins.map((plugin) => [
|
||||
plugin.pluginId,
|
||||
plugin.manifestHash,
|
||||
plugin.installRecordHash,
|
||||
]),
|
||||
startup,
|
||||
}),
|
||||
index,
|
||||
registryDiagnostics: registryResult.diagnostics,
|
||||
manifestRegistry,
|
||||
plugins: manifestRegistry.plugins,
|
||||
diagnostics: [...index.diagnostics, ...manifestRegistry.diagnostics],
|
||||
byPluginId,
|
||||
owners,
|
||||
startup,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user