import { NexusError } from '../shared/errors.js'; import type { Capability, MediaProvider, SearchProvider, SttProvider } from './types.js'; /** * Registry maps a provider name + capability to the concrete adapter. * Adding RouterAI / GPTunnel / OpenRouter / cloud STT means registering a new * adapter here — no changes needed in the MCP tool layer. */ export class ProviderRegistry { private media = new Map(); private search = new Map(); private stt = new Map(); registerMedia(provider: MediaProvider): void { this.media.set(provider.name, provider); } registerSearch(provider: SearchProvider): void { this.search.set(provider.name, provider); } registerStt(provider: SttProvider): void { this.stt.set(provider.name, provider); } getMedia(name: string, capability: Capability): MediaProvider { const p = this.media.get(name); if (!p) { throw new NexusError( 'UNSUPPORTED', `Unknown media provider "${name}". Available: ${[...this.media.keys()].join(', ') || 'none'}` ); } if (!p.capabilities.includes(capability)) { throw new NexusError( 'UNSUPPORTED', `Provider "${name}" does not support capability "${capability}"` ); } return p; } getSearch(name: string): SearchProvider { const p = this.search.get(name); if (!p) { throw new NexusError( 'UNSUPPORTED', `Unknown search provider "${name}". Available: ${[...this.search.keys()].join(', ') || 'none'}` ); } return p; } getStt(name: string): SttProvider { const p = this.stt.get(name); if (!p) { throw new NexusError( 'UNSUPPORTED', `Unknown STT provider "${name}". Available: ${[...this.stt.keys()].join(', ') || 'none'}` ); } return p; } listMediaProviders(): string[] { return [...this.media.keys()]; } listSearchProviders(): string[] { return [...this.search.keys()]; } listSttProviders(): string[] { return [...this.stt.keys()]; } }