import fs from "node:fs"; import path from "node:path"; import { getRuntimeConfig } from "../../config/config.js"; import { resolveBundledRuntimeDependencyJitiAliasMap } from "../bundled-runtime-deps-jiti-aliases.js"; import { getCachedPluginJitiLoader, type PluginJitiLoaderCache } from "../jiti-loader-cache.js"; import { loadPluginManifestRegistry } from "../manifest-registry.js"; import { buildPluginLoaderAliasMap, shouldPreferNativeJiti } from "../sdk-alias.js"; type PluginRuntimeRecord = { origin?: string; rootDir?: string; source: string; }; export function readPluginBoundaryConfigSafely() { try { return getRuntimeConfig(); } catch { return {}; } } export function resolvePluginRuntimeRecord( pluginId: string, onMissing?: () => never, ): PluginRuntimeRecord | null { const manifestRegistry = loadPluginManifestRegistry({ config: readPluginBoundaryConfigSafely(), }); const record = manifestRegistry.plugins.find((plugin) => plugin.id === pluginId); if (!record?.source) { if (onMissing) { onMissing(); } return null; } return { ...(record.origin ? { origin: record.origin } : {}), rootDir: record.rootDir, source: record.source, }; } export function resolvePluginRuntimeRecordByEntryBaseNames( entryBaseNames: string[], onMissing?: () => never, ): PluginRuntimeRecord | null { const manifestRegistry = loadPluginManifestRegistry({ config: readPluginBoundaryConfigSafely(), }); const matches = manifestRegistry.plugins.filter((plugin) => { if (!plugin?.source) { return false; } const record = { rootDir: plugin.rootDir, source: plugin.source, }; return entryBaseNames.every( (entryBaseName) => resolvePluginRuntimeModulePath(record, entryBaseName) !== null, ); }); if (matches.length === 0) { if (onMissing) { onMissing(); } return null; } if (matches.length > 1) { const pluginIds = matches.map((plugin) => plugin.id).join(", "); throw new Error( `plugin runtime boundary is ambiguous for entries [${entryBaseNames.join(", ")}]: ${pluginIds}`, ); } const record = matches[0]; return { ...(record.origin ? { origin: record.origin } : {}), rootDir: record.rootDir, source: record.source, }; } export function resolvePluginRuntimeModulePath( record: Pick, entryBaseName: string, onMissing?: () => never, ): string | null { const candidates = [ path.join(path.dirname(record.source), `${entryBaseName}.js`), path.join(path.dirname(record.source), `${entryBaseName}.ts`), ...(record.rootDir ? [ path.join(record.rootDir, `${entryBaseName}.js`), path.join(record.rootDir, `${entryBaseName}.ts`), ] : []), ]; for (const candidate of candidates) { if (fs.existsSync(candidate)) { return candidate; } } if (onMissing) { onMissing(); } return null; } export function getPluginBoundaryJiti(modulePath: string, loaders: PluginJitiLoaderCache) { const tryNative = shouldPreferNativeJiti(modulePath); const runtimeAliasMap = resolveBundledRuntimeDependencyJitiAliasMap(); return getCachedPluginJitiLoader({ cache: loaders, modulePath, importerUrl: import.meta.url, jitiFilename: import.meta.url, ...(runtimeAliasMap ? { aliasMap: { ...buildPluginLoaderAliasMap(modulePath, process.argv[1], import.meta.url), ...runtimeAliasMap, }, } : {}), tryNative, }); } // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Dynamic plugin boundary loaders use caller-supplied module types. export function loadPluginBoundaryModuleWithJiti( modulePath: string, loaders: PluginJitiLoaderCache, ): TModule { return getPluginBoundaryJiti(modulePath, loaders)(modulePath) as TModule; }