refactor: unify lazy module loaders

This commit is contained in:
Peter Steinberger
2026-05-02 10:15:16 +01:00
parent 4407c317f3
commit db06fcd990
39 changed files with 408 additions and 264 deletions

View File

@@ -17,6 +17,7 @@ import {
createSafeNpmInstallEnv,
} from "../infra/safe-package-install.js";
import { runCommandWithTimeout } from "../process/exec.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { resolveUserPath } from "../utils.js";
import {
@@ -38,11 +39,10 @@ import { linkOpenClawPeerDependencies } from "./plugin-peer-link.js";
export { resolvePluginInstallDir } from "./install-paths.js";
let pluginInstallRuntimePromise: Promise<typeof import("./install.runtime.js")> | undefined;
const pluginInstallRuntimeLoader = createLazyImportLoader(() => import("./install.runtime.js"));
async function loadPluginInstallRuntime() {
pluginInstallRuntimePromise ??= import("./install.runtime.js");
return pluginInstallRuntimePromise;
return await pluginInstallRuntimeLoader.load();
}
type PluginInstallLogger = {

View File

@@ -1,26 +0,0 @@
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { listPluginContributionIds, loadPluginRegistrySnapshot } from "./plugin-registry.js";
export function listManifestChannelContributionIds(
params: {
config?: OpenClawConfig;
workspaceDir?: string;
env?: NodeJS.ProcessEnv;
includeDisabled?: boolean;
} = {},
): readonly string[] {
const env = params.env ?? process.env;
const index = loadPluginRegistrySnapshot({
config: params.config,
workspaceDir: params.workspaceDir,
env,
});
return listPluginContributionIds({
index,
contribution: "channels",
config: params.config,
workspaceDir: params.workspaceDir,
env,
includeDisabled: params.includeDisabled,
});
}

View File

@@ -0,0 +1,54 @@
import {
listPluginContributionIds,
loadPluginRegistrySnapshot,
type LoadPluginRegistryParams,
type PluginRegistryContributionKey,
type PluginRegistrySnapshot,
} from "./plugin-registry.js";
export type ListManifestContributionIdsParams = LoadPluginRegistryParams & {
contribution: PluginRegistryContributionKey;
index?: PluginRegistrySnapshot;
includeDisabled?: boolean;
};
export function listManifestContributionIds(
params: ListManifestContributionIdsParams,
): readonly string[] {
const env = params.env ?? process.env;
const index =
params.index ??
loadPluginRegistrySnapshot({
config: params.config,
workspaceDir: params.workspaceDir,
env,
candidates: params.candidates,
preferPersisted: params.preferPersisted,
});
return listPluginContributionIds({
index,
contribution: params.contribution,
config: params.config,
workspaceDir: params.workspaceDir,
env,
includeDisabled: params.includeDisabled,
});
}
export function listManifestChannelContributionIds(
params: Omit<ListManifestContributionIdsParams, "contribution"> = {},
): readonly string[] {
return listManifestContributionIds({
...params,
contribution: "channels",
});
}
export function listManifestProviderContributionIds(
params: Omit<ListManifestContributionIdsParams, "contribution"> = {},
): readonly string[] {
return listManifestContributionIds({
...params,
contribution: "providers",
});
}

View File

@@ -9,17 +9,17 @@ import {
isValidFileSecretRefId,
resolveDefaultSecretProviderAlias,
} from "../secrets/ref-contract.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import {
normalizeOptionalString,
normalizeStringifiedOptionalString,
} from "../shared/string-coerce.js";
import type { WizardPrompter } from "../wizard/prompts.js";
let secretResolvePromise: Promise<typeof import("../secrets/resolve.js")> | undefined;
const secretResolveLoader = createLazyImportLoader(() => import("../secrets/resolve.js"));
function loadSecretResolve() {
secretResolvePromise ??= import("../secrets/resolve.js");
return secretResolvePromise;
return secretResolveLoader.load();
}
const ENV_SOURCE_LABEL_RE = /(?:^|:\s)([A-Z][A-Z0-9_]*)$/;

View File

@@ -1,22 +1,20 @@
import { normalizeProviderId } from "../agents/model-selection.js";
import type { ModelProviderConfig } from "../config/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { listManifestProviderContributionIds } from "./manifest-contribution-ids.js";
import type { PluginMetadataRegistryView } from "./plugin-metadata-snapshot.types.js";
import {
listPluginContributionIds,
loadPluginRegistrySnapshot,
type LoadPluginRegistryParams,
type PluginRegistrySnapshot,
} from "./plugin-registry.js";
import { type LoadPluginRegistryParams, type PluginRegistrySnapshot } from "./plugin-registry.js";
import type { ProviderDiscoveryOrder, ProviderPlugin } from "./types.js";
const DISCOVERY_ORDER: readonly ProviderDiscoveryOrder[] = ["simple", "profile", "paired", "late"];
const DANGEROUS_PROVIDER_KEYS = new Set(["__proto__", "prototype", "constructor"]);
let providerRuntimePromise: Promise<typeof import("./provider-discovery.runtime.js")> | undefined;
const providerRuntimeLoader = createLazyImportLoader(
() => import("./provider-discovery.runtime.js"),
);
function loadProviderRuntime() {
providerRuntimePromise ??= import("./provider-discovery.runtime.js");
return providerRuntimePromise;
return providerRuntimeLoader.load();
}
function resolveProviderCatalogHook(provider: ProviderPlugin) {
@@ -62,13 +60,11 @@ export function resolveInstalledPluginProviderContributionIds(
params.candidates && params.preferPersisted === undefined
? { ...params, preferPersisted: false }
: params;
const index = params.index ?? loadPluginRegistrySnapshot(registryParams);
return sortedValues(
listPluginContributionIds({
index,
contribution: "providers",
listManifestProviderContributionIds({
...registryParams,
index: params.index,
includeDisabled: params.includeDisabled,
config: params.config,
}),
);
}

View File

@@ -1,3 +1,5 @@
import { createLazyImportLoader } from "../shared/lazy-promise.js";
type ProviderRuntimeModule = typeof import("./provider-runtime.js");
type AugmentModelCatalogWithProviderPlugins =
@@ -12,13 +14,14 @@ type PrepareProviderRuntimeAuth = ProviderRuntimeModule["prepareProviderRuntimeA
type RefreshProviderOAuthCredentialWithPlugin =
ProviderRuntimeModule["refreshProviderOAuthCredentialWithPlugin"];
let providerRuntimePromise: Promise<ProviderRuntimeModule> | undefined;
const providerRuntimeLoader = createLazyImportLoader<ProviderRuntimeModule>(
() => import("./provider-runtime.js"),
);
async function loadProviderRuntime(): Promise<ProviderRuntimeModule> {
// Keep the heavy provider runtime behind an actual async boundary so callers
// can import this wrapper eagerly without collapsing the lazy chunk.
providerRuntimePromise ??= import("./provider-runtime.js");
return providerRuntimePromise;
return await providerRuntimeLoader.load();
}
export async function augmentModelCatalogWithProviderPlugins(