import { sendNodecgCommand, sendNodecgMessage } from '../../nodecg/browser/messages'; import { createPackBrowserReplicants } from '../../nodecg/browser/packReplicants'; import { messageNames } from '../../nodecg/messageNames'; import type { PackDownloadState, PackManifest, PackRegistry, PackUpdateInfo, } from '../../shared/domain/packs/types'; export interface PackReplicantHandlers { onRegistryChanged: (value: PackRegistry | null) => void; onInstalledPacksChanged: (value: string[], previousValue: string[]) => void; onDownloadStatesChanged: (value: Record) => void; onAvailableUpdatesChanged: (value: Record) => void; } export interface PackService { subscribe: (handlers: PackReplicantHandlers) => Promise<() => void>; fetchRegistry: () => Promise; downloadPack: (packId: string) => Promise; uninstallPack: (packId: string) => Promise; updatePack: (packId: string) => Promise; readLocalManifest: (packId: string) => Promise; } export const createPackService = (): PackService => { const subscribe = async (handlers: PackReplicantHandlers): Promise<() => void> => { const { registryRep, installedRep, statesRep, updatesRep, waitUntilReady, } = createPackBrowserReplicants(); await waitUntilReady(); handlers.onRegistryChanged(registryRep.value ?? null); handlers.onInstalledPacksChanged(installedRep.value ?? [], []); handlers.onDownloadStatesChanged(statesRep.value ?? {}); handlers.onAvailableUpdatesChanged(updatesRep.value ?? {}); const onRegistryChanged = (value: PackRegistry | null): void => { handlers.onRegistryChanged(value ?? null); }; const onInstalledPacksChanged = (value: string[], previousValue?: string[]): void => { handlers.onInstalledPacksChanged(value ?? [], previousValue ?? []); }; const onDownloadStatesChanged = (value: Record): void => { handlers.onDownloadStatesChanged(value ?? {}); }; const onAvailableUpdatesChanged = (value: Record): void => { handlers.onAvailableUpdatesChanged(value ?? {}); }; registryRep.on('change', onRegistryChanged); installedRep.on('change', onInstalledPacksChanged); statesRep.on('change', onDownloadStatesChanged); updatesRep.on('change', onAvailableUpdatesChanged); return () => { registryRep.off('change', onRegistryChanged); installedRep.off('change', onInstalledPacksChanged); statesRep.off('change', onDownloadStatesChanged); updatesRep.off('change', onAvailableUpdatesChanged); }; }; return { subscribe, fetchRegistry: () => sendNodecgCommand(messageNames.packs.fetchRegistry), downloadPack: (packId: string) => sendNodecgCommand(messageNames.packs.download, packId), uninstallPack: (packId: string) => sendNodecgCommand(messageNames.packs.uninstall, packId), updatePack: (packId: string) => sendNodecgCommand(messageNames.packs.update, packId), readLocalManifest: (packId: string) => sendNodecgMessage(messageNames.packs.readLocalManifest, packId), }; };