import type { HousekeepingCapabilityContext, HousekeepingErrorCode, } from "../contracts"; import { createCorrelationId } from "../correlation"; import { type HousekeepingProvider, runProvider } from "./run-provider"; export interface ProviderPolicy { timeoutMs: number; perProviderLimit: number; combinedLimit: number; sort(items: readonly T[]): readonly T[]; dedupeKey(item: T): string; } export interface ProviderBatchResult { items: readonly T[]; errors: readonly { providerId: string; code: HousekeepingErrorCode }[]; correlationId: string; } export async function orchestrateProviders( providers: readonly HousekeepingProvider[], context: HousekeepingCapabilityContext, policy: ProviderPolicy, ): Promise> { const providerResults = await Promise.all( providers.map((provider) => runProvider(provider, context, policy.timeoutMs), ), ); const items: T[] = []; const seen = new Set(); const errors: { providerId: string; code: HousekeepingErrorCode }[] = []; for (const result of providerResults) { if (result.error !== undefined) { errors.push({ providerId: result.providerId, code: result.error }); } for (const item of result.items.slice(0, policy.perProviderLimit)) { if (items.length >= policy.combinedLimit) break; const key = policy.dedupeKey(item); if (seen.has(key)) continue; seen.add(key); items.push(item); } } return { items: policy.sort(items), errors, correlationId: createCorrelationId(), }; }