@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,130 @@
|
|
|
1
|
+
import * as React from 'octane';
|
|
2
|
+
import { NetworkStatus } from '@apollo/client';
|
|
3
|
+
import { getSuspenseCache } from '@octanejs/apollo-client/react/internal';
|
|
4
|
+
import { __DEV__ } from '@apollo/client/utilities/environment';
|
|
5
|
+
import { variablesUnknownSymbol } from '@apollo/client/utilities/internal';
|
|
6
|
+
import { skipToken } from './constants.js';
|
|
7
|
+
import { __use, useDeepMemo, useSuspenseHookCacheKey, wrapHook } from './internal/index.js';
|
|
8
|
+
import { isCompilerSite } from './internal/site.js';
|
|
9
|
+
import { validateSuspenseHookOptions } from './internal/validateSuspenseHookOptions.js';
|
|
10
|
+
import { useApolloClient } from './useApolloClient.js';
|
|
11
|
+
export const useSuspenseQuery = function useSuspenseQuery(query, options, site) {
|
|
12
|
+
'use no memo';
|
|
13
|
+
if (isCompilerSite(options, skipToken)) {
|
|
14
|
+
site = options;
|
|
15
|
+
options = undefined;
|
|
16
|
+
}
|
|
17
|
+
return wrapHook(
|
|
18
|
+
'useSuspenseQuery',
|
|
19
|
+
useSuspenseQuery_,
|
|
20
|
+
useApolloClient(typeof options === 'object' ? options.client : undefined),
|
|
21
|
+
)(query, options ?? {}, site);
|
|
22
|
+
};
|
|
23
|
+
function useSuspenseQuery_(query, options, site) {
|
|
24
|
+
const client = useApolloClient(options.client);
|
|
25
|
+
const suspenseCache = getSuspenseCache(client);
|
|
26
|
+
const watchQueryOptions = useWatchQueryOptions({
|
|
27
|
+
client,
|
|
28
|
+
query,
|
|
29
|
+
options,
|
|
30
|
+
});
|
|
31
|
+
const { fetchPolicy } = watchQueryOptions;
|
|
32
|
+
const cacheKey = useSuspenseHookCacheKey(query, options);
|
|
33
|
+
const queryRef = suspenseCache.getQueryRef(cacheKey, () => client.watchQuery(watchQueryOptions));
|
|
34
|
+
let [current, setPromise] = React.useState([queryRef.key, queryRef.promise]);
|
|
35
|
+
// This saves us a re-execution of the render function when a variable changed.
|
|
36
|
+
if (current[0] !== queryRef.key) {
|
|
37
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
38
|
+
current[0] = queryRef.key;
|
|
39
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
40
|
+
current[1] = queryRef.promise;
|
|
41
|
+
}
|
|
42
|
+
let promise = current[1];
|
|
43
|
+
if (queryRef.didChangeOptions(watchQueryOptions)) {
|
|
44
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
45
|
+
current[1] = promise = queryRef.applyOptions(watchQueryOptions);
|
|
46
|
+
}
|
|
47
|
+
React.useEffect(() => {
|
|
48
|
+
const dispose = queryRef.retain();
|
|
49
|
+
const removeListener = queryRef.listen((promise) => {
|
|
50
|
+
setPromise([queryRef.key, promise]);
|
|
51
|
+
});
|
|
52
|
+
return () => {
|
|
53
|
+
removeListener();
|
|
54
|
+
dispose();
|
|
55
|
+
};
|
|
56
|
+
}, [queryRef]);
|
|
57
|
+
const skipResult = React.useMemo(() => {
|
|
58
|
+
const error = queryRef.result.error;
|
|
59
|
+
const complete = !!queryRef.result.data;
|
|
60
|
+
return {
|
|
61
|
+
loading: false,
|
|
62
|
+
data: queryRef.result.data,
|
|
63
|
+
dataState: queryRef.result.dataState,
|
|
64
|
+
networkStatus: error ? NetworkStatus.error : NetworkStatus.ready,
|
|
65
|
+
error,
|
|
66
|
+
complete,
|
|
67
|
+
partial: !complete,
|
|
68
|
+
};
|
|
69
|
+
}, [queryRef.result]);
|
|
70
|
+
const result = fetchPolicy === 'standby' ? skipResult : __use(promise, site);
|
|
71
|
+
const fetchMore = React.useCallback(
|
|
72
|
+
(options) => {
|
|
73
|
+
const promise = queryRef.fetchMore(options);
|
|
74
|
+
setPromise([queryRef.key, queryRef.promise]);
|
|
75
|
+
return promise;
|
|
76
|
+
},
|
|
77
|
+
[queryRef],
|
|
78
|
+
);
|
|
79
|
+
const refetch = React.useCallback(
|
|
80
|
+
(variables) => {
|
|
81
|
+
const promise = queryRef.refetch(variables);
|
|
82
|
+
setPromise([queryRef.key, queryRef.promise]);
|
|
83
|
+
return promise;
|
|
84
|
+
},
|
|
85
|
+
[queryRef],
|
|
86
|
+
);
|
|
87
|
+
// TODO: The internalQueryRef doesn't have TVariables' type information so we have to cast it here
|
|
88
|
+
const subscribeToMore = queryRef.observable.subscribeToMore;
|
|
89
|
+
return React.useMemo(() => {
|
|
90
|
+
return {
|
|
91
|
+
client,
|
|
92
|
+
data: result.data,
|
|
93
|
+
dataState: result.dataState,
|
|
94
|
+
error: result.error,
|
|
95
|
+
networkStatus: result.networkStatus,
|
|
96
|
+
fetchMore,
|
|
97
|
+
refetch,
|
|
98
|
+
subscribeToMore,
|
|
99
|
+
};
|
|
100
|
+
}, [client, fetchMore, refetch, result, subscribeToMore]);
|
|
101
|
+
}
|
|
102
|
+
export function useWatchQueryOptions({ client, query, options }) {
|
|
103
|
+
return useDeepMemo(() => {
|
|
104
|
+
if (options === skipToken) {
|
|
105
|
+
return {
|
|
106
|
+
query,
|
|
107
|
+
fetchPolicy: 'standby',
|
|
108
|
+
[variablesUnknownSymbol]: true,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const fetchPolicy =
|
|
112
|
+
options.fetchPolicy || client.defaultOptions.watchQuery?.fetchPolicy || 'cache-first';
|
|
113
|
+
const watchQueryOptions = {
|
|
114
|
+
...options,
|
|
115
|
+
fetchPolicy,
|
|
116
|
+
query,
|
|
117
|
+
notifyOnNetworkStatusChange: false,
|
|
118
|
+
nextFetchPolicy: void 0,
|
|
119
|
+
};
|
|
120
|
+
if (__DEV__) {
|
|
121
|
+
validateSuspenseHookOptions(watchQueryOptions);
|
|
122
|
+
}
|
|
123
|
+
// Assign the updated fetch policy after our validation since `standby` is
|
|
124
|
+
// not a supported fetch policy on its own without the use of `skip`.
|
|
125
|
+
if (options.skip) {
|
|
126
|
+
watchQueryOptions.fetchPolicy = 'standby';
|
|
127
|
+
}
|
|
128
|
+
return watchQueryOptions;
|
|
129
|
+
}, [client, options, query]);
|
|
130
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import * as React from 'octane';
|
|
2
|
+
import { __DEV__ } from '@apollo/client/utilities/environment';
|
|
3
|
+
import { canUseDOM } from '@apollo/client/utilities/internal';
|
|
4
|
+
import { maybe } from '@apollo/client/utilities/internal/globals';
|
|
5
|
+
import { invariant } from '@apollo/client/utilities/invariant';
|
|
6
|
+
let didWarnUncachedGetSnapshot = false;
|
|
7
|
+
// Prevent webpack from complaining about our feature detection of the
|
|
8
|
+
// useSyncExternalStore property of the React namespace, which is expected not
|
|
9
|
+
// to exist when using React 17 and earlier, and that's fine.
|
|
10
|
+
const uSESKey = 'useSyncExternalStore';
|
|
11
|
+
const realHook = React[uSESKey];
|
|
12
|
+
const isReactNative = maybe(() => navigator.product) == 'ReactNative';
|
|
13
|
+
const usingJSDOM =
|
|
14
|
+
// Following advice found in this comment from @domenic (maintainer of jsdom):
|
|
15
|
+
// https://github.com/jsdom/jsdom/issues/1537#issuecomment-229405327
|
|
16
|
+
//
|
|
17
|
+
// Since we control the version of Jest and jsdom used when running Apollo
|
|
18
|
+
// Client tests, and that version is recent enough to include " jsdom/x.y.z"
|
|
19
|
+
// at the end of the user agent string, I believe this case is all we need to
|
|
20
|
+
// check. Testing for "Node.js" was recommended for backwards compatibility
|
|
21
|
+
// with older version of jsdom, but we don't have that problem.
|
|
22
|
+
maybe(() => navigator.userAgent.indexOf('jsdom') >= 0) || false;
|
|
23
|
+
// Our tests should all continue to pass if we remove this !usingJSDOM
|
|
24
|
+
// condition, thereby allowing useLayoutEffect when using jsdom. Unfortunately,
|
|
25
|
+
// if we allow useLayoutEffect, then useSyncExternalStore generates many
|
|
26
|
+
// warnings about useLayoutEffect doing nothing on the server. While these
|
|
27
|
+
// warnings are harmless, this !usingJSDOM condition seems to be the best way to
|
|
28
|
+
// prevent them (i.e. skipping useLayoutEffect when using jsdom).
|
|
29
|
+
const canUseLayoutEffect = (canUseDOM || isReactNative) && !usingJSDOM;
|
|
30
|
+
// Adapted from https://www.npmjs.com/package/use-sync-external-store, with
|
|
31
|
+
// Apollo Client deviations called out by "// DEVIATION ..." comments.
|
|
32
|
+
// When/if React.useSyncExternalStore is defined, delegate fully to it.
|
|
33
|
+
export const useSyncExternalStore =
|
|
34
|
+
realHook ||
|
|
35
|
+
((subscribe, getSnapshot, getServerSnapshot) => {
|
|
36
|
+
// Read the current snapshot from the store on every render. Again, this
|
|
37
|
+
// breaks the rules of React, and only works here because of specific
|
|
38
|
+
// implementation details, most importantly that updates are
|
|
39
|
+
// always synchronous.
|
|
40
|
+
const value = getSnapshot();
|
|
41
|
+
if (
|
|
42
|
+
// DEVIATION: Using __DEV__
|
|
43
|
+
__DEV__ &&
|
|
44
|
+
!didWarnUncachedGetSnapshot &&
|
|
45
|
+
// DEVIATION: Not using Object.is because we know our snapshots will never
|
|
46
|
+
// be exotic primitive values like NaN, which is !== itself.
|
|
47
|
+
value !== getSnapshot()
|
|
48
|
+
) {
|
|
49
|
+
didWarnUncachedGetSnapshot = true;
|
|
50
|
+
// DEVIATION: Using invariant.error instead of console.error directly.
|
|
51
|
+
invariant.error(34);
|
|
52
|
+
}
|
|
53
|
+
// Because updates are synchronous, we don't queue them. Instead we force a
|
|
54
|
+
// re-render whenever the subscribed state changes by updating an some
|
|
55
|
+
// arbitrary useState hook. Then, during render, we call getSnapshot to read
|
|
56
|
+
// the current value.
|
|
57
|
+
//
|
|
58
|
+
// Because we don't actually use the state returned by the useState hook, we
|
|
59
|
+
// can save a bit of memory by storing other stuff in that slot.
|
|
60
|
+
//
|
|
61
|
+
// To implement the early bailout, we need to track some things on a mutable
|
|
62
|
+
// object. Usually, we would put that in a useRef hook, but we can stash it in
|
|
63
|
+
// our useState hook instead.
|
|
64
|
+
//
|
|
65
|
+
// To force a re-render, we call forceUpdate({inst}). That works because the
|
|
66
|
+
// new object always fails an equality check.
|
|
67
|
+
const [{ inst }, forceUpdate] = React.useState({
|
|
68
|
+
inst: { value, getSnapshot },
|
|
69
|
+
});
|
|
70
|
+
// Track the latest getSnapshot function with a ref. This needs to be updated
|
|
71
|
+
// in the layout phase so we can access it during the tearing check that
|
|
72
|
+
// happens on subscribe.
|
|
73
|
+
if (canUseLayoutEffect) {
|
|
74
|
+
// DEVIATION: We avoid calling useLayoutEffect when !canUseLayoutEffect,
|
|
75
|
+
// which may seem like a conditional hook, but this code ends up behaving
|
|
76
|
+
// unconditionally (one way or the other) because canUseLayoutEffect is
|
|
77
|
+
// constant.
|
|
78
|
+
React.useLayoutEffect(() => {
|
|
79
|
+
Object.assign(inst, { value, getSnapshot });
|
|
80
|
+
// Whenever getSnapshot or subscribe changes, we need to check in the
|
|
81
|
+
// commit phase if there was an interleaved mutation. In concurrent mode
|
|
82
|
+
// this can happen all the time, but even in synchronous mode, an earlier
|
|
83
|
+
// effect may have mutated the store.
|
|
84
|
+
if (checkIfSnapshotChanged(inst)) {
|
|
85
|
+
// Force a re-render.
|
|
86
|
+
forceUpdate({ inst });
|
|
87
|
+
}
|
|
88
|
+
// React Hook React.useLayoutEffect has a missing dependency: 'inst'. Either include it or remove the dependency array.
|
|
89
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
90
|
+
}, [subscribe, value, getSnapshot]);
|
|
91
|
+
} else {
|
|
92
|
+
Object.assign(inst, { value, getSnapshot });
|
|
93
|
+
}
|
|
94
|
+
React.useEffect(() => {
|
|
95
|
+
// Check for changes right before subscribing. Subsequent changes will be
|
|
96
|
+
// detected in the subscription handler.
|
|
97
|
+
if (checkIfSnapshotChanged(inst)) {
|
|
98
|
+
// Force a re-render.
|
|
99
|
+
forceUpdate({ inst });
|
|
100
|
+
}
|
|
101
|
+
// Subscribe to the store and return a clean-up function.
|
|
102
|
+
return subscribe(function handleStoreChange() {
|
|
103
|
+
// TODO: Because there is no cross-renderer API for batching updates, it's
|
|
104
|
+
// up to the consumer of this library to wrap their subscription event
|
|
105
|
+
// with unstable_batchedUpdates. Should we try to detect when this isn't
|
|
106
|
+
// the case and print a warning in development?
|
|
107
|
+
// The store changed. Check if the snapshot changed since the last time we
|
|
108
|
+
// read from the store.
|
|
109
|
+
if (checkIfSnapshotChanged(inst)) {
|
|
110
|
+
// Force a re-render.
|
|
111
|
+
forceUpdate({ inst });
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
// React Hook React.useEffect has a missing dependency: 'inst'. Either include it or remove the dependency array.
|
|
115
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
116
|
+
}, [subscribe]);
|
|
117
|
+
return value;
|
|
118
|
+
});
|
|
119
|
+
function checkIfSnapshotChanged({ value, getSnapshot }) {
|
|
120
|
+
try {
|
|
121
|
+
return value !== getSnapshot();
|
|
122
|
+
} catch {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export type { ApolloContextValue } from './context/ApolloContext.js';
|
|
2
|
+
export { getApolloContext } from './context/ApolloContext.js';
|
|
3
|
+
export { ApolloProvider } from './context/ApolloProvider.js';
|
|
4
|
+
export { useApolloClient } from './hooks/useApolloClient.js';
|
|
5
|
+
export { useLazyQuery } from './hooks/useLazyQuery.js';
|
|
6
|
+
export { useMutation } from './hooks/useMutation.js';
|
|
7
|
+
export { useQuery } from './hooks/useQuery.js';
|
|
8
|
+
export { useSubscription } from './hooks/useSubscription.js';
|
|
9
|
+
export { useReactiveVar } from './hooks/useReactiveVar.js';
|
|
10
|
+
export { useFragment } from './hooks/useFragment.js';
|
|
11
|
+
export { useSuspenseQuery } from './hooks/useSuspenseQuery.js';
|
|
12
|
+
export { useBackgroundQuery } from './hooks/useBackgroundQuery.js';
|
|
13
|
+
export { useSuspenseFragment } from './hooks/useSuspenseFragment.js';
|
|
14
|
+
export { useLoadableQuery } from './hooks/useLoadableQuery.js';
|
|
15
|
+
export { useQueryRefHandlers } from './hooks/useQueryRefHandlers.js';
|
|
16
|
+
export { useReadQuery } from './hooks/useReadQuery.js';
|
|
17
|
+
export { skipToken } from './hooks/constants.js';
|
|
18
|
+
export type { SkipToken } from './hooks/constants.js';
|
|
19
|
+
export type {
|
|
20
|
+
PreloadQueryFetchPolicy,
|
|
21
|
+
PreloadQueryFunction,
|
|
22
|
+
PreloadQueryOptions,
|
|
23
|
+
} from './query-preloader/createQueryPreloader.js';
|
|
24
|
+
export { createQueryPreloader } from './query-preloader/createQueryPreloader.js';
|
|
25
|
+
export type { PreloadedQueryRef, QueryRef } from '@octanejs/apollo-client/react/internal';
|
|
26
|
+
export type {
|
|
27
|
+
BackgroundQueryHookFetchPolicy,
|
|
28
|
+
BackgroundQueryHookOptions,
|
|
29
|
+
LazyQueryExecFunction,
|
|
30
|
+
LazyQueryHookExecOptions,
|
|
31
|
+
LazyQueryHookOptions,
|
|
32
|
+
LazyQueryResult,
|
|
33
|
+
LazyQueryResultTuple,
|
|
34
|
+
LoadableQueryFetchPolicy,
|
|
35
|
+
LoadableQueryHookOptions,
|
|
36
|
+
LoadQueryFunction,
|
|
37
|
+
MutationFunctionOptions,
|
|
38
|
+
MutationHookOptions,
|
|
39
|
+
MutationResult,
|
|
40
|
+
MutationTuple,
|
|
41
|
+
OnDataOptions,
|
|
42
|
+
OnSubscriptionDataOptions,
|
|
43
|
+
QueryHookOptions,
|
|
44
|
+
QueryResult,
|
|
45
|
+
SubscriptionHookOptions,
|
|
46
|
+
SubscriptionResult,
|
|
47
|
+
SuspenseQueryHookFetchPolicy,
|
|
48
|
+
SuspenseQueryHookOptions,
|
|
49
|
+
UseBackgroundQueryResult,
|
|
50
|
+
UseFragmentOptions,
|
|
51
|
+
UseFragmentResult,
|
|
52
|
+
UseLoadableQueryResult,
|
|
53
|
+
UseQueryRefHandlersResult,
|
|
54
|
+
UseReadQueryResult,
|
|
55
|
+
UseSuspenseFragmentOptions,
|
|
56
|
+
UseSuspenseFragmentResult,
|
|
57
|
+
UseSuspenseQueryResult,
|
|
58
|
+
} from './types/deprecated.js';
|
|
59
|
+
import type { HookWrappers } from './hooks/internal/wrapHook.js';
|
|
60
|
+
/**
|
|
61
|
+
* @internal
|
|
62
|
+
*
|
|
63
|
+
* @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
|
|
64
|
+
*/
|
|
65
|
+
export declare namespace InternalTypes {
|
|
66
|
+
export type { HookWrappers };
|
|
67
|
+
}
|
|
68
|
+
export declare const reactCompilerVersion: string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { getApolloContext } from './context/ApolloContext.js';
|
|
2
|
+
export { ApolloProvider } from './context/ApolloProvider.js';
|
|
3
|
+
export { useApolloClient } from './hooks/useApolloClient.js';
|
|
4
|
+
export { useLazyQuery } from './hooks/useLazyQuery.js';
|
|
5
|
+
export { useMutation } from './hooks/useMutation.js';
|
|
6
|
+
export { useQuery } from './hooks/useQuery.js';
|
|
7
|
+
export { useSubscription } from './hooks/useSubscription.js';
|
|
8
|
+
export { useReactiveVar } from './hooks/useReactiveVar.js';
|
|
9
|
+
export { useFragment } from './hooks/useFragment.js';
|
|
10
|
+
export { useSuspenseQuery } from './hooks/useSuspenseQuery.js';
|
|
11
|
+
export { useBackgroundQuery } from './hooks/useBackgroundQuery.js';
|
|
12
|
+
export { useSuspenseFragment } from './hooks/useSuspenseFragment.js';
|
|
13
|
+
export { useLoadableQuery } from './hooks/useLoadableQuery.js';
|
|
14
|
+
export { useQueryRefHandlers } from './hooks/useQueryRefHandlers.js';
|
|
15
|
+
export { useReadQuery } from './hooks/useReadQuery.js';
|
|
16
|
+
export { skipToken } from './hooks/constants.js';
|
|
17
|
+
export { createQueryPreloader } from './query-preloader/createQueryPreloader.js';
|
|
18
|
+
export const reactCompilerVersion = 'uncompiled';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ApolloClient, OperationVariables } from '@apollo/client';
|
|
2
|
+
import type { MaybeMasked } from '@apollo/client/masking';
|
|
3
|
+
import type { DecoratedPromise } from '@apollo/client/utilities/internal';
|
|
4
|
+
import type { FragmentKey } from './types.js';
|
|
5
|
+
type FragmentRefPromise<TData> = DecoratedPromise<TData>;
|
|
6
|
+
type Listener<TData> = (promise: FragmentRefPromise<TData>) => void;
|
|
7
|
+
interface FragmentReferenceOptions {
|
|
8
|
+
autoDisposeTimeoutMs?: number;
|
|
9
|
+
onDispose?: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare class FragmentReference<
|
|
12
|
+
TData = unknown,
|
|
13
|
+
TVariables extends OperationVariables = OperationVariables,
|
|
14
|
+
> {
|
|
15
|
+
readonly observable: ApolloClient.ObservableFragment<TData | null>;
|
|
16
|
+
readonly key: FragmentKey;
|
|
17
|
+
promise: FragmentRefPromise<MaybeMasked<TData>>;
|
|
18
|
+
private resolve;
|
|
19
|
+
private reject;
|
|
20
|
+
private subscription;
|
|
21
|
+
private listeners;
|
|
22
|
+
private autoDisposeTimeoutId?;
|
|
23
|
+
private references;
|
|
24
|
+
constructor(
|
|
25
|
+
client: ApolloClient,
|
|
26
|
+
watchFragmentOptions: ApolloClient.WatchFragmentOptions<TData, TVariables> & {
|
|
27
|
+
from: string | null | Array<string | null>;
|
|
28
|
+
},
|
|
29
|
+
options: FragmentReferenceOptions,
|
|
30
|
+
);
|
|
31
|
+
listen(listener: Listener<MaybeMasked<TData>>): () => void;
|
|
32
|
+
retain(): () => void;
|
|
33
|
+
private dispose;
|
|
34
|
+
private onDispose;
|
|
35
|
+
private subscribeToFragment;
|
|
36
|
+
private handleNext;
|
|
37
|
+
private handleError;
|
|
38
|
+
private deliver;
|
|
39
|
+
private createPendingPromise;
|
|
40
|
+
}
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { equal } from '@wry/equality';
|
|
2
|
+
import { createFulfilledPromise, decoratePromise } from '@apollo/client/utilities/internal';
|
|
3
|
+
export class FragmentReference {
|
|
4
|
+
observable;
|
|
5
|
+
key = {};
|
|
6
|
+
promise;
|
|
7
|
+
resolve;
|
|
8
|
+
reject;
|
|
9
|
+
subscription;
|
|
10
|
+
listeners = new Set();
|
|
11
|
+
autoDisposeTimeoutId;
|
|
12
|
+
references = 0;
|
|
13
|
+
constructor(client, watchFragmentOptions, options) {
|
|
14
|
+
this.dispose = this.dispose.bind(this);
|
|
15
|
+
this.handleNext = this.handleNext.bind(this);
|
|
16
|
+
this.handleError = this.handleError.bind(this);
|
|
17
|
+
this.observable = client.watchFragment(watchFragmentOptions);
|
|
18
|
+
if (options.onDispose) {
|
|
19
|
+
this.onDispose = options.onDispose;
|
|
20
|
+
}
|
|
21
|
+
const result = this.observable.getCurrentResult();
|
|
22
|
+
// Start a timer that will automatically dispose of the query if the
|
|
23
|
+
// suspended resource does not use this fragmentRef in the given time. This
|
|
24
|
+
// helps prevent memory leaks when a component has unmounted before the
|
|
25
|
+
// query has finished loading.
|
|
26
|
+
const startDisposeTimer = () => {
|
|
27
|
+
if (!this.references) {
|
|
28
|
+
this.autoDisposeTimeoutId = setTimeout(
|
|
29
|
+
this.dispose,
|
|
30
|
+
options.autoDisposeTimeoutMs ?? 30_000,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
this.promise = result.complete
|
|
35
|
+
? createFulfilledPromise(result.data)
|
|
36
|
+
: this.createPendingPromise();
|
|
37
|
+
this.subscribeToFragment();
|
|
38
|
+
this.promise.then(startDisposeTimer, startDisposeTimer);
|
|
39
|
+
}
|
|
40
|
+
listen(listener) {
|
|
41
|
+
this.listeners.add(listener);
|
|
42
|
+
return () => {
|
|
43
|
+
this.listeners.delete(listener);
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
retain() {
|
|
47
|
+
this.references++;
|
|
48
|
+
clearTimeout(this.autoDisposeTimeoutId);
|
|
49
|
+
let disposed = false;
|
|
50
|
+
return () => {
|
|
51
|
+
if (disposed) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
disposed = true;
|
|
55
|
+
this.references--;
|
|
56
|
+
setTimeout(() => {
|
|
57
|
+
if (!this.references) {
|
|
58
|
+
this.dispose();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
dispose() {
|
|
64
|
+
this.subscription.unsubscribe();
|
|
65
|
+
}
|
|
66
|
+
onDispose() {
|
|
67
|
+
// noop. overridable by options
|
|
68
|
+
}
|
|
69
|
+
subscribeToFragment() {
|
|
70
|
+
this.subscription = this.observable.subscribe(
|
|
71
|
+
this.handleNext.bind(this),
|
|
72
|
+
this.handleError.bind(this),
|
|
73
|
+
);
|
|
74
|
+
// call `onDispose` when the subscription is finalized, either because it is
|
|
75
|
+
// unsubscribed as a consequence of a `dispose` call or because the
|
|
76
|
+
// ObservableQuery completes because of a `ApolloClient.stop()` call.
|
|
77
|
+
this.subscription.add(this.onDispose);
|
|
78
|
+
}
|
|
79
|
+
handleNext(result) {
|
|
80
|
+
switch (this.promise.status) {
|
|
81
|
+
case 'pending': {
|
|
82
|
+
if (result.complete) {
|
|
83
|
+
return this.resolve?.(result.data);
|
|
84
|
+
}
|
|
85
|
+
this.deliver(this.promise);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case 'fulfilled': {
|
|
89
|
+
// This can occur when we already have a result written to the cache and
|
|
90
|
+
// we subscribe for the first time. We create a fulfilled promise in the
|
|
91
|
+
// constructor with a value that is the same as the first emitted value
|
|
92
|
+
// so we want to skip delivering it.
|
|
93
|
+
if (equal(this.promise.value, result.data)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
this.promise = result.complete
|
|
97
|
+
? createFulfilledPromise(result.data)
|
|
98
|
+
: this.createPendingPromise();
|
|
99
|
+
this.deliver(this.promise);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
handleError(error) {
|
|
104
|
+
this.reject?.(error);
|
|
105
|
+
}
|
|
106
|
+
deliver(promise) {
|
|
107
|
+
this.listeners.forEach((listener) => listener(promise));
|
|
108
|
+
}
|
|
109
|
+
createPendingPromise() {
|
|
110
|
+
return decoratePromise(
|
|
111
|
+
new Promise((resolve, reject) => {
|
|
112
|
+
this.resolve = resolve;
|
|
113
|
+
this.reject = reject;
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DocumentTypeDecoration,
|
|
3
|
+
ResultOf,
|
|
4
|
+
VariablesOf,
|
|
5
|
+
} from '@graphql-typed-document-node/core';
|
|
6
|
+
import type { ApolloClient, DataState, ObservableQuery, OperationVariables } from '@apollo/client';
|
|
7
|
+
import type { MaybeMasked } from '@apollo/client/masking';
|
|
8
|
+
import type { DecoratedPromise } from '@apollo/client/utilities/internal';
|
|
9
|
+
import type { QueryKey } from './types.js';
|
|
10
|
+
type QueryRefPromise<TData, TStates extends DataState<TData>['dataState']> = DecoratedPromise<
|
|
11
|
+
ObservableQuery.Result<MaybeMasked<TData>, TStates>
|
|
12
|
+
>;
|
|
13
|
+
type Listener<TData, TStates extends DataState<TData>['dataState']> = (
|
|
14
|
+
promise: QueryRefPromise<TData, TStates>,
|
|
15
|
+
) => void;
|
|
16
|
+
declare const QUERY_REFERENCE_SYMBOL: unique symbol;
|
|
17
|
+
declare const PROMISE_SYMBOL: unique symbol;
|
|
18
|
+
declare const QUERY_REF_BRAND: unique symbol;
|
|
19
|
+
declare const PRELOADED_QUERY_REF_BRAND: unique symbol;
|
|
20
|
+
/**
|
|
21
|
+
* A `QueryReference` is an opaque object returned by `useBackgroundQuery`.
|
|
22
|
+
* A child component reading the `QueryReference` via `useReadQuery` will
|
|
23
|
+
* suspend until the promise resolves.
|
|
24
|
+
*/
|
|
25
|
+
export interface QueryRef<
|
|
26
|
+
TData = unknown,
|
|
27
|
+
TVariables extends OperationVariables = OperationVariables,
|
|
28
|
+
TStates extends DataState<TData>['dataState'] = 'complete' | 'streaming',
|
|
29
|
+
> {
|
|
30
|
+
/**
|
|
31
|
+
* @internal
|
|
32
|
+
*
|
|
33
|
+
* @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
|
|
34
|
+
*/
|
|
35
|
+
[QUERY_REF_BRAND]?(variables: TVariables): {
|
|
36
|
+
data: TData;
|
|
37
|
+
states: TStates;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export declare namespace QueryRef {
|
|
41
|
+
type ForQuery<
|
|
42
|
+
Document extends DocumentTypeDecoration<any, any>,
|
|
43
|
+
TStates extends DataState<ResultOf<Document>>['dataState'] = 'complete' | 'streaming',
|
|
44
|
+
> = QueryRef<ResultOf<Document>, VariablesOf<Document>, TStates>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* @internal
|
|
48
|
+
* For usage in internal helpers only.
|
|
49
|
+
*
|
|
50
|
+
* @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
|
|
51
|
+
*/
|
|
52
|
+
interface WrappedQueryRef<
|
|
53
|
+
TData = unknown,
|
|
54
|
+
TVariables extends OperationVariables = OperationVariables,
|
|
55
|
+
TStates extends DataState<TData>['dataState'] = 'complete' | 'streaming',
|
|
56
|
+
> extends QueryRef<TData, TVariables, TStates> {
|
|
57
|
+
/**
|
|
58
|
+
* @internal
|
|
59
|
+
*
|
|
60
|
+
* @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
|
|
61
|
+
*/
|
|
62
|
+
readonly [QUERY_REFERENCE_SYMBOL]: InternalQueryReference<TData, TStates>;
|
|
63
|
+
/**
|
|
64
|
+
* @internal
|
|
65
|
+
*
|
|
66
|
+
* @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
|
|
67
|
+
*/
|
|
68
|
+
[PROMISE_SYMBOL]: QueryRefPromise<TData, TStates>;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A `QueryReference` is an opaque object returned by `useBackgroundQuery`.
|
|
72
|
+
* A child component reading the `QueryReference` via `useReadQuery` will
|
|
73
|
+
* suspend until the promise resolves.
|
|
74
|
+
*/
|
|
75
|
+
export interface PreloadedQueryRef<
|
|
76
|
+
TData = unknown,
|
|
77
|
+
TVariables extends OperationVariables = OperationVariables,
|
|
78
|
+
TStates extends DataState<TData>['dataState'] = 'complete' | 'streaming',
|
|
79
|
+
> extends QueryRef<TData, TVariables, TStates> {
|
|
80
|
+
/**
|
|
81
|
+
* @internal
|
|
82
|
+
*
|
|
83
|
+
* @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
|
|
84
|
+
*/
|
|
85
|
+
[PRELOADED_QUERY_REF_BRAND]: typeof PRELOADED_QUERY_REF_BRAND;
|
|
86
|
+
}
|
|
87
|
+
interface InternalQueryReferenceOptions {
|
|
88
|
+
onDispose?: () => void;
|
|
89
|
+
autoDisposeTimeoutMs?: number;
|
|
90
|
+
}
|
|
91
|
+
export declare function wrapQueryRef<
|
|
92
|
+
TData,
|
|
93
|
+
TVariables extends OperationVariables,
|
|
94
|
+
TStates extends DataState<TData>['dataState'],
|
|
95
|
+
>(
|
|
96
|
+
internalQueryRef: InternalQueryReference<TData, TStates>,
|
|
97
|
+
): WrappedQueryRef<TData, TVariables, TStates>;
|
|
98
|
+
export declare function assertWrappedQueryRef<
|
|
99
|
+
TData,
|
|
100
|
+
TVariables extends OperationVariables,
|
|
101
|
+
TStates extends DataState<TData>['dataState'],
|
|
102
|
+
>(
|
|
103
|
+
queryRef: QueryRef<TData, TVariables, TStates>,
|
|
104
|
+
): asserts queryRef is WrappedQueryRef<TData, TVariables, TStates>;
|
|
105
|
+
export declare function assertWrappedQueryRef<
|
|
106
|
+
TData,
|
|
107
|
+
TVariables extends OperationVariables,
|
|
108
|
+
TStates extends DataState<TData>['dataState'],
|
|
109
|
+
>(
|
|
110
|
+
queryRef: QueryRef<TData, TVariables, TStates> | undefined | null,
|
|
111
|
+
): asserts queryRef is WrappedQueryRef<TData, TVariables, TStates> | undefined | null;
|
|
112
|
+
export declare function getWrappedPromise<TData, TStates extends DataState<TData>['dataState']>(
|
|
113
|
+
queryRef: WrappedQueryRef<TData, any, TStates>,
|
|
114
|
+
): QueryRefPromise<TData, TStates>;
|
|
115
|
+
export declare function unwrapQueryRef<TData, TStates extends DataState<TData>['dataState']>(
|
|
116
|
+
queryRef: WrappedQueryRef<TData, any, TStates>,
|
|
117
|
+
): InternalQueryReference<TData, TStates>;
|
|
118
|
+
export declare function unwrapQueryRef<TData, TStates extends DataState<TData>['dataState']>(
|
|
119
|
+
queryRef: Partial<WrappedQueryRef<TData, any, TStates>>,
|
|
120
|
+
): undefined | InternalQueryReference<TData, TStates>;
|
|
121
|
+
export declare function updateWrappedQueryRef<TData, TStates extends DataState<TData>['dataState']>(
|
|
122
|
+
queryRef: WrappedQueryRef<TData, any, TStates>,
|
|
123
|
+
promise: QueryRefPromise<TData, TStates>,
|
|
124
|
+
): void;
|
|
125
|
+
declare const OBSERVED_CHANGED_OPTIONS: readonly [
|
|
126
|
+
'context',
|
|
127
|
+
'errorPolicy',
|
|
128
|
+
'fetchPolicy',
|
|
129
|
+
'refetchOn',
|
|
130
|
+
'refetchWritePolicy',
|
|
131
|
+
'returnPartialData',
|
|
132
|
+
];
|
|
133
|
+
type ObservedOptions = Pick<
|
|
134
|
+
ApolloClient.WatchQueryOptions,
|
|
135
|
+
(typeof OBSERVED_CHANGED_OPTIONS)[number]
|
|
136
|
+
>;
|
|
137
|
+
export declare class InternalQueryReference<
|
|
138
|
+
TData = unknown,
|
|
139
|
+
TStates extends DataState<TData>['dataState'] = DataState<TData>['dataState'],
|
|
140
|
+
> {
|
|
141
|
+
result: ObservableQuery.Result<MaybeMasked<TData>, TStates>;
|
|
142
|
+
readonly key: QueryKey;
|
|
143
|
+
readonly observable: ObservableQuery<TData>;
|
|
144
|
+
promise: QueryRefPromise<TData, TStates>;
|
|
145
|
+
private queue;
|
|
146
|
+
private subscription;
|
|
147
|
+
private listeners;
|
|
148
|
+
private autoDisposeTimeoutId?;
|
|
149
|
+
private resolve;
|
|
150
|
+
private reject;
|
|
151
|
+
private references;
|
|
152
|
+
private softReferences;
|
|
153
|
+
constructor(observable: ObservableQuery<TData, any>, options: InternalQueryReferenceOptions);
|
|
154
|
+
get disposed(): boolean;
|
|
155
|
+
get watchQueryOptions(): ObservableQuery.Options<TData, OperationVariables>;
|
|
156
|
+
reinitialize(): void;
|
|
157
|
+
retain(): () => void;
|
|
158
|
+
softRetain(): () => void;
|
|
159
|
+
didChangeOptions(watchQueryOptions: ObservedOptions): boolean;
|
|
160
|
+
applyOptions(watchQueryOptions: ObservedOptions): QueryRefPromise<TData, TStates>;
|
|
161
|
+
listen(listener: Listener<TData, TStates>): () => void;
|
|
162
|
+
refetch(variables: OperationVariables | undefined): Promise<{
|
|
163
|
+
data: TData | undefined;
|
|
164
|
+
error?: import('@apollo/client').ErrorLike;
|
|
165
|
+
}>;
|
|
166
|
+
fetchMore(options: ObservableQuery.FetchMoreOptions<TData, any, any, any>): Promise<{
|
|
167
|
+
data: TData | undefined;
|
|
168
|
+
error?: import('@apollo/client').ErrorLike;
|
|
169
|
+
}>;
|
|
170
|
+
private dispose;
|
|
171
|
+
private onDispose;
|
|
172
|
+
private handleNext;
|
|
173
|
+
private deliver;
|
|
174
|
+
private initiateFetch;
|
|
175
|
+
private subscribeToQuery;
|
|
176
|
+
private setResult;
|
|
177
|
+
private shouldReject;
|
|
178
|
+
private createPendingPromise;
|
|
179
|
+
}
|
|
180
|
+
export {};
|