@octanejs/apollo-client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +49 -0
- package/README.md +97 -0
- package/package.json +77 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +3 -0
- package/src/react/context/ApolloContext.d.ts +8 -0
- package/src/react/context/ApolloContext.js +21 -0
- package/src/react/context/ApolloProvider.d.ts +9 -0
- package/src/react/context/ApolloProvider.js +15 -0
- package/src/react/hooks/constants.d.ts +2 -0
- package/src/react/hooks/constants.js +1 -0
- package/src/react/hooks/internal/__use.d.ts +3 -0
- package/src/react/hooks/internal/__use.js +9 -0
- package/src/react/hooks/internal/index.d.ts +5 -0
- package/src/react/hooks/internal/index.js +6 -0
- package/src/react/hooks/internal/site.d.ts +2 -0
- package/src/react/hooks/internal/site.js +20 -0
- package/src/react/hooks/internal/useDeepMemo.d.ts +5 -0
- package/src/react/hooks/internal/useDeepMemo.js +11 -0
- package/src/react/hooks/internal/useIsomorphicLayoutEffect.d.ts +2 -0
- package/src/react/hooks/internal/useIsomorphicLayoutEffect.js +8 -0
- package/src/react/hooks/internal/useRenderGuard.d.ts +1 -0
- package/src/react/hooks/internal/useRenderGuard.js +14 -0
- package/src/react/hooks/internal/useSuspenseHookCacheKey.d.ts +13 -0
- package/src/react/hooks/internal/useSuspenseHookCacheKey.js +19 -0
- package/src/react/hooks/internal/validateSuspenseHookOptions.d.ts +4 -0
- package/src/react/hooks/internal/validateSuspenseHookOptions.js +16 -0
- package/src/react/hooks/internal/wrapHook.d.ts +77 -0
- package/src/react/hooks/internal/wrapHook.js +64 -0
- package/src/react/hooks/useApolloClient.d.ts +17 -0
- package/src/react/hooks/useApolloClient.js +27 -0
- package/src/react/hooks/useBackgroundQuery.d.ts +3061 -0
- package/src/react/hooks/useBackgroundQuery.js +88 -0
- package/src/react/hooks/useFragment.d.ts +205 -0
- package/src/react/hooks/useFragment.js +75 -0
- package/src/react/hooks/useLazyQuery.d.ts +947 -0
- package/src/react/hooks/useLazyQuery.js +156 -0
- package/src/react/hooks/useLoadableQuery.d.ts +955 -0
- package/src/react/hooks/useLoadableQuery.js +98 -0
- package/src/react/hooks/useMutation.d.ts +585 -0
- package/src/react/hooks/useMutation.js +121 -0
- package/src/react/hooks/useQuery.d.ts +1401 -0
- package/src/react/hooks/useQuery.js +234 -0
- package/src/react/hooks/useQueryRefHandlers.d.ts +85 -0
- package/src/react/hooks/useQueryRefHandlers.js +79 -0
- package/src/react/hooks/useReactiveVar.d.ts +21 -0
- package/src/react/hooks/useReactiveVar.js +41 -0
- package/src/react/hooks/useReadQuery.d.ts +104 -0
- package/src/react/hooks/useReadQuery.js +83 -0
- package/src/react/hooks/useSubscription.d.ts +289 -0
- package/src/react/hooks/useSubscription.js +258 -0
- package/src/react/hooks/useSuspenseFragment.d.ts +154 -0
- package/src/react/hooks/useSuspenseFragment.js +50 -0
- package/src/react/hooks/useSuspenseQuery.d.ts +1629 -0
- package/src/react/hooks/useSuspenseQuery.js +130 -0
- package/src/react/hooks/useSyncExternalStore.d.ts +2 -0
- package/src/react/hooks/useSyncExternalStore.js +125 -0
- package/src/react/index.d.ts +68 -0
- package/src/react/index.js +18 -0
- package/src/react/internal/cache/FragmentReference.d.ts +41 -0
- package/src/react/internal/cache/FragmentReference.js +117 -0
- package/src/react/internal/cache/QueryReference.d.ts +180 -0
- package/src/react/internal/cache/QueryReference.js +310 -0
- package/src/react/internal/cache/SuspenseCache.d.ts +38 -0
- package/src/react/internal/cache/SuspenseCache.js +39 -0
- package/src/react/internal/cache/getSuspenseCache.d.ts +26 -0
- package/src/react/internal/cache/getSuspenseCache.js +8 -0
- package/src/react/internal/cache/types.d.ts +13 -0
- package/src/react/internal/cache/types.js +1 -0
- package/src/react/internal/index.d.ts +16 -0
- package/src/react/internal/index.js +10 -0
- package/src/react/internal/types.d.ts +15 -0
- package/src/react/internal/types.js +1 -0
- package/src/react/query-preloader/createQueryPreloader.d.ts +630 -0
- package/src/react/query-preloader/createQueryPreloader.js +89 -0
- package/src/react/types/deprecated.d.ts +140 -0
- package/src/react/types/deprecated.js +1 -0
- package/src/react/types/types.documentation.d.ts +551 -0
- package/src/react/types/types.documentation.js +1 -0
- package/src/testing/index.d.ts +1 -0
- package/src/testing/index.js +1 -0
- package/src/testing/react/MockedProvider.d.ts +21 -0
- package/src/testing/react/MockedProvider.js +53 -0
- package/src/testing/react/index.d.ts +2 -0
- package/src/testing/react/index.js +1 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { equal } from '@wry/equality';
|
|
2
|
+
import { filter } from 'rxjs';
|
|
3
|
+
import {
|
|
4
|
+
createFulfilledPromise,
|
|
5
|
+
createRejectedPromise,
|
|
6
|
+
decoratePromise,
|
|
7
|
+
} from '@apollo/client/utilities/internal';
|
|
8
|
+
import { invariant } from '@apollo/client/utilities/invariant';
|
|
9
|
+
const QUERY_REFERENCE_SYMBOL = Symbol.for('apollo.internal.queryRef');
|
|
10
|
+
const PROMISE_SYMBOL = Symbol.for('apollo.internal.refPromise');
|
|
11
|
+
export function wrapQueryRef(internalQueryRef) {
|
|
12
|
+
return {
|
|
13
|
+
[QUERY_REFERENCE_SYMBOL]: internalQueryRef,
|
|
14
|
+
[PROMISE_SYMBOL]: internalQueryRef.promise,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function assertWrappedQueryRef(queryRef) {
|
|
18
|
+
invariant(!queryRef || QUERY_REFERENCE_SYMBOL in queryRef, 27);
|
|
19
|
+
}
|
|
20
|
+
export function getWrappedPromise(queryRef) {
|
|
21
|
+
const internalQueryRef = unwrapQueryRef(queryRef);
|
|
22
|
+
return internalQueryRef.promise.status === 'fulfilled'
|
|
23
|
+
? internalQueryRef.promise
|
|
24
|
+
: queryRef[PROMISE_SYMBOL];
|
|
25
|
+
}
|
|
26
|
+
export function unwrapQueryRef(queryRef) {
|
|
27
|
+
return queryRef[QUERY_REFERENCE_SYMBOL];
|
|
28
|
+
}
|
|
29
|
+
export function updateWrappedQueryRef(queryRef, promise) {
|
|
30
|
+
queryRef[PROMISE_SYMBOL] = promise;
|
|
31
|
+
}
|
|
32
|
+
const OBSERVED_CHANGED_OPTIONS = [
|
|
33
|
+
'context',
|
|
34
|
+
'errorPolicy',
|
|
35
|
+
'fetchPolicy',
|
|
36
|
+
'refetchOn',
|
|
37
|
+
'refetchWritePolicy',
|
|
38
|
+
'returnPartialData',
|
|
39
|
+
];
|
|
40
|
+
export class InternalQueryReference {
|
|
41
|
+
result;
|
|
42
|
+
key = {};
|
|
43
|
+
observable;
|
|
44
|
+
promise;
|
|
45
|
+
queue;
|
|
46
|
+
subscription;
|
|
47
|
+
listeners = new Set();
|
|
48
|
+
autoDisposeTimeoutId;
|
|
49
|
+
resolve;
|
|
50
|
+
reject;
|
|
51
|
+
references = 0;
|
|
52
|
+
softReferences = 0;
|
|
53
|
+
constructor(observable, options) {
|
|
54
|
+
this.handleNext = this.handleNext.bind(this);
|
|
55
|
+
this.dispose = this.dispose.bind(this);
|
|
56
|
+
this.observable = observable;
|
|
57
|
+
if (options.onDispose) {
|
|
58
|
+
this.onDispose = options.onDispose;
|
|
59
|
+
}
|
|
60
|
+
this.setResult();
|
|
61
|
+
this.subscribeToQuery();
|
|
62
|
+
// Start a timer that will automatically dispose of the query if the
|
|
63
|
+
// suspended resource does not use this queryRef in the given time. This
|
|
64
|
+
// helps prevent memory leaks when a component has unmounted before the
|
|
65
|
+
// query has finished loading.
|
|
66
|
+
const startDisposeTimer = () => {
|
|
67
|
+
if (!this.references) {
|
|
68
|
+
this.autoDisposeTimeoutId = setTimeout(
|
|
69
|
+
this.dispose,
|
|
70
|
+
options.autoDisposeTimeoutMs ?? 30_000,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
// We wait until the request has settled to ensure we don't dispose of the
|
|
75
|
+
// query ref before the request finishes, otherwise we would leave the
|
|
76
|
+
// promise in a pending state rendering the suspense boundary indefinitely.
|
|
77
|
+
this.promise.then(startDisposeTimer, startDisposeTimer);
|
|
78
|
+
}
|
|
79
|
+
get disposed() {
|
|
80
|
+
return this.subscription.closed;
|
|
81
|
+
}
|
|
82
|
+
get watchQueryOptions() {
|
|
83
|
+
return this.observable.options;
|
|
84
|
+
}
|
|
85
|
+
reinitialize() {
|
|
86
|
+
const { observable } = this;
|
|
87
|
+
const originalFetchPolicy = this.watchQueryOptions.fetchPolicy;
|
|
88
|
+
const avoidNetworkRequests =
|
|
89
|
+
originalFetchPolicy === 'no-cache' || originalFetchPolicy === 'standby';
|
|
90
|
+
try {
|
|
91
|
+
if (avoidNetworkRequests) {
|
|
92
|
+
observable.applyOptions({ fetchPolicy: 'standby' });
|
|
93
|
+
} else {
|
|
94
|
+
observable.reset();
|
|
95
|
+
observable.applyOptions({ fetchPolicy: 'cache-first' });
|
|
96
|
+
}
|
|
97
|
+
if (!avoidNetworkRequests) {
|
|
98
|
+
this.setResult();
|
|
99
|
+
}
|
|
100
|
+
this.subscribeToQuery();
|
|
101
|
+
} finally {
|
|
102
|
+
observable.applyOptions({ fetchPolicy: originalFetchPolicy });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
retain() {
|
|
106
|
+
this.references++;
|
|
107
|
+
clearTimeout(this.autoDisposeTimeoutId);
|
|
108
|
+
let disposed = false;
|
|
109
|
+
return () => {
|
|
110
|
+
if (disposed) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
disposed = true;
|
|
114
|
+
this.references--;
|
|
115
|
+
setTimeout(() => {
|
|
116
|
+
if (!this.references) {
|
|
117
|
+
this.dispose();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
softRetain() {
|
|
123
|
+
this.softReferences++;
|
|
124
|
+
let disposed = false;
|
|
125
|
+
return () => {
|
|
126
|
+
// Tracking if this has already been called helps ensure that
|
|
127
|
+
// multiple calls to this function won't decrement the reference
|
|
128
|
+
// counter more than it should. Subsequent calls just result in a noop.
|
|
129
|
+
if (disposed) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
disposed = true;
|
|
133
|
+
this.softReferences--;
|
|
134
|
+
setTimeout(() => {
|
|
135
|
+
if (!this.softReferences && !this.references) {
|
|
136
|
+
this.dispose();
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
didChangeOptions(watchQueryOptions) {
|
|
142
|
+
return OBSERVED_CHANGED_OPTIONS.some(
|
|
143
|
+
(option) =>
|
|
144
|
+
option in watchQueryOptions &&
|
|
145
|
+
!equal(this.watchQueryOptions[option], watchQueryOptions[option]),
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
applyOptions(watchQueryOptions) {
|
|
149
|
+
const { fetchPolicy: currentFetchPolicy } = this.watchQueryOptions;
|
|
150
|
+
// "standby" is used when `skip` is set to `true`. Detect when we've
|
|
151
|
+
// enabled the query (i.e. `skip` is `false`) to execute a network request.
|
|
152
|
+
if (currentFetchPolicy === 'standby' && currentFetchPolicy !== watchQueryOptions.fetchPolicy) {
|
|
153
|
+
this.initiateFetch(this.observable.reobserve(watchQueryOptions));
|
|
154
|
+
} else {
|
|
155
|
+
this.observable.applyOptions(watchQueryOptions);
|
|
156
|
+
}
|
|
157
|
+
return this.promise;
|
|
158
|
+
}
|
|
159
|
+
listen(listener) {
|
|
160
|
+
this.listeners.add(listener);
|
|
161
|
+
if (this.queue) {
|
|
162
|
+
this.deliver(this.queue);
|
|
163
|
+
this.queue = undefined;
|
|
164
|
+
}
|
|
165
|
+
return () => {
|
|
166
|
+
this.listeners.delete(listener);
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
refetch(variables) {
|
|
170
|
+
return this.initiateFetch(this.observable.refetch(variables));
|
|
171
|
+
}
|
|
172
|
+
fetchMore(options) {
|
|
173
|
+
return this.initiateFetch(this.observable.fetchMore(options));
|
|
174
|
+
}
|
|
175
|
+
dispose() {
|
|
176
|
+
this.subscription.unsubscribe();
|
|
177
|
+
}
|
|
178
|
+
onDispose() {
|
|
179
|
+
// noop. overridable by options
|
|
180
|
+
}
|
|
181
|
+
handleNext(result) {
|
|
182
|
+
switch (this.promise.status) {
|
|
183
|
+
case 'pending': {
|
|
184
|
+
// Maintain the last successful `data` value if the next result does not
|
|
185
|
+
// have one.
|
|
186
|
+
// TODO: This can likely be removed once
|
|
187
|
+
// https://github.com/apollographql/apollo-client/issues/12667 is fixed
|
|
188
|
+
if (result.data === void 0) {
|
|
189
|
+
result.data = this.result.data;
|
|
190
|
+
if (result.data) {
|
|
191
|
+
result.dataState = 'complete';
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (this.shouldReject(result)) {
|
|
195
|
+
this.reject?.(result.error);
|
|
196
|
+
} else {
|
|
197
|
+
this.result = result;
|
|
198
|
+
this.resolve?.(result);
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
default: {
|
|
203
|
+
// This occurs when switching to a result that is fully cached when this
|
|
204
|
+
// class is instantiated. ObservableQuery will run reobserve when
|
|
205
|
+
// subscribing, which delivers a result from the cache.
|
|
206
|
+
if (
|
|
207
|
+
result.data === this.result.data &&
|
|
208
|
+
result.networkStatus === this.result.networkStatus
|
|
209
|
+
) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
// Maintain the last successful `data` value if the next result does not
|
|
213
|
+
// have one.
|
|
214
|
+
if (result.data === void 0) {
|
|
215
|
+
result.data = this.result.data;
|
|
216
|
+
}
|
|
217
|
+
if (this.shouldReject(result)) {
|
|
218
|
+
this.promise = createRejectedPromise(result.error);
|
|
219
|
+
this.deliver(this.promise);
|
|
220
|
+
} else {
|
|
221
|
+
this.result = result;
|
|
222
|
+
this.promise = createFulfilledPromise(result);
|
|
223
|
+
this.deliver(this.promise);
|
|
224
|
+
}
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
deliver(promise) {
|
|
230
|
+
// Maintain a queue of the last item we tried to deliver so that we can
|
|
231
|
+
// deliver it as soon as we get the first listener. This helps in cases such
|
|
232
|
+
// as `@stream` where React may render a component and incremental results
|
|
233
|
+
// are loaded in between when the component renders and effects are run. If
|
|
234
|
+
// effects are run after the incremntal chunks are delivered, we'll have
|
|
235
|
+
// rendered a stale value. The queue ensures we can deliver the most
|
|
236
|
+
// up-to-date value as soon as the component is ready to listen for new
|
|
237
|
+
// values.
|
|
238
|
+
if (this.listeners.size === 0) {
|
|
239
|
+
this.queue = promise;
|
|
240
|
+
}
|
|
241
|
+
this.listeners.forEach((listener) => listener(promise));
|
|
242
|
+
}
|
|
243
|
+
initiateFetch(returnedPromise) {
|
|
244
|
+
this.promise = this.createPendingPromise();
|
|
245
|
+
this.promise.catch(() => {});
|
|
246
|
+
// If the data returned from the fetch is deeply equal to the data already
|
|
247
|
+
// in the cache, `handleNext` will not be triggered leaving the promise we
|
|
248
|
+
// created in a pending state forever. To avoid this situation, we attempt
|
|
249
|
+
// to resolve the promise if `handleNext` hasn't been run to ensure the
|
|
250
|
+
// promise is resolved correctly.
|
|
251
|
+
returnedPromise
|
|
252
|
+
.then(() => {
|
|
253
|
+
// In the case of `fetchMore`, this promise is resolved before a cache
|
|
254
|
+
// result is emitted due to the fact that `fetchMore` sets a `no-cache`
|
|
255
|
+
// fetch policy and runs `cache.batch` in its `.then` handler. Because
|
|
256
|
+
// the timing is different, we accidentally run this update twice
|
|
257
|
+
// causing an additional re-render with the `fetchMore` result by
|
|
258
|
+
// itself. By wrapping in `setTimeout`, this should provide a short
|
|
259
|
+
// delay to allow the `QueryInfo.notify` handler to run before this
|
|
260
|
+
// promise is checked.
|
|
261
|
+
// See https://github.com/apollographql/apollo-client/issues/11315 for
|
|
262
|
+
// more information
|
|
263
|
+
setTimeout(() => {
|
|
264
|
+
if (this.promise.status === 'pending') {
|
|
265
|
+
// Use the current result from the observable instead of the value
|
|
266
|
+
// resolved from the promise. This avoids issues in some cases where
|
|
267
|
+
// the raw resolved value should not be the emitted value, such as
|
|
268
|
+
// when a `fetchMore` call returns an empty array after it has
|
|
269
|
+
// reached the end of the list.
|
|
270
|
+
//
|
|
271
|
+
// See the following for more information:
|
|
272
|
+
// https://github.com/apollographql/apollo-client/issues/11642
|
|
273
|
+
this.result = this.observable.getCurrentResult();
|
|
274
|
+
this.resolve?.(this.result);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
})
|
|
278
|
+
.catch((error) => this.reject?.(error));
|
|
279
|
+
return returnedPromise;
|
|
280
|
+
}
|
|
281
|
+
subscribeToQuery() {
|
|
282
|
+
this.subscription = this.observable
|
|
283
|
+
.pipe(filter((result) => !equal(result, this.result)))
|
|
284
|
+
.subscribe(this.handleNext);
|
|
285
|
+
// call `onDispose` when the subscription is finalized, either because it is
|
|
286
|
+
// unsubscribed as a consequence of a `dispose` call or because the
|
|
287
|
+
// ObservableQuery completes because of a `ApolloClient.stop()` call.
|
|
288
|
+
this.subscription.add(this.onDispose);
|
|
289
|
+
}
|
|
290
|
+
setResult() {
|
|
291
|
+
const result = this.observable.getCurrentResult();
|
|
292
|
+
if (equal(result, this.result)) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
this.result = result;
|
|
296
|
+
this.promise = result.data ? createFulfilledPromise(result) : this.createPendingPromise();
|
|
297
|
+
}
|
|
298
|
+
shouldReject(result) {
|
|
299
|
+
const { errorPolicy = 'none' } = this.watchQueryOptions;
|
|
300
|
+
return result.error && errorPolicy === 'none';
|
|
301
|
+
}
|
|
302
|
+
createPendingPromise() {
|
|
303
|
+
return decoratePromise(
|
|
304
|
+
new Promise((resolve, reject) => {
|
|
305
|
+
this.resolve = resolve;
|
|
306
|
+
this.reject = reject;
|
|
307
|
+
}),
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ApolloClient, DataState, ObservableQuery, OperationVariables } from '@apollo/client';
|
|
2
|
+
import { FragmentReference } from './FragmentReference.js';
|
|
3
|
+
import { InternalQueryReference } from './QueryReference.js';
|
|
4
|
+
import type { CacheKey, FragmentCacheKey } from './types.js';
|
|
5
|
+
export interface SuspenseCacheOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Specifies the amount of time, in milliseconds, the suspense cache will wait
|
|
8
|
+
* for a suspended component to read from the suspense cache before it
|
|
9
|
+
* automatically disposes of the query. This prevents memory leaks when a
|
|
10
|
+
* component unmounts before a suspended resource finishes loading. Increase
|
|
11
|
+
* the timeout if your queries take longer than than the specified time to
|
|
12
|
+
* prevent your queries from suspending over and over.
|
|
13
|
+
*
|
|
14
|
+
* Defaults to 30 seconds.
|
|
15
|
+
*/
|
|
16
|
+
autoDisposeTimeoutMs?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare class SuspenseCache {
|
|
19
|
+
private queryRefs;
|
|
20
|
+
private fragmentRefs;
|
|
21
|
+
private options;
|
|
22
|
+
constructor(options?: SuspenseCacheOptions);
|
|
23
|
+
getQueryRef<
|
|
24
|
+
TData = unknown,
|
|
25
|
+
TStates extends DataState<TData>['dataState'] = DataState<TData>['dataState'],
|
|
26
|
+
>(
|
|
27
|
+
cacheKey: CacheKey,
|
|
28
|
+
createObservable: () => ObservableQuery<TData>,
|
|
29
|
+
): InternalQueryReference<TData, TStates>;
|
|
30
|
+
getFragmentRef<TData, TVariables extends OperationVariables>(
|
|
31
|
+
cacheKey: FragmentCacheKey,
|
|
32
|
+
client: ApolloClient,
|
|
33
|
+
options: ApolloClient.WatchFragmentOptions<TData, TVariables> & {
|
|
34
|
+
from: string | null | Array<string | null>;
|
|
35
|
+
},
|
|
36
|
+
): FragmentReference<TData, TVariables>;
|
|
37
|
+
add(cacheKey: CacheKey, queryRef: InternalQueryReference<any, any>): void;
|
|
38
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Trie } from '@wry/trie';
|
|
2
|
+
import { FragmentReference } from './FragmentReference.js';
|
|
3
|
+
import { InternalQueryReference } from './QueryReference.js';
|
|
4
|
+
export class SuspenseCache {
|
|
5
|
+
queryRefs = new Trie();
|
|
6
|
+
fragmentRefs = new Trie();
|
|
7
|
+
options;
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
}
|
|
11
|
+
getQueryRef(cacheKey, createObservable) {
|
|
12
|
+
const ref = this.queryRefs.lookupArray(cacheKey);
|
|
13
|
+
if (!ref.current) {
|
|
14
|
+
ref.current = new InternalQueryReference(createObservable(), {
|
|
15
|
+
autoDisposeTimeoutMs: this.options.autoDisposeTimeoutMs,
|
|
16
|
+
onDispose: () => {
|
|
17
|
+
delete ref.current;
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return ref.current;
|
|
22
|
+
}
|
|
23
|
+
getFragmentRef(cacheKey, client, options) {
|
|
24
|
+
const ref = this.fragmentRefs.lookupArray(cacheKey);
|
|
25
|
+
if (!ref.current) {
|
|
26
|
+
ref.current = new FragmentReference(client, options, {
|
|
27
|
+
autoDisposeTimeoutMs: this.options.autoDisposeTimeoutMs,
|
|
28
|
+
onDispose: () => {
|
|
29
|
+
delete ref.current;
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return ref.current;
|
|
34
|
+
}
|
|
35
|
+
add(cacheKey, queryRef) {
|
|
36
|
+
const ref = this.queryRefs.lookupArray(cacheKey);
|
|
37
|
+
ref.current = queryRef;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ApolloClient } from '@apollo/client';
|
|
2
|
+
import type { SuspenseCacheOptions } from '@octanejs/apollo-client/react/internal';
|
|
3
|
+
import { SuspenseCache } from './SuspenseCache.js';
|
|
4
|
+
declare module '@apollo/client' {
|
|
5
|
+
namespace ApolloClient {
|
|
6
|
+
interface DefaultOptions {
|
|
7
|
+
react?: {
|
|
8
|
+
suspense?: Readonly<SuspenseCacheOptions>;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
namespace DefaultOptions {
|
|
12
|
+
interface Input {
|
|
13
|
+
react?: {
|
|
14
|
+
suspense?: Readonly<SuspenseCacheOptions>;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
declare const suspenseCacheSymbol: unique symbol;
|
|
21
|
+
export declare function getSuspenseCache(
|
|
22
|
+
client: ApolloClient & {
|
|
23
|
+
[suspenseCacheSymbol]?: SuspenseCache;
|
|
24
|
+
},
|
|
25
|
+
): SuspenseCache;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SuspenseCache } from './SuspenseCache.js';
|
|
2
|
+
const suspenseCacheSymbol = Symbol.for('apollo.suspenseCache');
|
|
3
|
+
export function getSuspenseCache(client) {
|
|
4
|
+
if (!client[suspenseCacheSymbol]) {
|
|
5
|
+
client[suspenseCacheSymbol] = new SuspenseCache(client.defaultOptions.react?.suspense);
|
|
6
|
+
}
|
|
7
|
+
return client[suspenseCacheSymbol];
|
|
8
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DocumentNode } from 'graphql';
|
|
2
|
+
export type CacheKey = [query: DocumentNode, stringifiedVariables: string, ...queryKey: any[]];
|
|
3
|
+
export type FragmentCacheKey = [
|
|
4
|
+
fragment: DocumentNode,
|
|
5
|
+
stringifiedVariables: string,
|
|
6
|
+
cacheId: string | null,
|
|
7
|
+
];
|
|
8
|
+
export interface QueryKey {
|
|
9
|
+
__queryKey?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface FragmentKey {
|
|
12
|
+
__fragmentKey?: string;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { InternalTypes as ReactInternalTypes } from '@octanejs/apollo-client/react';
|
|
2
|
+
export { getSuspenseCache } from './cache/getSuspenseCache.js';
|
|
3
|
+
export type { CacheKey, FragmentKey, QueryKey } from './cache/types.js';
|
|
4
|
+
export type { PreloadedQueryRef, QueryRef } from './cache/QueryReference.js';
|
|
5
|
+
export {
|
|
6
|
+
assertWrappedQueryRef,
|
|
7
|
+
getWrappedPromise,
|
|
8
|
+
InternalQueryReference,
|
|
9
|
+
unwrapQueryRef,
|
|
10
|
+
updateWrappedQueryRef,
|
|
11
|
+
wrapQueryRef,
|
|
12
|
+
} from './cache/QueryReference.js';
|
|
13
|
+
export type { SuspenseCacheOptions } from './cache/SuspenseCache.js';
|
|
14
|
+
export type HookWrappers = ReactInternalTypes.HookWrappers;
|
|
15
|
+
export declare const wrapperSymbol: unique symbol;
|
|
16
|
+
export type { FetchMoreFunction, RefetchFunction } from './types.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { getSuspenseCache } from './cache/getSuspenseCache.js';
|
|
2
|
+
export {
|
|
3
|
+
assertWrappedQueryRef,
|
|
4
|
+
getWrappedPromise,
|
|
5
|
+
InternalQueryReference,
|
|
6
|
+
unwrapQueryRef,
|
|
7
|
+
updateWrappedQueryRef,
|
|
8
|
+
wrapQueryRef,
|
|
9
|
+
} from './cache/QueryReference.js';
|
|
10
|
+
export const wrapperSymbol = Symbol.for('apollo.hook.wrappers');
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ApolloClient,
|
|
3
|
+
MaybeMasked,
|
|
4
|
+
ObservableQuery,
|
|
5
|
+
OperationVariables,
|
|
6
|
+
} from '@apollo/client';
|
|
7
|
+
export type RefetchFunction<TData, TVariables extends OperationVariables> = (
|
|
8
|
+
variables?: Partial<TVariables>,
|
|
9
|
+
) => Promise<ApolloClient.QueryResult<TData>>;
|
|
10
|
+
export type FetchMoreFunction<TData, TVariables extends OperationVariables> = <
|
|
11
|
+
TFetchData = TData,
|
|
12
|
+
TFetchVars extends OperationVariables = TVariables,
|
|
13
|
+
>(
|
|
14
|
+
fetchMoreOptions: ObservableQuery.FetchMoreOptions<TData, TVariables, TFetchData, TFetchVars>,
|
|
15
|
+
) => Promise<ApolloClient.QueryResult<MaybeMasked<TData>>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|