import { mkdirSync } from "node:fs"; import { tmpdir } from "node:os"; const RETRIABLE_IMPORT_ERROR_CODES = new Set([ "ENOENT", "EACCES", "EPERM", "EBUSY", "EMFILE", "ENFILE", "ENOTDIR", "ERR_MODULE_NOT_FOUND", ]); export function isRetriableImportError(error: unknown): boolean { if (error instanceof Error && "code" in error) { const code = (error as { code?: unknown }).code; if (typeof code === "string" && RETRIABLE_IMPORT_ERROR_CODES.has(code)) { return true; } } const message = error instanceof Error ? error.message : String(error); return /no such file or directory/i.test(message); } function ensureJitiFallbackDir(): void { try { mkdirSync(`${tmpdir()}/jiti`, { recursive: true }); } catch { // Ignore; the runtime loader is responsible for its own cache directory. } } export interface ModuleCache { module?: T; promise?: Promise; } export type ModuleImporter = (specifier: string) => Promise; export async function tryImportWithRetry( specifier: string, maxRetries: number, tryImport: ModuleImporter, ): Promise { let lastError: unknown; for (let attempt = 0; attempt <= maxRetries; attempt += 1) { try { const url = attempt === 0 ? specifier : `${specifier}?__sensitive_guard_retry=${attempt}`; return (await tryImport(url)) as T; } catch (error) { lastError = error; if (!isRetriableImportError(error) || attempt === maxRetries) { throw error; } ensureJitiFallbackDir(); await new Promise((resolve) => { setTimeout(resolve, 50 * attempt); }); } } throw lastError; } export async function importWithRetry( specifier: string, maxRetries = 2, ): Promise { return tryImportWithRetry(specifier, maxRetries, (url) => import(url)); } export function loadCachedModule( specifier: string, cache: ModuleCache, maxRetries = 2, tryImport?: ModuleImporter, ): Promise { if (cache.module) { return Promise.resolve(cache.module); } if (cache.promise) { return cache.promise; } const loadPromise = tryImport ? tryImportWithRetry(specifier, maxRetries, tryImport) : importWithRetry(specifier, maxRetries); cache.promise = loadPromise.then((module) => { cache.module = module; return module; }); return cache.promise; }