-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
index.ts
106 lines (95 loc) 路 2.73 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import type {
PersistedClient,
Persister,
Promisable,
} from '@tanstack/query-persist-client-core'
import { asyncThrottle } from './asyncThrottle'
interface AsyncStorage {
getItem: (key: string) => Promise<string | null>
setItem: (key: string, value: string) => Promise<unknown>
removeItem: (key: string) => Promise<void>
}
export type AsyncPersistRetryer = (props: {
persistedClient: PersistedClient
error: Error
errorCount: number
}) => Promisable<PersistedClient | undefined>
interface CreateAsyncStoragePersisterOptions {
/** The storage client used for setting and retrieving items from cache.
* For SSR pass in `undefined`.
*/
storage: AsyncStorage | undefined
/** The key to use when storing the cache */
key?: string
/** To avoid spamming,
* pass a time in ms to throttle saving the cache to disk */
throttleTime?: number
/**
* How to serialize the data to storage.
* @default `JSON.stringify`
*/
serialize?: (client: PersistedClient) => string
/**
* How to deserialize the data from storage.
* @default `JSON.parse`
*/
deserialize?: (cachedString: string) => PersistedClient
retry?: AsyncPersistRetryer
}
export const createAsyncStoragePersister = ({
storage,
key = `REACT_QUERY_OFFLINE_CACHE`,
throttleTime = 1000,
serialize = JSON.stringify,
deserialize = JSON.parse,
retry,
}: CreateAsyncStoragePersisterOptions): Persister => {
if (typeof storage !== 'undefined') {
const trySave = async (
persistedClient: PersistedClient,
): Promise<Error | undefined> => {
try {
await storage.setItem(key, serialize(persistedClient))
return
} catch (error) {
return error as Error
}
}
return {
persistClient: asyncThrottle(
async (persistedClient) => {
let client: PersistedClient | undefined = persistedClient
let error = await trySave(client)
let errorCount = 0
while (error && client) {
errorCount++
client = await retry?.({
persistedClient: client,
error,
errorCount,
})
if (client) {
error = await trySave(client)
}
}
},
{ interval: throttleTime },
),
restoreClient: async () => {
const cacheString = await storage.getItem(key)
if (!cacheString) {
return
}
return deserialize(cacheString) as PersistedClient
},
removeClient: () => storage.removeItem(key),
}
}
return {
persistClient: noop,
restoreClient: () => Promise.resolve(undefined),
removeClient: noop,
}
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
function noop() {}