mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
234 lines
7.2 KiB
TypeScript
234 lines
7.2 KiB
TypeScript
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
|
import { withActivatedPluginIds } from "./activation-context.js";
|
|
import {
|
|
buildPluginSnapshotCacheEnvKey,
|
|
resolvePluginSnapshotCacheTtlMs,
|
|
shouldUsePluginSnapshotCache,
|
|
} from "./cache-controls.js";
|
|
import {
|
|
isPluginRegistryLoadInFlight,
|
|
loadOpenClawPlugins,
|
|
resolveCompatibleRuntimePluginRegistry,
|
|
resolveRuntimePluginRegistry,
|
|
} from "./loader.js";
|
|
import type { PluginLoadOptions } from "./loader.js";
|
|
import type { PluginManifestRecord } from "./manifest-registry.js";
|
|
import type { PluginRegistry } from "./registry.js";
|
|
import { getActivePluginRegistryWorkspaceDir } from "./runtime.js";
|
|
import {
|
|
buildPluginRuntimeLoadOptionsFromValues,
|
|
createPluginRuntimeLoaderLogger,
|
|
} from "./runtime/load-context.js";
|
|
import { buildWebProviderSnapshotCacheKey } from "./web-provider-resolution-shared.js";
|
|
|
|
type WebProviderSnapshotCacheEntry<TEntry> = {
|
|
expiresAt: number;
|
|
providers: TEntry[];
|
|
};
|
|
|
|
export type WebProviderSnapshotCache<TEntry> = WeakMap<
|
|
OpenClawConfig,
|
|
WeakMap<NodeJS.ProcessEnv, Map<string, WebProviderSnapshotCacheEntry<TEntry>>>
|
|
>;
|
|
|
|
export type ResolvePluginWebProvidersParams = {
|
|
config?: PluginLoadOptions["config"];
|
|
workspaceDir?: string;
|
|
env?: PluginLoadOptions["env"];
|
|
bundledAllowlistCompat?: boolean;
|
|
onlyPluginIds?: readonly string[];
|
|
activate?: boolean;
|
|
cache?: boolean;
|
|
mode?: "runtime" | "setup";
|
|
origin?: PluginManifestRecord["origin"];
|
|
};
|
|
|
|
type ResolveWebProviderRuntimeDeps<TEntry> = {
|
|
snapshotCache: WebProviderSnapshotCache<TEntry>;
|
|
resolveBundledResolutionConfig: (params: {
|
|
config?: PluginLoadOptions["config"];
|
|
workspaceDir?: string;
|
|
env?: PluginLoadOptions["env"];
|
|
bundledAllowlistCompat?: boolean;
|
|
}) => {
|
|
config: PluginLoadOptions["config"];
|
|
activationSourceConfig?: PluginLoadOptions["config"];
|
|
autoEnabledReasons: Record<string, string[]>;
|
|
};
|
|
resolveCandidatePluginIds: (params: {
|
|
config?: PluginLoadOptions["config"];
|
|
workspaceDir?: string;
|
|
env?: PluginLoadOptions["env"];
|
|
onlyPluginIds?: readonly string[];
|
|
origin?: PluginManifestRecord["origin"];
|
|
}) => string[] | undefined;
|
|
mapRegistryProviders: (params: {
|
|
registry: PluginRegistry;
|
|
onlyPluginIds?: readonly string[];
|
|
}) => TEntry[];
|
|
};
|
|
|
|
export function createWebProviderSnapshotCache<TEntry>(): WebProviderSnapshotCache<TEntry> {
|
|
return new WeakMap<
|
|
OpenClawConfig,
|
|
WeakMap<NodeJS.ProcessEnv, Map<string, WebProviderSnapshotCacheEntry<TEntry>>>
|
|
>();
|
|
}
|
|
|
|
function resolveWebProviderLoadOptions<TEntry>(
|
|
params: ResolvePluginWebProvidersParams,
|
|
deps: ResolveWebProviderRuntimeDeps<TEntry>,
|
|
) {
|
|
const env = params.env ?? process.env;
|
|
const workspaceDir = params.workspaceDir ?? getActivePluginRegistryWorkspaceDir();
|
|
const { config, activationSourceConfig, autoEnabledReasons } =
|
|
deps.resolveBundledResolutionConfig({
|
|
...params,
|
|
workspaceDir,
|
|
env,
|
|
});
|
|
const onlyPluginIds = deps.resolveCandidatePluginIds({
|
|
config,
|
|
workspaceDir,
|
|
env,
|
|
onlyPluginIds: params.onlyPluginIds,
|
|
origin: params.origin,
|
|
});
|
|
return buildPluginRuntimeLoadOptionsFromValues(
|
|
{
|
|
env,
|
|
config,
|
|
activationSourceConfig,
|
|
autoEnabledReasons,
|
|
workspaceDir,
|
|
logger: createPluginRuntimeLoaderLogger(),
|
|
},
|
|
{
|
|
cache: params.cache ?? false,
|
|
activate: params.activate ?? false,
|
|
...(onlyPluginIds ? { onlyPluginIds } : {}),
|
|
},
|
|
);
|
|
}
|
|
|
|
export function resolvePluginWebProviders<TEntry>(
|
|
params: ResolvePluginWebProvidersParams,
|
|
deps: ResolveWebProviderRuntimeDeps<TEntry>,
|
|
): TEntry[] {
|
|
const env = params.env ?? process.env;
|
|
const workspaceDir = params.workspaceDir ?? getActivePluginRegistryWorkspaceDir();
|
|
if (params.mode === "setup") {
|
|
const pluginIds =
|
|
deps.resolveCandidatePluginIds({
|
|
config: params.config,
|
|
workspaceDir,
|
|
env,
|
|
onlyPluginIds: params.onlyPluginIds,
|
|
origin: params.origin,
|
|
}) ?? [];
|
|
if (pluginIds.length === 0) {
|
|
return [];
|
|
}
|
|
const registry = loadOpenClawPlugins(
|
|
buildPluginRuntimeLoadOptionsFromValues(
|
|
{
|
|
config: withActivatedPluginIds({
|
|
config: params.config,
|
|
pluginIds,
|
|
}),
|
|
activationSourceConfig: params.config,
|
|
autoEnabledReasons: {},
|
|
workspaceDir,
|
|
env,
|
|
logger: createPluginRuntimeLoaderLogger(),
|
|
},
|
|
{
|
|
onlyPluginIds: pluginIds,
|
|
cache: params.cache ?? false,
|
|
activate: params.activate ?? false,
|
|
},
|
|
),
|
|
);
|
|
return deps.mapRegistryProviders({ registry, onlyPluginIds: pluginIds });
|
|
}
|
|
|
|
const cacheOwnerConfig = params.config;
|
|
const shouldMemoizeSnapshot =
|
|
params.activate !== true && params.cache !== true && shouldUsePluginSnapshotCache(env);
|
|
const cacheKey = buildWebProviderSnapshotCacheKey({
|
|
config: cacheOwnerConfig,
|
|
workspaceDir,
|
|
bundledAllowlistCompat: params.bundledAllowlistCompat,
|
|
onlyPluginIds: params.onlyPluginIds,
|
|
origin: params.origin,
|
|
envKey: buildPluginSnapshotCacheEnvKey(env),
|
|
});
|
|
if (cacheOwnerConfig && shouldMemoizeSnapshot) {
|
|
const configCache = deps.snapshotCache.get(cacheOwnerConfig);
|
|
const envCache = configCache?.get(env);
|
|
const cached = envCache?.get(cacheKey);
|
|
if (cached && cached.expiresAt > Date.now()) {
|
|
return cached.providers;
|
|
}
|
|
}
|
|
const memoizeSnapshot = (providers: TEntry[]) => {
|
|
if (!cacheOwnerConfig || !shouldMemoizeSnapshot) {
|
|
return;
|
|
}
|
|
const ttlMs = resolvePluginSnapshotCacheTtlMs(env);
|
|
let configCache = deps.snapshotCache.get(cacheOwnerConfig);
|
|
if (!configCache) {
|
|
configCache = new WeakMap<
|
|
NodeJS.ProcessEnv,
|
|
Map<string, WebProviderSnapshotCacheEntry<TEntry>>
|
|
>();
|
|
deps.snapshotCache.set(cacheOwnerConfig, configCache);
|
|
}
|
|
let envCache = configCache.get(env);
|
|
if (!envCache) {
|
|
envCache = new Map<string, WebProviderSnapshotCacheEntry<TEntry>>();
|
|
configCache.set(env, envCache);
|
|
}
|
|
envCache.set(cacheKey, {
|
|
expiresAt: Date.now() + ttlMs,
|
|
providers,
|
|
});
|
|
};
|
|
|
|
const loadOptions = resolveWebProviderLoadOptions(params, deps);
|
|
const compatible = resolveCompatibleRuntimePluginRegistry(loadOptions);
|
|
if (compatible) {
|
|
const resolved = deps.mapRegistryProviders({
|
|
registry: compatible,
|
|
onlyPluginIds: params.onlyPluginIds,
|
|
});
|
|
memoizeSnapshot(resolved);
|
|
return resolved;
|
|
}
|
|
if (isPluginRegistryLoadInFlight(loadOptions)) {
|
|
return [];
|
|
}
|
|
const resolved = deps.mapRegistryProviders({
|
|
registry: loadOpenClawPlugins(loadOptions),
|
|
onlyPluginIds: params.onlyPluginIds,
|
|
});
|
|
memoizeSnapshot(resolved);
|
|
return resolved;
|
|
}
|
|
|
|
export function resolveRuntimeWebProviders<TEntry>(
|
|
params: Omit<ResolvePluginWebProvidersParams, "activate" | "cache" | "mode">,
|
|
deps: ResolveWebProviderRuntimeDeps<TEntry>,
|
|
): TEntry[] {
|
|
const runtimeRegistry = resolveRuntimePluginRegistry(
|
|
params.config === undefined ? undefined : resolveWebProviderLoadOptions(params, deps),
|
|
);
|
|
if (runtimeRegistry) {
|
|
return deps.mapRegistryProviders({
|
|
registry: runtimeRegistry,
|
|
onlyPluginIds: params.onlyPluginIds,
|
|
});
|
|
}
|
|
return resolvePluginWebProviders(params, deps);
|
|
}
|