import { isTruthyEnvValue } from "../infra/env.js"; import { toSafeImportPath } from "./import-specifier.js"; type LazyServiceModule = Record; export type LazyPluginServiceHandle = { stop: () => Promise; }; // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic service exports are typed by the caller. function resolveExport(mod: LazyServiceModule, names: string[]): T | null { for (const name of names) { const value = mod[name]; if (typeof value === "function") { return value as T; } } return null; } export async function defaultLoadOverrideModule( specifier: string, importModule: (specifier: string) => Promise = async (source: string) => await import(source), ): Promise { return importModule(toSafeImportPath(specifier)); } export async function startLazyPluginServiceModule(params: { skipEnvVar?: string; overrideEnvVar?: string; validateOverrideSpecifier?: (specifier: string) => string; loadDefaultModule: () => Promise; loadOverrideModule?: (specifier: string) => Promise; startExportNames: string[]; stopExportNames?: string[]; }): Promise { const skipEnvVar = params.skipEnvVar?.trim(); if (skipEnvVar && isTruthyEnvValue(process.env[skipEnvVar])) { return null; } const overrideEnvVar = params.overrideEnvVar?.trim(); const override = overrideEnvVar ? process.env[overrideEnvVar]?.trim() : undefined; const loadOverrideModule = params.loadOverrideModule ?? defaultLoadOverrideModule; const validatedOverride = override && params.validateOverrideSpecifier ? params.validateOverrideSpecifier(override) : override; const mod = validatedOverride ? await loadOverrideModule(validatedOverride) : await params.loadDefaultModule(); const start = resolveExport<() => Promise>(mod, params.startExportNames); if (!start) { return null; } const stop = params.stopExportNames && params.stopExportNames.length > 0 ? resolveExport<() => Promise>(mod, params.stopExportNames) : null; await start(); return { stop: stop ?? (async () => {}), }; }