-
-
Notifications
You must be signed in to change notification settings - Fork 3k
/
Copy pathindex.ts
142 lines (129 loc) · 4.05 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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import { QueryClient } from '../core'
import { getLogger } from '../core/logger'
import {
dehydrate,
DehydratedState,
DehydrateOptions,
HydrateOptions,
hydrate,
} from 'react-query'
import { Promisable } from 'type-fest'
export interface Persister {
persistClient(persistClient: PersistedClient): Promisable<void>
restoreClient(): Promisable<PersistedClient | undefined>
removeClient(): Promisable<void>
}
export interface PersistedClient {
timestamp: number
buster: string
clientState: DehydratedState
}
export interface PersistQueryClienRootOptions {
/** The QueryClient to persist */
queryClient: QueryClient
/** The Persister interface for storing and restoring the cache
* to/from a persisted location */
persister: Persister
/** A unique string that can be used to forcefully
* invalidate existing caches if they do not share the same buster string */
buster?: string
}
export interface PersistedQueryClientRestoreOptions
extends PersistQueryClienRootOptions {
/** The max-allowed age of the cache in milliseconds.
* If a persisted cache is found that is older than this
* time, it will be discarded */
maxAge?: number
/** The options passed to the hydrate function */
hydrateOptions?: HydrateOptions
}
export interface PersistedQueryClientSaveOptions
extends PersistQueryClienRootOptions {
/** The options passed to the dehydrate function */
dehydrateOptions?: DehydrateOptions
}
export interface PersistQueryClientOptions
extends PersistedQueryClientRestoreOptions,
PersistedQueryClientSaveOptions,
PersistQueryClienRootOptions {}
/**
* Restores persisted data to the QueryCache
* - data obtained from persister.restoreClient
* - data is hydrated using hydrateOptions
* If data is expired, busted, empty, or throws, it runs persister.removeClient
*/
export async function persistQueryClientRestore({
queryClient,
persister,
maxAge = 1000 * 60 * 60 * 24,
buster = '',
hydrateOptions,
}: PersistedQueryClientRestoreOptions) {
if (typeof window !== 'undefined') {
try {
const persistedClient = await persister.restoreClient()
if (persistedClient) {
if (persistedClient.timestamp) {
const expired = Date.now() - persistedClient.timestamp > maxAge
const busted = persistedClient.buster !== buster
if (expired || busted) {
persister.removeClient()
} else {
hydrate(queryClient, persistedClient.clientState, hydrateOptions)
}
} else {
persister.removeClient()
}
}
} catch (err) {
getLogger().error(err)
getLogger().warn(
'Encountered an error attempting to restore client cache from persisted location. As a precaution, the persisted cache will be discarded.'
)
persister.removeClient()
}
}
}
/**
* Persists data from the QueryCache
* - data dehydrated using dehydrateOptions
* - data is persisted using persister.persistClient
*/
export async function persistQueryClientSave({
queryClient,
persister,
buster = '',
dehydrateOptions,
}: PersistedQueryClientSaveOptions) {
if (typeof window !== 'undefined') {
const persistClient: PersistedClient = {
buster,
timestamp: Date.now(),
clientState: dehydrate(queryClient, dehydrateOptions),
}
await persister.persistClient(persistClient)
}
}
/**
* Subscribe to QueryCache updates (for persisting)
* @returns an unsubscribe function (to discontinue monitoring)
*/
export function persistQueryClientSubscribe(
props: PersistedQueryClientSaveOptions
) {
return props.queryClient.getQueryCache().subscribe(() => {
persistQueryClientSave(props)
})
}
/**
* Restores persisted data to QueryCache and persists further changes.
* (Retained for backwards compatibility)
*/
export async function persistQueryClient(props: PersistQueryClientOptions) {
if (typeof window !== 'undefined') {
// Attempt restore
await persistQueryClientRestore(props)
// Subscribe to changes in the query cache to trigger the save
return persistQueryClientSubscribe(props)
}
}