Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / redux-utilities / asyncModelThunk / promiseStore.ts
blobc129b90c5d0986c76d828262f31d0696cbdb96b5
1 import { defaultExpiry, getFetchedEphemeral as defaultGetFetchedEphemeral, isNotStale } from './fetchedAt';
2 import { CacheType, type ReducerValue } from './interface';
4 const context: { cache?: CacheType; fetchedEphemeral: ReturnType<typeof defaultGetFetchedEphemeral> } = {
5     cache: CacheType.StaleRefetch,
6     fetchedEphemeral: defaultGetFetchedEphemeral(),
7 };
9 export const configureCache = ({
10     cache = CacheType.StaleRefetch,
11     getFetchedEphemeral = defaultGetFetchedEphemeral,
12 }: {
13     cache?: CacheType;
14     getFetchedEphemeral?: typeof defaultGetFetchedEphemeral;
15 }) => {
16     context.cache = cache;
17     context.fetchedEphemeral = getFetchedEphemeral();
20 export const getIsStaleRefetch = (
21     fetchedEphemeral: ReturnType<typeof defaultGetFetchedEphemeral> | undefined,
22     cache: CacheType
23 ) => {
24     return cache === CacheType.StaleRefetch && fetchedEphemeral !== context.fetchedEphemeral;
27 export const cacheHelper = <Returned>({
28     store,
29     key,
30     select,
31     cb,
32     cache = context.cache,
33     expiry = defaultExpiry,
34 }: {
35     store: {
36         get: (key: string) => Promise<Returned> | undefined;
37         set: (key: string, promise: Promise<Returned>) => void;
38     };
39     key?: any;
40     select: () => ReducerValue<Returned> | undefined;
41     cb: () => Promise<Returned>;
42     cache?: CacheType;
43     expiry?: number;
44 }): Promise<Returned> => {
45     const promise = store.get(key);
46     if (promise) {
47         return promise;
48     }
49     if (cache === CacheType.Stale || cache === CacheType.StaleRefetch) {
50         const state = select();
51         if (state && state.value !== undefined && isNotStale(state.meta.fetchedAt, expiry)) {
52             if (getIsStaleRefetch(state.meta.fetchedEphemeral, cache)) {
53                 const newPromise = cb();
54                 store.set(key, newPromise);
55             }
56             return Promise.resolve(state.value);
57         }
58     }
59     const newPromise = cb();
60     store.set(key, newPromise);
61     return newPromise;
64 export const createPromiseStore = <Returned>() => {
65     let promise: Promise<Returned> | undefined = undefined;
67     const set = (key: string, newPromise: Promise<Returned>) => {
68         promise = newPromise;
69         newPromise
70             .finally(() => {
71                 promise = undefined;
72             })
73             .catch(() => {});
74     };
76     const get = () => promise;
78     return { get, set };
81 export const createPromiseMapStore = <Returned>() => {
82     const map = new Map<string, Promise<Returned>>();
84     const set = (id: string, newPromise: Promise<Returned>) => {
85         map.set(id, newPromise);
86         newPromise
87             .finally(() => {
88                 map.delete(id);
89             })
90             .catch(() => {});
91     };
93     const get = (id: string) => map.get(id);
95     return { get, set };