@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
package/LICENSE
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Octane binding
|
|
2
|
+
==============
|
|
3
|
+
|
|
4
|
+
MIT License
|
|
5
|
+
|
|
6
|
+
Copyright (c) 2026 Dominic Gannaway
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
in the Software without restriction, including without limitation the rights
|
|
11
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
furnished to do so, subject to the following conditions:
|
|
14
|
+
|
|
15
|
+
The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
copies or substantial portions of the Software.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
SOFTWARE.
|
|
25
|
+
|
|
26
|
+
Apollo Client-derived adapter sources
|
|
27
|
+
=====================================
|
|
28
|
+
|
|
29
|
+
The MIT License (MIT)
|
|
30
|
+
|
|
31
|
+
Copyright (c) 2022 Apollo Graph, Inc. (Formerly Meteor Development Group, Inc.)
|
|
32
|
+
|
|
33
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
34
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
35
|
+
in the Software without restriction, including without limitation the rights
|
|
36
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
37
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
38
|
+
furnished to do so, subject to the following conditions:
|
|
39
|
+
|
|
40
|
+
The above copyright notice and this permission notice shall be included in all
|
|
41
|
+
copies or substantial portions of the Software.
|
|
42
|
+
|
|
43
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
44
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
45
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
46
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
47
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
48
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
49
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# @octanejs/apollo-client
|
|
2
|
+
|
|
3
|
+
Apollo Client 4 bindings for Octane. The package reuses Apollo's client, cache,
|
|
4
|
+
links, GraphQL types, and testing core unchanged, while porting the published
|
|
5
|
+
React hook adapter to Octane's compiler-slotted hooks.
|
|
6
|
+
|
|
7
|
+
The adapter is pinned and surface-tested against `@apollo/client@4.2.6`.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @octanejs/apollo-client @apollo/client graphql rxjs
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Use
|
|
16
|
+
|
|
17
|
+
Apollo 4 keeps its framework-neutral API at the package root and its component
|
|
18
|
+
adapter on `/react`. The Octane package mirrors that split:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import {
|
|
22
|
+
ApolloClient,
|
|
23
|
+
InMemoryCache,
|
|
24
|
+
HttpLink,
|
|
25
|
+
gql,
|
|
26
|
+
type TypedDocumentNode,
|
|
27
|
+
} from '@octanejs/apollo-client';
|
|
28
|
+
import { ApolloProvider, useQuery } from '@octanejs/apollo-client/react';
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```tsrx
|
|
32
|
+
interface ViewerData {
|
|
33
|
+
viewer: {
|
|
34
|
+
id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const client = new ApolloClient({
|
|
40
|
+
cache: new InMemoryCache(),
|
|
41
|
+
link: new HttpLink({ uri: '/graphql' }),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const GET_VIEWER: TypedDocumentNode<ViewerData> = gql`
|
|
45
|
+
query Viewer {
|
|
46
|
+
viewer {
|
|
47
|
+
id
|
|
48
|
+
name
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
function Viewer() @{
|
|
54
|
+
const result = useQuery(GET_VIEWER);
|
|
55
|
+
|
|
56
|
+
@if (result.loading) {
|
|
57
|
+
<p>Loading…</p>
|
|
58
|
+
} @else if (result.error) {
|
|
59
|
+
<p>{result.error.message}</p>
|
|
60
|
+
} @else {
|
|
61
|
+
<p>{(result.data?.viewer.name ?? 'Unknown viewer') as string}</p>
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function App() @{
|
|
66
|
+
<ApolloProvider client={client}>
|
|
67
|
+
<Viewer />
|
|
68
|
+
</ApolloProvider>
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The complete Apollo 4.2.6 client hook surface is available, including lazy
|
|
73
|
+
queries, mutations, subscriptions, fragments, Suspense queries, background and
|
|
74
|
+
loadable queries, query references, `skipToken`, and query preloading.
|
|
75
|
+
|
|
76
|
+
For tests, import Apollo's framework-neutral mocks from
|
|
77
|
+
`@octanejs/apollo-client/testing` and the Octane `MockedProvider` from
|
|
78
|
+
`@octanejs/apollo-client/testing/react`.
|
|
79
|
+
|
|
80
|
+
## Compatibility
|
|
81
|
+
|
|
82
|
+
- Hooks and public TypeScript overloads track Apollo Client 4.2.6.
|
|
83
|
+
- Suspense unwraps Apollo's stable query promises through Octane `use()` rather
|
|
84
|
+
than throwing promises.
|
|
85
|
+
- Omitted React dependency arrays that intentionally mean “every render” are
|
|
86
|
+
explicit `null` in the port so Octane does not infer a narrower dependency
|
|
87
|
+
set.
|
|
88
|
+
- React Server Components and Apollo's React Compiler output are out of scope.
|
|
89
|
+
- `MockedProvider` accepts normal Octane children blocks; use a descriptor-style
|
|
90
|
+
`children={<App />}` prop when `childProps` must be cloned onto the child.
|
|
91
|
+
- Apollo-aware buffered SSR/cache extraction is not included in this first
|
|
92
|
+
client release.
|
|
93
|
+
|
|
94
|
+
The adapter sources are derived from Apollo Client at commit
|
|
95
|
+
`f934b60720fc828a61e04b00988eeefb83d273bc`, under Apollo's MIT license. Local
|
|
96
|
+
changes are limited to Octane imports, hook semantics, Suspense site identity,
|
|
97
|
+
the render-phase guard, and the functional `MockedProvider`.
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@octanejs/apollo-client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22"
|
|
9
|
+
},
|
|
10
|
+
"description": "Apollo Client bindings for the octane renderer — reuses Apollo's framework-neutral core and ports its React adapter onto octane.",
|
|
11
|
+
"author": {
|
|
12
|
+
"name": "Dominic Gannaway",
|
|
13
|
+
"email": "dg@domgan.com"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/octanejs/octane.git",
|
|
21
|
+
"directory": "packages/apollo-client"
|
|
22
|
+
},
|
|
23
|
+
"main": "src/index.js",
|
|
24
|
+
"module": "src/index.js",
|
|
25
|
+
"types": "src/index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"src",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./src/index.d.ts",
|
|
33
|
+
"default": "./src/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./react": {
|
|
36
|
+
"types": "./src/react/index.d.ts",
|
|
37
|
+
"default": "./src/react/index.js"
|
|
38
|
+
},
|
|
39
|
+
"./react/internal": {
|
|
40
|
+
"types": "./src/react/internal/index.d.ts",
|
|
41
|
+
"default": "./src/react/internal/index.js"
|
|
42
|
+
},
|
|
43
|
+
"./testing": {
|
|
44
|
+
"types": "./src/testing/index.d.ts",
|
|
45
|
+
"default": "./src/testing/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./testing/react": {
|
|
48
|
+
"types": "./src/testing/react/index.d.ts",
|
|
49
|
+
"default": "./src/testing/react/index.js"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@graphql-typed-document-node/core": "^3.1.1",
|
|
54
|
+
"@wry/equality": "^0.5.6",
|
|
55
|
+
"@wry/trie": "^0.5.0"
|
|
56
|
+
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"@apollo/client": ">=4.2.6 <4.3.0",
|
|
59
|
+
"graphql": "^16.0.0 || ^17.0.0",
|
|
60
|
+
"rxjs": "^7.3.0",
|
|
61
|
+
"octane": "0.1.5"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@apollo/client": "4.2.6",
|
|
65
|
+
"@tsrx/react": "^0.2.37",
|
|
66
|
+
"esbuild": "^0.28.1",
|
|
67
|
+
"graphql": "^16.11.0",
|
|
68
|
+
"react": "^19.2.0",
|
|
69
|
+
"react-dom": "^19.2.0",
|
|
70
|
+
"rxjs": "^7.8.2",
|
|
71
|
+
"vitest": "^4.1.9",
|
|
72
|
+
"octane": "0.1.5"
|
|
73
|
+
},
|
|
74
|
+
"scripts": {
|
|
75
|
+
"test": "vitest run --root ../.. --project apollo-client"
|
|
76
|
+
}
|
|
77
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@apollo/client';
|
package/src/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Context } from 'octane';
|
|
2
|
+
import type { ApolloClient } from '@apollo/client';
|
|
3
|
+
import type { HookWrappers, wrapperSymbol } from '@octanejs/apollo-client/react/internal';
|
|
4
|
+
export interface ApolloContextValue {
|
|
5
|
+
client?: ApolloClient;
|
|
6
|
+
[wrapperSymbol]?: HookWrappers;
|
|
7
|
+
}
|
|
8
|
+
export declare function getApolloContext(): Context<ApolloContextValue>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from 'octane';
|
|
2
|
+
import { invariant } from '@apollo/client/utilities/invariant';
|
|
3
|
+
// To make sure Apollo Client doesn't create more than one React context
|
|
4
|
+
// (which can lead to problems like having an Apollo Client instance added
|
|
5
|
+
// in one context, then attempting to retrieve it from another different
|
|
6
|
+
// context), a single Apollo context is created and tracked in global state.
|
|
7
|
+
const contextKey = Symbol.for('__APOLLO_CONTEXT__');
|
|
8
|
+
export function getApolloContext() {
|
|
9
|
+
invariant('createContext' in React, 37);
|
|
10
|
+
let context = React.createContext[contextKey];
|
|
11
|
+
if (!context) {
|
|
12
|
+
Object.defineProperty(React.createContext, contextKey, {
|
|
13
|
+
value: (context = React.createContext({})),
|
|
14
|
+
enumerable: false,
|
|
15
|
+
writable: false,
|
|
16
|
+
configurable: true,
|
|
17
|
+
});
|
|
18
|
+
context.displayName = 'ApolloContext';
|
|
19
|
+
}
|
|
20
|
+
return context;
|
|
21
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ComponentBody } from 'octane';
|
|
2
|
+
import type { ApolloClient } from '@apollo/client';
|
|
3
|
+
export declare namespace ApolloProvider {
|
|
4
|
+
interface Props {
|
|
5
|
+
client: ApolloClient;
|
|
6
|
+
children?: unknown;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export declare const ApolloProvider: ComponentBody<ApolloProvider.Props>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from 'octane';
|
|
2
|
+
import { invariant } from '@apollo/client/utilities/invariant';
|
|
3
|
+
import { getApolloContext } from './ApolloContext.js';
|
|
4
|
+
export const ApolloProvider = ({ client, children }) => {
|
|
5
|
+
const ApolloContext = getApolloContext();
|
|
6
|
+
const parentContext = React.useContext(ApolloContext);
|
|
7
|
+
const context = React.useMemo(() => {
|
|
8
|
+
return {
|
|
9
|
+
...parentContext,
|
|
10
|
+
client: client || parentContext.client,
|
|
11
|
+
};
|
|
12
|
+
}, [parentContext, client]);
|
|
13
|
+
invariant(context.client, 38);
|
|
14
|
+
return React.createElement(ApolloContext.Provider, { value: context }, children);
|
|
15
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const skipToken = Symbol.for('apollo.skipToken');
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from 'octane';
|
|
2
|
+
const fallbackSite = Symbol('apollo.__use');
|
|
3
|
+
// Apollo's React adapter falls back to throwing decorated promises on React 18.
|
|
4
|
+
// Octane always has use(), and raw promise throws are errors rather than
|
|
5
|
+
// suspension. The public hook's compiler-provided site is threaded through on
|
|
6
|
+
// the server so conditional sibling hooks keep stable SSR cache identities.
|
|
7
|
+
export function __use(promise, site) {
|
|
8
|
+
return React.use(promise, site ?? fallbackSite);
|
|
9
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// These hooks are used internally and are not exported publicly by the library
|
|
2
|
+
export { useDeepMemo } from './useDeepMemo.js';
|
|
3
|
+
export { useRenderGuard } from './useRenderGuard.js';
|
|
4
|
+
export { useSuspenseHookCacheKey } from './useSuspenseHookCacheKey.js';
|
|
5
|
+
export { __use } from './__use.js';
|
|
6
|
+
export { wrapHook } from './wrapHook.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const ROOT_SITE = Symbol('apollo.root');
|
|
2
|
+
const subSites = new Map();
|
|
3
|
+
|
|
4
|
+
/** Return a stable child site for repeated helper hooks inside one public hook. */
|
|
5
|
+
export function subSite(site, tag) {
|
|
6
|
+
const parent = typeof site === 'symbol' ? site : ROOT_SITE;
|
|
7
|
+
let children = subSites.get(parent);
|
|
8
|
+
if (!children) subSites.set(parent, (children = new Map()));
|
|
9
|
+
let child = children.get(tag);
|
|
10
|
+
if (!child) {
|
|
11
|
+
child = Symbol(`${parent.description || 'apollo'}:${tag}`);
|
|
12
|
+
children.set(tag, child);
|
|
13
|
+
}
|
|
14
|
+
return child;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Compiler hook sites are symbols, but Apollo's skipToken is user data. */
|
|
18
|
+
export function isCompilerSite(value, reserved) {
|
|
19
|
+
return typeof value === 'symbol' && value !== reserved;
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { equal } from '@wry/equality';
|
|
2
|
+
import * as React from 'octane';
|
|
3
|
+
export function useDeepMemo(memoFn, deps, site) {
|
|
4
|
+
const ref = React.useRef(void 0, site);
|
|
5
|
+
// eslint-disable-next-line react-hooks/refs
|
|
6
|
+
if (!ref.current || !equal(ref.current.deps, deps)) {
|
|
7
|
+
ref.current = { value: memoFn(), deps };
|
|
8
|
+
}
|
|
9
|
+
// eslint-disable-next-line react-hooks/refs
|
|
10
|
+
return ref.current.value;
|
|
11
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from 'octane';
|
|
2
|
+
import { canUseDOM } from '@apollo/client/utilities/internal';
|
|
3
|
+
// use canUseDOM here instead of canUseLayoutEffect because we want to be able
|
|
4
|
+
// to use useLayoutEffect in our jest tests. useLayoutEffect seems to work fine
|
|
5
|
+
// in useSuspenseQuery tests, but to honor the original comment about the
|
|
6
|
+
// warnings for useSyncExternalStore implementation, canUseLayoutEffect is left
|
|
7
|
+
// alone.
|
|
8
|
+
export const useIsomorphicLayoutEffect = canUseDOM ? React.useLayoutEffect : React.useEffect;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useRenderGuard(): () => boolean;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from 'octane';
|
|
2
|
+
export function useRenderGuard() {
|
|
3
|
+
return React.useCallback(() => {
|
|
4
|
+
try {
|
|
5
|
+
// Unlike React, Octane context reads are valid outside a render. A
|
|
6
|
+
// slot-keyed hook is the reliable render-phase probe: conditional
|
|
7
|
+
// hooks are supported, and useRef throws when no component is active.
|
|
8
|
+
React.useRef(null);
|
|
9
|
+
return true;
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}, []);
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DocumentNode } from 'graphql';
|
|
2
|
+
import type { OperationVariables } from '@apollo/client';
|
|
3
|
+
import type { SkipToken } from '../constants.js';
|
|
4
|
+
export declare namespace useSuspenseHookCacheKey {
|
|
5
|
+
interface Options {
|
|
6
|
+
variables?: OperationVariables;
|
|
7
|
+
queryKey?: string | number | any[];
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export declare function useSuspenseHookCacheKey(
|
|
11
|
+
query: DocumentNode,
|
|
12
|
+
options: (SkipToken & Partial<useSuspenseHookCacheKey.Options>) | useSuspenseHookCacheKey.Options,
|
|
13
|
+
): [DocumentNode, string, ...any[]];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'octane';
|
|
2
|
+
import { canonicalStringify } from '@apollo/client/utilities';
|
|
3
|
+
import { skipToken } from '../constants.js';
|
|
4
|
+
export function useSuspenseHookCacheKey(query, options) {
|
|
5
|
+
const { queryKey = [], variables } = options;
|
|
6
|
+
const canonicalVariables = canonicalStringify(variables);
|
|
7
|
+
// This state value let's us maintain the variables used for the cache key
|
|
8
|
+
// when `skipToken` is used to skip a query after its been executed.
|
|
9
|
+
// Since options aren't provided when using `skipToken`, `variables` would
|
|
10
|
+
// otherwise disappear which means we'd return a new cache key without a
|
|
11
|
+
// variables value which creates a new `ObservableQuery` instance. This was
|
|
12
|
+
// particularly problematic when `refetchQueries` was used because it meant
|
|
13
|
+
// refetching against an `ObservableQuery` instance that had no variables.
|
|
14
|
+
let [cacheKeyVariables, setCacheKeyVariables] = React.useState(canonicalVariables);
|
|
15
|
+
if (options !== skipToken && cacheKeyVariables !== canonicalVariables) {
|
|
16
|
+
setCacheKeyVariables((cacheKeyVariables = canonicalVariables));
|
|
17
|
+
}
|
|
18
|
+
return [query, cacheKeyVariables, ...[].concat(queryKey)];
|
|
19
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { __DEV__ } from '@apollo/client/utilities/environment';
|
|
2
|
+
import { invariant } from '@apollo/client/utilities/invariant';
|
|
3
|
+
export function validateSuspenseHookOptions(options) {
|
|
4
|
+
const { fetchPolicy, returnPartialData } = options;
|
|
5
|
+
validateFetchPolicy(fetchPolicy);
|
|
6
|
+
validatePartialDataReturn(fetchPolicy, returnPartialData);
|
|
7
|
+
}
|
|
8
|
+
function validateFetchPolicy(fetchPolicy = 'cache-first') {
|
|
9
|
+
const supportedFetchPolicies = ['cache-first', 'network-only', 'no-cache', 'cache-and-network'];
|
|
10
|
+
invariant(supportedFetchPolicies.includes(fetchPolicy), 35, fetchPolicy);
|
|
11
|
+
}
|
|
12
|
+
function validatePartialDataReturn(fetchPolicy, returnPartialData) {
|
|
13
|
+
if (fetchPolicy === 'no-cache' && returnPartialData) {
|
|
14
|
+
__DEV__ && invariant.warn(36);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { ApolloClient } from '@apollo/client';
|
|
2
|
+
import type { ObservableQuery } from '@apollo/client';
|
|
3
|
+
import type { createQueryPreloader } from '@octanejs/apollo-client/react';
|
|
4
|
+
import type {
|
|
5
|
+
useBackgroundQuery,
|
|
6
|
+
useFragment,
|
|
7
|
+
useQuery,
|
|
8
|
+
useQueryRefHandlers,
|
|
9
|
+
useReadQuery,
|
|
10
|
+
useSuspenseFragment,
|
|
11
|
+
useSuspenseQuery,
|
|
12
|
+
} from '@octanejs/apollo-client/react';
|
|
13
|
+
type FunctionSignature<T> = T extends (...args: infer A) => infer R ? (...args: A) => R : never;
|
|
14
|
+
interface WrappableHooks {
|
|
15
|
+
createQueryPreloader: FunctionSignature<typeof createQueryPreloader>;
|
|
16
|
+
useQuery: FunctionSignature<typeof useQuery>;
|
|
17
|
+
useSuspenseQuery: FunctionSignature<typeof useSuspenseQuery>;
|
|
18
|
+
useSuspenseFragment: FunctionSignature<typeof useSuspenseFragment>;
|
|
19
|
+
useBackgroundQuery: FunctionSignature<typeof useBackgroundQuery>;
|
|
20
|
+
useReadQuery: FunctionSignature<typeof useReadQuery>;
|
|
21
|
+
useFragment: FunctionSignature<typeof useFragment>;
|
|
22
|
+
useQueryRefHandlers: FunctionSignature<typeof useQueryRefHandlers>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* @internal
|
|
26
|
+
* Can be used to correctly type the [Symbol.for("apollo.hook.wrappers")] property of
|
|
27
|
+
* `QueryManager`, to override/wrap hook functionality.
|
|
28
|
+
*
|
|
29
|
+
* @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
|
|
30
|
+
*/
|
|
31
|
+
export type HookWrappers = {
|
|
32
|
+
[K in keyof WrappableHooks]?: (originalHook: WrappableHooks[K]) => WrappableHooks[K];
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* @internal
|
|
36
|
+
*
|
|
37
|
+
* Makes an Apollo Client hook "wrappable".
|
|
38
|
+
* That means that the Apollo Client instance can expose a "wrapper" that will be
|
|
39
|
+
* used to wrap the original hook implementation with additional logic.
|
|
40
|
+
* @example
|
|
41
|
+
*
|
|
42
|
+
* ```tsx
|
|
43
|
+
* // this is already done in `@apollo/client` for all wrappable hooks (see `WrappableHooks`)
|
|
44
|
+
* // following this pattern
|
|
45
|
+
* function useQuery() {
|
|
46
|
+
* return wrapHook('useQuery', _useQuery, options.client)(query, options);
|
|
47
|
+
* }
|
|
48
|
+
* function _useQuery(query, options) {
|
|
49
|
+
* // original implementation
|
|
50
|
+
* }
|
|
51
|
+
*
|
|
52
|
+
* // this is what a library like `@apollo/client-react-streaming` would do
|
|
53
|
+
* class ApolloClientWithStreaming extends ApolloClient {
|
|
54
|
+
* constructor(options) {
|
|
55
|
+
* super(options);
|
|
56
|
+
* this.queryManager[Symbol.for("apollo.hook.wrappers")] = {
|
|
57
|
+
* useQuery: (original) => (query, options) => {
|
|
58
|
+
* console.log("useQuery was called with options", options);
|
|
59
|
+
* return original(query, options);
|
|
60
|
+
* }
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
* }
|
|
64
|
+
*
|
|
65
|
+
* // this will now log the options and then call the original `useQuery`
|
|
66
|
+
* const client = new ApolloClientWithStreaming({ ... });
|
|
67
|
+
* useQuery(query, { client });
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
|
|
71
|
+
*/
|
|
72
|
+
export declare function wrapHook<Hook extends (...args: any[]) => any>(
|
|
73
|
+
hookName: keyof WrappableHooks,
|
|
74
|
+
useHook: Hook,
|
|
75
|
+
clientOrObsQuery: ObservableQuery<any> | ApolloClient,
|
|
76
|
+
): Hook;
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as React from 'octane';
|
|
2
|
+
import { wrapperSymbol } from '@octanejs/apollo-client/react/internal';
|
|
3
|
+
// direct import to avoid circular dependency
|
|
4
|
+
import { getApolloContext } from '../../context/ApolloContext.js';
|
|
5
|
+
/**
|
|
6
|
+
* @internal
|
|
7
|
+
*
|
|
8
|
+
* Makes an Apollo Client hook "wrappable".
|
|
9
|
+
* That means that the Apollo Client instance can expose a "wrapper" that will be
|
|
10
|
+
* used to wrap the original hook implementation with additional logic.
|
|
11
|
+
* @example
|
|
12
|
+
*
|
|
13
|
+
* ```tsx
|
|
14
|
+
* // this is already done in `@apollo/client` for all wrappable hooks (see `WrappableHooks`)
|
|
15
|
+
* // following this pattern
|
|
16
|
+
* function useQuery() {
|
|
17
|
+
* return wrapHook('useQuery', _useQuery, options.client)(query, options);
|
|
18
|
+
* }
|
|
19
|
+
* function _useQuery(query, options) {
|
|
20
|
+
* // original implementation
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* // this is what a library like `@apollo/client-react-streaming` would do
|
|
24
|
+
* class ApolloClientWithStreaming extends ApolloClient {
|
|
25
|
+
* constructor(options) {
|
|
26
|
+
* super(options);
|
|
27
|
+
* this.queryManager[Symbol.for("apollo.hook.wrappers")] = {
|
|
28
|
+
* useQuery: (original) => (query, options) => {
|
|
29
|
+
* console.log("useQuery was called with options", options);
|
|
30
|
+
* return original(query, options);
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* // this will now log the options and then call the original `useQuery`
|
|
37
|
+
* const client = new ApolloClientWithStreaming({ ... });
|
|
38
|
+
* useQuery(query, { client });
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
|
|
42
|
+
*/
|
|
43
|
+
export function wrapHook(hookName, useHook, clientOrObsQuery) {
|
|
44
|
+
// Priority-wise, the later entries in this array wrap
|
|
45
|
+
// previous entries and could prevent them (and in the end,
|
|
46
|
+
// even the original hook) from running
|
|
47
|
+
const wrapperSources = [
|
|
48
|
+
clientOrObsQuery['queryManager'],
|
|
49
|
+
// if we are a hook (not `preloadQuery`), we are guaranteed to be inside of
|
|
50
|
+
// a React render and can use context
|
|
51
|
+
hookName.startsWith('use')
|
|
52
|
+
? // eslint-disable-next-line react-hooks/rules-of-hooks
|
|
53
|
+
React.useContext(getApolloContext())
|
|
54
|
+
: undefined,
|
|
55
|
+
];
|
|
56
|
+
let wrapped = useHook;
|
|
57
|
+
for (const source of wrapperSources) {
|
|
58
|
+
const wrapper = source?.[wrapperSymbol]?.[hookName];
|
|
59
|
+
if (wrapper) {
|
|
60
|
+
wrapped = wrapper(wrapped);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return wrapped;
|
|
64
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ApolloClient } from '@apollo/client';
|
|
2
|
+
/**
|
|
3
|
+
* @example
|
|
4
|
+
*
|
|
5
|
+
* ```jsx
|
|
6
|
+
* import { useApolloClient } from "@octanejs/apollo-client/react";
|
|
7
|
+
*
|
|
8
|
+
* function SomeComponent() {
|
|
9
|
+
* const client = useApolloClient();
|
|
10
|
+
* // `client` is now set to the `ApolloClient` instance being used by the
|
|
11
|
+
* // application (that was configured using something like `ApolloProvider`)
|
|
12
|
+
* }
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @returns The `ApolloClient` instance being used by the application.
|
|
16
|
+
*/
|
|
17
|
+
export declare function useApolloClient(override?: ApolloClient): ApolloClient;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from 'octane';
|
|
2
|
+
import { invariant } from '@apollo/client/utilities/invariant';
|
|
3
|
+
import { getApolloContext } from '../context/ApolloContext.js';
|
|
4
|
+
/**
|
|
5
|
+
* @example
|
|
6
|
+
*
|
|
7
|
+
* ```jsx
|
|
8
|
+
* import { useApolloClient } from "@octanejs/apollo-client/react";
|
|
9
|
+
*
|
|
10
|
+
* function SomeComponent() {
|
|
11
|
+
* const client = useApolloClient();
|
|
12
|
+
* // `client` is now set to the `ApolloClient` instance being used by the
|
|
13
|
+
* // application (that was configured using something like `ApolloProvider`)
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @returns The `ApolloClient` instance being used by the application.
|
|
18
|
+
*/
|
|
19
|
+
export function useApolloClient(override) {
|
|
20
|
+
// A zero-argument custom hook call is compiled as useApolloClient(site).
|
|
21
|
+
// ApolloClient is an object, so a symbol here can only be Octane's site.
|
|
22
|
+
if (typeof override === 'symbol') override = undefined;
|
|
23
|
+
const context = React.useContext(getApolloContext());
|
|
24
|
+
const client = override || context.client;
|
|
25
|
+
invariant(!!client, 28);
|
|
26
|
+
return client;
|
|
27
|
+
}
|