project-transition-state.ts55 lines · main
1export const FALLBACK_LONG_RUNNING_STATE_THRESHOLD_MINUTES = 10
2// Persist long enough for same-browser reloads, but not so long that a later transition reuses stale state.
3export const MAX_PERSISTED_TRANSITION_AGE_HOURS = 24
4
5const MS_PER_MINUTE = 60 * 1000
6const MS_PER_HOUR = 60 * MS_PER_MINUTE
7
8export const minutesToMilliseconds = (minutes: number) => minutes * MS_PER_MINUTE
9export const hoursToMilliseconds = (hours: number) => hours * MS_PER_HOUR
10
11export const getPersistedTransitionStartTime = (
12 storageKey: string,
13 now = Date.now(),
14 maxAgeMs = Number.POSITIVE_INFINITY
15) => {
16 if (typeof window === 'undefined') return now
17
18 const existingValue = window.localStorage.getItem(storageKey)
19
20 if (existingValue !== null) {
21 const parsedStartTime = Number(existingValue)
22 const elapsedMs = now - parsedStartTime
23
24 if (
25 Number.isFinite(parsedStartTime) &&
26 parsedStartTime > 0 &&
27 elapsedMs >= 0 &&
28 elapsedMs <= maxAgeMs
29 ) {
30 return parsedStartTime
31 }
32 }
33
34 window.localStorage.setItem(storageKey, String(now))
35 return now
36}
37
38export const clearPersistedTransitionStartTime = (storageKey: string) => {
39 if (typeof window === 'undefined') return
40
41 window.localStorage.removeItem(storageKey)
42}
43
44export const getRemainingTransitionTimeMs = ({
45 startTimeMs,
46 thresholdMs,
47 now = Date.now(),
48}: {
49 startTimeMs: number
50 thresholdMs: number
51 now?: number
52}) => {
53 const elapsedMs = now - startTimeMs
54 return Math.max(thresholdMs - elapsedMs, 0)
55}