1 import type { Cache } from '@proton/shared/lib/helpers/cache';
2 import { STATUS } from '@proton/shared/lib/models/cache';
8 promise?: Promise<Value>;
11 const getRecordPending = <Value>(promise: Promise<Value>): Record<Value> => {
13 status: STATUS.PENDING,
16 timestamp: Date.now(),
20 const getRecordThen = <Value>(promise: Promise<Value>): Promise<Record<Value>> => {
24 status: STATUS.RESOLVED,
26 timestamp: Date.now(),
32 status: STATUS.REJECTED,
34 timestamp: Date.now(),
41 * The strategy to re-fetch is:
42 * 1) When no record exists for that key.
43 * 2) If the old record has failed to fetch.
44 * This should only happen when:
45 * 1) When the component is initially mounted.
46 * 2) A mounted component that receives an update from the cache that the key has been removed.
47 * 3) A mounted component receives an update that the key has changed.
49 const update = <Value, Key>(cache: Cache<Key, Record<Value>>, key: Key, promise: Promise<Value>) => {
50 const record = getRecordPending(promise);
51 cache.set(key, record);
52 getRecordThen(promise).then((newRecord) => {
53 if (cache.get(key) === record) {
54 cache.set(key, newRecord);
60 export const getIsRecordInvalid = <Value>(record: Record<Value> | undefined, lifetime = Number.MAX_SAFE_INTEGER) => {
63 record.status === STATUS.REJECTED ||
64 (record.status === STATUS.RESOLVED && Date.now() - record.timestamp > lifetime)
68 export const getPromiseValue = <Value, Key>(
69 cache: Cache<Key, Record<Value>>,
71 miss: (key: Key) => Promise<Value>,
73 ): Promise<Value> => {
74 const oldRecord = cache.get(key);
75 if (!oldRecord || getIsRecordInvalid(oldRecord, lifetime)) {
76 return update(cache, key, miss(key));
78 if (oldRecord.promise) {
79 return oldRecord.promise;
81 return Promise.resolve(oldRecord.value!);