// Wires capture/media.ts's manifest detection to the content scripts, and answers the // two calls the in-page video panel needs (media.listVariants, media.addVariant). A // separate, simpler channel from bridge.ts's port because content scripts are per-tab // and use one-shot runtime.sendMessage rather than a long-lived port. import type { MediaAddVariantParams, MediaListVariantsParams } from '../shared/protocol/index.js'; import type { VeloxTransport } from './transport/index.js'; import type { DetectedManifest } from './capture/media.js'; export type ContentMessage = | { type: 'velox-list-variants'; params: MediaListVariantsParams } | { type: 'velox-add-variant'; params: MediaAddVariantParams }; export type ManifestDetectedMessage = { type: 'velox-manifest-detected'; url: string; headers: DetectedManifest['headers'] }; export interface TabsLike { sendMessage(tabId: number, message: unknown): Promise; } export interface RuntimeOnMessageLike { addListener(cb: (msg: ContentMessage, sender: unknown, sendResponse: (r: unknown) => void) => boolean | void): void; } /** Tells the tab's content script a manifest was seen, swallowing the "no content * script listening" error a tab without one (or the daemon's own tab) throws. */ export function notifyTab(tabs: TabsLike, manifest: DetectedManifest): void { const message: ManifestDetectedMessage = { type: 'velox-manifest-detected', url: manifest.url, headers: manifest.headers }; tabs.sendMessage(manifest.tabId, message).catch(() => undefined); } export class MediaBridge { constructor(private readonly getTransport: () => VeloxTransport | undefined) {} attach(onMessage: RuntimeOnMessageLike): void { onMessage.addListener((msg, _sender, sendResponse) => { if (msg.type !== 'velox-list-variants' && msg.type !== 'velox-add-variant') return undefined; void this.handle(msg).then(sendResponse); return true; // sendResponse is called asynchronously }); } private async handle(msg: ContentMessage): Promise<{ ok: true; result: unknown } | { ok: false; error: string }> { const t = this.getTransport(); if (!t) return { ok: false, error: 'transport not ready' }; try { const result = msg.type === 'velox-list-variants' ? await t.call('media.listVariants', msg.params) : await t.call('media.addVariant', msg.params); return { ok: true, result }; } catch (e) { return { ok: false, error: e instanceof Error ? e.message : String(e) }; } } }