import { Module } from "@nestjs/common"; import { withTenant } from "../db/client.js"; import { LiveDestinationController } from "./live-destination.controller.js"; import { LiveDestinationRepository, LIVE_DESTINATION_DEPENDENCIES, type TenantTransaction } from "./live-destination.repository.js"; import { GoLiveService, GO_LIVE_DEPENDENCIES } from "./go-live.service.js"; import { StreamOutputController } from "./stream-output.controller.js"; import { createPublishingRegistry } from "@tactical-media-broadcast-hub/connector-runtime"; import { pool } from "../db/client.js"; /** Registers connector-level live source resolvers from the connector registry. */ function registerSourceResolvers(goLive: GoLiveService): void { // Registry pattern: the provider set comes from the publishing registry — // connector packages (twitch et al.) own provider behaviour, so every // connector implementing resolveLiveSource registers under its own manifest // id; generic-hls resolves through the built-in prober. No provider names // branch here. if (process.env.DATABASE_URL === undefined) return; try { const registry = createPublishingRegistry(pool); for (const connector of registry.list()) { const { id } = connector.manifest(); if (connector.resolveLiveSource === undefined) continue; const resolveLiveSource = connector.resolveLiveSource.bind(connector); goLive.registerSourceResolver(id, async (request) => resolveLiveSource( { id: `${id}:live-source`, workspaceId: "live-source", provider: id, channelId: request.channelId ?? request.externalUrl ?? "", credentialId: { kind: "credential-ref", id: `${id}:live-source` }, fields: {}, createdAt: new Date(), }, request, )); } } catch { /* No connectors configured in this process: only generic-hls stays registered. */ } } @Module({ controllers: [LiveDestinationController, StreamOutputController], providers: [ { provide: "STREAM_OUTPUT_TRANSACTION", useValue: withTenant satisfies TenantTransaction }, { provide: LiveDestinationRepository, useFactory: (dependencies?: unknown) => new LiveDestinationRepository(dependencies as never), inject: [{ token: LIVE_DESTINATION_DEPENDENCIES, optional: true }], }, { provide: GoLiveService, useFactory: (destinations: LiveDestinationRepository, dependencies?: unknown) => { const service = new GoLiveService(destinations, dependencies as never); registerSourceResolvers(service); return service; }, inject: [LiveDestinationRepository, { token: GO_LIVE_DEPENDENCIES, optional: true }], }, ], exports: [LiveDestinationRepository, GoLiveService], }) export class LiveModule {}