1
1
import type { ApolloClient } from "@apollo/client/index.js" ;
2
2
import { cache } from "react" ;
3
3
4
+ const seenWrappers = WeakSet
5
+ ? new WeakSet < { client : ApolloClient < any > | Promise < ApolloClient < any > > } > ( )
6
+ : undefined ;
7
+ const seenClients = WeakSet
8
+ ? new WeakSet < ApolloClient < any > | Promise < ApolloClient < any > > > ( )
9
+ : undefined ;
10
+
4
11
/**
5
12
* > This export is only available in React Server Components
6
13
*
7
- * Ensures that you can always access the same instance of ApolloClient
14
+ * Ensures that you can always access the same instance of ApolloClient
8
15
* during RSC for an ongoing request, while always returning
9
16
* a new instance for different requests.
10
17
*
@@ -26,7 +33,7 @@ export function registerApolloClient(
26
33
makeClient : ( ) => Promise < ApolloClient < any > >
27
34
) : { getClient : ( ) => Promise < ApolloClient < any > > } ;
28
35
/**
29
- * Ensures that you can always access the same instance of ApolloClient
36
+ * Ensures that you can always access the same instance of ApolloClient
30
37
* during RSC for an ongoing request, while always returning
31
38
* a new instance for different requests.
32
39
*
@@ -50,7 +57,19 @@ export function registerApolloClient(makeClient: () => ApolloClient<any>): {
50
57
export function registerApolloClient (
51
58
makeClient : ( ( ) => Promise < ApolloClient < any > > ) | ( ( ) => ApolloClient < any > )
52
59
) {
53
- function wrappedMakeClient ( ) {
60
+ // React invalidates the cache on each server request, so the wrapping
61
+ // object is needed to properly detect whether the client is a unique
62
+ // reference or not. We can warn if `cachedMakeWrappedClient` creates a new "wrapper",
63
+ // but with a `client` property that we have already seen before.
64
+ // In that case, not every call to `makeClient` would create a new
65
+ // `ApolloClient` instance.
66
+ function makeWrappedClient ( ) {
67
+ return { client : makeClient ( ) } ;
68
+ }
69
+
70
+ const cachedMakeWrappedClient = cache ( makeWrappedClient ) ;
71
+
72
+ function getClient ( ) {
54
73
if ( arguments . length ) {
55
74
throw new Error (
56
75
`
@@ -61,9 +80,27 @@ resulting in duplicate requests and a non-functional cache.
61
80
` . trim ( )
62
81
) ;
63
82
}
64
- return makeClient ( ) ;
83
+ const wrapper = cachedMakeWrappedClient ( ) ;
84
+ if ( seenWrappers && seenClients ) {
85
+ if ( ! seenWrappers . has ( wrapper ) ) {
86
+ if ( seenClients . has ( wrapper . client ) ) {
87
+ console . warn (
88
+ `
89
+ Multiple calls to \`getClient\` for different requests returned the same client instance.
90
+ This means that private user data could accidentally be shared between requests.
91
+ This happens, for example, if you create a global \`ApolloClient\` instance and your \`makeClient\`
92
+ implementation just looks like \`() => client\`.
93
+ Always call \`new ApolloClient\` **inside** your \`makeClient\` function and
94
+ return a new instance every time \`makeClient\` is called.
95
+ ` . trim ( )
96
+ ) ;
97
+ }
98
+ seenWrappers . add ( wrapper ) ;
99
+ seenClients . add ( wrapper . client ) ;
100
+ }
101
+ }
102
+ return wrapper . client ;
65
103
}
66
- const getClient = cache ( wrappedMakeClient ) ;
67
104
return {
68
105
getClient,
69
106
} ;
0 commit comments