import type { ConcreteNetwork } from "@fetcha/core"; import { DecodoProvider } from "./decodo"; import { DirectProvider } from "./direct"; import { OxylabsProvider } from "./oxylabs"; import { SoaxProvider } from "./soax"; import type { ProviderId, ProxyProvider } from "./types"; export * from "./types"; export { OxylabsProvider } from "./oxylabs"; export { DecodoProvider } from "./decodo"; export { SoaxProvider } from "./soax"; export { DirectProvider } from "./direct"; export { closeAllDispatchers } from "./http"; export * from "./fingerprint"; export * from "./cookies"; export interface ProviderRegistryOptions { env?: NodeJS.ProcessEnv; /** Per-provider per-network price overrides (USD/GB), typically loaded from `provider_configs`. */ prices?: Partial>>; /** Providers disabled by the admin. */ disabled?: ProviderId[]; } export class ProviderRegistry { private readonly providers = new Map(); private readonly disabled: Set; constructor(opts: ProviderRegistryOptions = {}) { const env = opts.env ?? process.env; const p = opts.prices ?? {}; this.disabled = new Set(opts.disabled ?? []); for (const provider of [new OxylabsProvider(env, p.oxylabs), new DecodoProvider(env, p.decodo), new SoaxProvider(env, p.soax), new DirectProvider(env)]) { this.providers.set(provider.id, provider); } } get(id: ProviderId): ProxyProvider | undefined { return this.providers.get(id); } all(): ProxyProvider[] { return [...this.providers.values()]; } /** Providers that are configured, enabled, and can serve `network`. */ available(network?: ConcreteNetwork): ProxyProvider[] { return this.all().filter((p) => p.isConfigured() && !this.disabled.has(p.id) && (!network || p.networks.includes(network))); } /** Network classes the platform can actually serve right now. */ availableNetworks(): ConcreteNetwork[] { const set = new Set(); for (const p of this.available()) for (const n of p.networks) set.add(n); return [...set]; } setDisabled(id: ProviderId, disabled: boolean): void { if (disabled) this.disabled.add(id); else this.disabled.delete(id); } } /** Customer-facing display names for network classes. */ export const NETWORK_LABELS: Record = { datacenter: "Datacenter", residential: "Residential", isp: "ISP", mobile: "Mobile", direct: "Datacenter", };