1import * as Updates from './Updates';
2import type { Manifest, UpdatesNativeStateMachineContext } from './Updates.types';
3import { UpdateInfoType, type CurrentlyRunningInfo, type UpdateInfo } from './UseUpdates.types';
4
5// The currently running info, constructed from Updates constants
6export const currentlyRunning: CurrentlyRunningInfo = {
7  updateId: Updates.updateId ?? undefined,
8  channel: Updates.channel ?? undefined,
9  createdAt: Updates.createdAt ?? undefined,
10  isEmbeddedLaunch: Updates.isEmbeddedLaunch,
11  isEmergencyLaunch: Updates.isEmergencyLaunch,
12  manifest: Updates.manifest ?? undefined,
13  runtimeVersion: Updates.runtimeVersion ?? undefined,
14};
15
16// Type for the state managed by useUpdates().
17// Used internally by this module and not exported publicly.
18export type UseUpdatesStateType = {
19  availableUpdate?: UpdateInfo;
20  downloadedUpdate?: UpdateInfo;
21  checkError?: Error;
22  downloadError?: Error;
23  isUpdateAvailable: boolean;
24  isUpdatePending: boolean;
25  isChecking: boolean;
26  isDownloading: boolean;
27  lastCheckForUpdateTimeSinceRestart?: Date;
28};
29
30// Constructs an UpdateInfo from a manifest
31export const updateFromManifest: (manifest: NonNullable<Manifest>) => UpdateInfo = (manifest) => {
32  return {
33    type: UpdateInfoType.NEW,
34    updateId: manifest.id ?? '',
35    createdAt:
36      manifest && 'createdAt' in manifest && manifest.createdAt
37        ? new Date(manifest.createdAt)
38        : manifest && 'publishedTime' in manifest && manifest.publishedTime
39        ? new Date(manifest.publishedTime)
40        : // We should never reach this if the manifest is valid and has a commit time,
41          // but leave this in so that createdAt is always defined
42          new Date(0),
43    manifest,
44  };
45};
46
47// Default useUpdates() state
48export const defaultUseUpdatesState: UseUpdatesStateType = {
49  isChecking: false,
50  isDownloading: false,
51  isUpdateAvailable: false,
52  isUpdatePending: false,
53};
54
55// Transform the useUpdates() state based on native state machine context
56export const reduceUpdatesStateFromContext: (
57  updatesState: UseUpdatesStateType,
58  context: UpdatesNativeStateMachineContext
59) => UseUpdatesStateType = (updatesState, context) => {
60  const availableUpdate = context?.latestManifest
61    ? updateFromManifest(context?.latestManifest)
62    : undefined;
63  const downloadedUpdate = context?.downloadedManifest
64    ? updateFromManifest(context?.downloadedManifest)
65    : undefined;
66  return {
67    ...updatesState,
68    isUpdateAvailable: context.isUpdateAvailable,
69    isUpdatePending: context.isUpdatePending,
70    isChecking: context.isChecking,
71    isDownloading: context.isDownloading,
72    availableUpdate,
73    downloadedUpdate,
74    checkError: context.checkError,
75    downloadError: context.downloadError,
76    lastCheckForUpdateTimeSinceRestart: context.isChecking
77      ? new Date()
78      : updatesState.lastCheckForUpdateTimeSinceRestart,
79  };
80};
81