import { useEffect, useState, useCallback } from 'react'; import * as PulseUpdates from './PulseUpdates'; import type { PulseManifest, UpdateCheckResult, UpdateFetchResult } from './types'; export interface UsePulseUpdatesResult { // State isEnabled: boolean; isChecking: boolean; isDownloading: boolean; updateId: string | null; runtimeVersion: string | null; channel: string | null; manifest: PulseManifest | null; isEmbeddedLaunch: boolean; createdAt: Date | null; build: string | null; // Available/downloaded updates availableUpdate: PulseManifest | null; downloadedUpdate: PulseManifest | null; error: Error | null; // Actions checkForUpdate: () => Promise; downloadUpdate: () => Promise; reload: () => Promise; } export function usePulseUpdates(): UsePulseUpdatesResult { const [isChecking, setIsChecking] = useState(false); const [isDownloading, setIsDownloading] = useState(false); const [availableUpdate, setAvailableUpdate] = useState(null); const [downloadedUpdate, setDownloadedUpdate] = useState(null); const [error, setError] = useState(null); // Refresh state on mount to get latest values after configure useEffect(() => { PulseUpdates.refreshStateAsync().catch(() => {}); }, []); useEffect(() => { if (!PulseUpdates.isEnabled) return; const subscription = PulseUpdates.addUpdateListener((event) => { switch (event.type) { case 'updateAvailable': setAvailableUpdate(event.manifest ?? null); break; case 'updateDownloaded': setDownloadedUpdate(event.manifest ?? null); break; case 'updateError': setError(new Error(event.error ?? 'Unknown error')); break; case 'noUpdateAvailable': setAvailableUpdate(null); break; } }); return () => subscription.remove(); }, []); const checkForUpdate = useCallback(async (): Promise => { if (!PulseUpdates.isEnabled) { return { isAvailable: false }; } setIsChecking(true); setError(null); try { const result = await PulseUpdates.checkForUpdateAsync(); if (result.isAvailable && result.manifest) { setAvailableUpdate(result.manifest); } else { setAvailableUpdate(null); } return result; } catch (e) { const err = e instanceof Error ? e : new Error(String(e)); setError(err); return { isAvailable: false, failedReason: err.message }; } finally { setIsChecking(false); } }, []); const downloadUpdate = useCallback(async (): Promise => { if (!PulseUpdates.isEnabled) { return { isNew: false }; } setIsDownloading(true); setError(null); try { const result = await PulseUpdates.fetchUpdateAsync(); if (result.isNew && result.manifest) { setDownloadedUpdate(result.manifest); } return result; } catch (e) { const err = e instanceof Error ? e : new Error(String(e)); setError(err); return { isNew: false }; } finally { setIsDownloading(false); } }, []); const reload = useCallback(async (): Promise => { if (!PulseUpdates.isEnabled) return; await PulseUpdates.reloadAsync(); }, []); return { isEnabled: PulseUpdates.isEnabled, isChecking, isDownloading, updateId: PulseUpdates.updateId, runtimeVersion: PulseUpdates.runtimeVersion, channel: PulseUpdates.channel, manifest: PulseUpdates.manifest, isEmbeddedLaunch: PulseUpdates.isEmbeddedLaunch, createdAt: PulseUpdates.createdAt, build: PulseUpdates.getUpdateBuild(), availableUpdate, downloadedUpdate, error, checkForUpdate, downloadUpdate, reload, }; }