export type RuntimeToolAuthScopeDigestResolver = (( toolId: string, ) => Promise) & { invalidate: (toolId?: string | null) => void; }; export type RuntimeToolAuthScopeDigestFetcher = ( normalizedToolId: string, ) => Promise; const DEFAULT_AUTH_SCOPE_RETRY_DELAYS_MS = [100, 250] as const; function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } export function createRuntimeToolAuthScopeDigestResolver(input: { fetchDigest: RuntimeToolAuthScopeDigestFetcher; missingToolIdMessage?: string; retryDelaysMs?: readonly number[]; sleepMs?: (ms: number) => Promise; }): RuntimeToolAuthScopeDigestResolver { const resolved = new Map(); const inFlight = new Map>(); const retryDelaysMs = input.retryDelaysMs ?? DEFAULT_AUTH_SCOPE_RETRY_DELAYS_MS; const sleepMs = input.sleepMs ?? sleep; const resolver = async (toolId: string): Promise => { const normalizedToolId = String(toolId || '').trim(); if (!normalizedToolId) { throw new Error( input.missingToolIdMessage ?? 'Runtime auth scope lookup needs tool id.', ); } const cachedDigest = resolved.get(normalizedToolId); if (cachedDigest !== undefined) { return cachedDigest; } const cachedPromise = inFlight.get(normalizedToolId); if (cachedPromise) { return await cachedPromise; } const promise = (async () => { let lastError: unknown = null; const maxAttempts = retryDelaysMs.length + 1; for (let attempt = 1; attempt <= maxAttempts; attempt += 1) { try { const digest = (await input.fetchDigest(normalizedToolId)).trim(); if (!digest) { throw new Error( `Runtime auth scope lookup for tool ${normalizedToolId} returned no digest.`, ); } resolved.set(normalizedToolId, digest); return digest; } catch (error) { lastError = error; if (attempt >= maxAttempts) { throw error; } await sleepMs(retryDelaysMs[attempt - 1] ?? 250); } } throw lastError instanceof Error ? lastError : new Error(String(lastError)); })(); inFlight.set(normalizedToolId, promise); try { return await promise; } finally { inFlight.delete(normalizedToolId); } }; resolver.invalidate = (toolId?: string | null): void => { const normalizedToolId = String(toolId || '').trim(); if (!normalizedToolId) { resolved.clear(); inFlight.clear(); return; } resolved.delete(normalizedToolId); inFlight.delete(normalizedToolId); }; return resolver; }