@apollo/client-ai-apps 0.6.5 → 0.7.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/CHANGELOG.md +62 -0
- package/CONTRIBUTING.md +195 -0
- package/README.md +74 -0
- package/dist/core/AbstractApolloClient.d.ts +33 -0
- package/dist/core/AbstractApolloClient.d.ts.map +1 -0
- package/dist/core/AbstractApolloClient.js +129 -0
- package/dist/core/AbstractApolloClient.js.map +1 -0
- package/dist/core/ApolloClient.d.ts +3 -7
- package/dist/core/ApolloClient.d.ts.map +1 -1
- package/dist/core/ApolloClient.js +5 -4
- package/dist/core/ApolloClient.js.map +1 -1
- package/dist/{mcp/core → core}/McpAppManager.d.ts +14 -10
- package/dist/core/McpAppManager.d.ts.map +1 -0
- package/dist/core/McpAppManager.js +56 -0
- package/dist/core/McpAppManager.js.map +1 -0
- package/dist/core/typeRegistration.d.ts +0 -14
- package/dist/core/typeRegistration.d.ts.map +1 -1
- package/dist/core/typeRegistration.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mcp.d.ts +0 -1
- package/dist/index.mcp.d.ts.map +1 -1
- package/dist/index.mcp.js +0 -1
- package/dist/index.mcp.js.map +1 -1
- package/dist/index.openai.d.ts +0 -1
- package/dist/index.openai.d.ts.map +1 -1
- package/dist/index.openai.js +0 -1
- package/dist/index.openai.js.map +1 -1
- package/dist/link/ToolCallLink.d.ts +6 -1
- package/dist/link/ToolCallLink.d.ts.map +1 -1
- package/dist/link/ToolCallLink.js +17 -4
- package/dist/link/ToolCallLink.js.map +1 -1
- package/dist/link/ToolHydrationLink.d.ts +21 -0
- package/dist/link/ToolHydrationLink.d.ts.map +1 -0
- package/dist/link/ToolHydrationLink.js +57 -0
- package/dist/link/ToolHydrationLink.js.map +1 -0
- package/dist/mcp/core/ApolloClient.d.ts +3 -20
- package/dist/mcp/core/ApolloClient.d.ts.map +1 -1
- package/dist/mcp/core/ApolloClient.js +20 -101
- package/dist/mcp/core/ApolloClient.js.map +1 -1
- package/dist/mcp/index.d.ts +0 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +0 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/openai/core/ApolloClient.d.ts +3 -20
- package/dist/openai/core/ApolloClient.d.ts.map +1 -1
- package/dist/openai/core/ApolloClient.js +36 -101
- package/dist/openai/core/ApolloClient.js.map +1 -1
- package/dist/openai/index.d.ts +0 -1
- package/dist/openai/index.d.ts.map +1 -1
- package/dist/openai/index.js +0 -1
- package/dist/openai/index.js.map +1 -1
- package/dist/openai/react/index.d.ts +0 -7
- package/dist/openai/react/index.d.ts.map +1 -1
- package/dist/openai/react/index.js +0 -7
- package/dist/openai/react/index.js.map +1 -1
- package/dist/react/ApolloProvider.d.ts.map +1 -1
- package/dist/react/ApolloProvider.js +1 -1
- package/dist/react/ApolloProvider.js.map +1 -1
- package/dist/{mcp/react/hooks → react}/createHydrationUtils.d.ts +1 -1
- package/dist/react/createHydrationUtils.d.ts.map +1 -0
- package/dist/{mcp/react/hooks → react}/createHydrationUtils.js +7 -9
- package/dist/react/createHydrationUtils.js.map +1 -0
- package/dist/react/hooks/internal/useApolloClient.d.ts +3 -0
- package/dist/react/hooks/internal/useApolloClient.d.ts.map +1 -0
- package/dist/{mcp/react/hooks → react/hooks/internal}/useApolloClient.js +3 -3
- package/dist/react/hooks/internal/useApolloClient.js.map +1 -0
- package/dist/react/hooks/useApp.d.ts.map +1 -0
- package/dist/react/hooks/useApp.js +5 -0
- package/dist/react/hooks/useApp.js.map +1 -0
- package/dist/react/hooks/useHostContext.d.ts.map +1 -0
- package/dist/{openai/react → react}/hooks/useHostContext.js +1 -1
- package/dist/react/hooks/useHostContext.js.map +1 -0
- package/dist/react/hooks/useToolInfo.d.ts +3 -0
- package/dist/react/hooks/useToolInfo.d.ts.map +1 -0
- package/dist/react/hooks/useToolInfo.js +5 -0
- package/dist/react/hooks/useToolInfo.js.map +1 -0
- package/dist/react/hooks/useToolMetadata.d.ts +2 -0
- package/dist/react/hooks/useToolMetadata.d.ts.map +1 -0
- package/dist/react/hooks/useToolMetadata.js +5 -0
- package/dist/react/hooks/useToolMetadata.js.map +1 -0
- package/dist/react/index.d.ts +5 -16
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +5 -19
- package/dist/react/index.js.map +1 -1
- package/dist/utilities/connectToHost.d.ts +3 -0
- package/dist/utilities/connectToHost.d.ts.map +1 -0
- package/dist/utilities/connectToHost.js +11 -0
- package/dist/utilities/connectToHost.js.map +1 -0
- package/dist/utilities/index.d.ts +1 -0
- package/dist/utilities/index.d.ts.map +1 -1
- package/dist/utilities/index.js +1 -0
- package/dist/utilities/index.js.map +1 -1
- package/package.json +5 -22
- package/src/core/AbstractApolloClient.ts +217 -0
- package/src/core/ApolloClient.ts +8 -10
- package/src/core/McpAppManager.ts +106 -0
- package/src/core/typeRegistration.ts +0 -15
- package/src/index.mcp.ts +0 -1
- package/src/index.openai.ts +0 -1
- package/src/index.ts +1 -6
- package/src/link/ToolCallLink.ts +27 -5
- package/src/link/ToolHydrationLink.ts +90 -0
- package/src/link/__tests__/ToolCallLink.test.ts +99 -0
- package/src/mcp/core/ApolloClient.ts +32 -170
- package/src/mcp/core/__tests__/ApolloClient.test.ts +398 -140
- package/src/mcp/index.ts +0 -1
- package/src/openai/core/ApolloClient.ts +48 -166
- package/src/openai/core/__tests__/ApolloClient.test.ts +680 -185
- package/src/openai/index.ts +0 -1
- package/src/openai/react/index.ts +0 -7
- package/src/react/ApolloProvider.tsx +1 -6
- package/src/react/__tests__/ApolloProvider/mcp.test.tsx +66 -29
- package/src/react/__tests__/ApolloProvider/openai.test.tsx +16 -41
- package/src/react/__tests__/createHydrationUtils.test.tsx +1260 -0
- package/src/{mcp/react/hooks → react}/createHydrationUtils.ts +7 -10
- package/src/react/hooks/__tests__/useApp.test.tsx +46 -0
- package/src/react/hooks/__tests__/useHostContext.test.tsx +99 -0
- package/src/react/hooks/__tests__/useToolInfo.test.tsx +98 -0
- package/src/react/hooks/__tests__/useToolMetadata.test.tsx +58 -0
- package/src/{mcp/react/hooks → react/hooks/internal}/useApolloClient.ts +3 -3
- package/src/{mcp/react → react}/hooks/useApp.ts +1 -1
- package/src/{openai/react → react}/hooks/useHostContext.ts +1 -1
- package/src/react/hooks/useToolInfo.ts +6 -0
- package/src/react/hooks/useToolMetadata.ts +5 -0
- package/src/react/index.ts +5 -36
- package/src/testing/internal/graphql/parseManifestOperation.ts +87 -0
- package/src/testing/internal/index.ts +3 -0
- package/src/testing/internal/matchers/index.ts +1 -0
- package/src/testing/internal/matchers/toEmitAnything.ts +43 -0
- package/src/testing/internal/matchers/types.ts +1 -0
- package/src/testing/internal/mcp/mockMcpHost.ts +25 -4
- package/src/testing/internal/tests/eachHostEnv.ts +22 -0
- package/src/testing/internal/utilities/createHostEnv.ts +117 -0
- package/src/utilities/connectToHost.ts +13 -0
- package/src/utilities/index.ts +1 -0
- package/tsconfig.vite.json +1 -1
- package/vitest.config.ts +13 -0
- package/dist/mcp/core/McpAppManager.d.ts.map +0 -1
- package/dist/mcp/core/McpAppManager.js +0 -88
- package/dist/mcp/core/McpAppManager.js.map +0 -1
- package/dist/mcp/link/ToolCallLink.d.ts +0 -28
- package/dist/mcp/link/ToolCallLink.d.ts.map +0 -1
- package/dist/mcp/link/ToolCallLink.js +0 -35
- package/dist/mcp/link/ToolCallLink.js.map +0 -1
- package/dist/mcp/react/hooks/createHydrationUtils.d.ts.map +0 -1
- package/dist/mcp/react/hooks/createHydrationUtils.js.map +0 -1
- package/dist/mcp/react/hooks/useApolloClient.d.ts +0 -3
- package/dist/mcp/react/hooks/useApolloClient.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useApolloClient.js.map +0 -1
- package/dist/mcp/react/hooks/useApp.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useApp.js +0 -5
- package/dist/mcp/react/hooks/useApp.js.map +0 -1
- package/dist/mcp/react/hooks/useHostContext.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useHostContext.js +0 -7
- package/dist/mcp/react/hooks/useHostContext.js.map +0 -1
- package/dist/mcp/react/hooks/useToolInfo.d.ts +0 -3
- package/dist/mcp/react/hooks/useToolInfo.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useToolInfo.js +0 -10
- package/dist/mcp/react/hooks/useToolInfo.js.map +0 -1
- package/dist/mcp/react/hooks/useToolInput.d.ts +0 -7
- package/dist/mcp/react/hooks/useToolInput.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useToolInput.js +0 -9
- package/dist/mcp/react/hooks/useToolInput.js.map +0 -1
- package/dist/mcp/react/hooks/useToolMetadata.d.ts +0 -2
- package/dist/mcp/react/hooks/useToolMetadata.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useToolMetadata.js +0 -5
- package/dist/mcp/react/hooks/useToolMetadata.js.map +0 -1
- package/dist/mcp/react/hooks/useToolName.d.ts +0 -7
- package/dist/mcp/react/hooks/useToolName.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useToolName.js +0 -9
- package/dist/mcp/react/hooks/useToolName.js.map +0 -1
- package/dist/mcp/react/index.d.ts +0 -8
- package/dist/mcp/react/index.d.ts.map +0 -1
- package/dist/mcp/react/index.js +0 -8
- package/dist/mcp/react/index.js.map +0 -1
- package/dist/openai/core/McpAppManager.d.ts +0 -37
- package/dist/openai/core/McpAppManager.d.ts.map +0 -1
- package/dist/openai/core/McpAppManager.js +0 -97
- package/dist/openai/core/McpAppManager.js.map +0 -1
- package/dist/openai/link/ToolCallLink.d.ts +0 -28
- package/dist/openai/link/ToolCallLink.d.ts.map +0 -1
- package/dist/openai/link/ToolCallLink.js +0 -35
- package/dist/openai/link/ToolCallLink.js.map +0 -1
- package/dist/openai/react/hooks/createHydrationUtils.d.ts +0 -15
- package/dist/openai/react/hooks/createHydrationUtils.d.ts.map +0 -1
- package/dist/openai/react/hooks/createHydrationUtils.js +0 -113
- package/dist/openai/react/hooks/createHydrationUtils.js.map +0 -1
- package/dist/openai/react/hooks/useApp.d.ts +0 -2
- package/dist/openai/react/hooks/useApp.d.ts.map +0 -1
- package/dist/openai/react/hooks/useApp.js +0 -5
- package/dist/openai/react/hooks/useApp.js.map +0 -1
- package/dist/openai/react/hooks/useHostContext.d.ts +0 -2
- package/dist/openai/react/hooks/useHostContext.d.ts.map +0 -1
- package/dist/openai/react/hooks/useHostContext.js.map +0 -1
- package/dist/openai/react/hooks/useToolInfo.d.ts +0 -3
- package/dist/openai/react/hooks/useToolInfo.d.ts.map +0 -1
- package/dist/openai/react/hooks/useToolInfo.js +0 -10
- package/dist/openai/react/hooks/useToolInfo.js.map +0 -1
- package/dist/openai/react/hooks/useToolInput.d.ts +0 -7
- package/dist/openai/react/hooks/useToolInput.d.ts.map +0 -1
- package/dist/openai/react/hooks/useToolInput.js +0 -9
- package/dist/openai/react/hooks/useToolInput.js.map +0 -1
- package/dist/openai/react/hooks/useToolMetadata.d.ts +0 -2
- package/dist/openai/react/hooks/useToolMetadata.d.ts.map +0 -1
- package/dist/openai/react/hooks/useToolMetadata.js +0 -5
- package/dist/openai/react/hooks/useToolMetadata.js.map +0 -1
- package/dist/openai/react/hooks/useToolName.d.ts +0 -7
- package/dist/openai/react/hooks/useToolName.d.ts.map +0 -1
- package/dist/openai/react/hooks/useToolName.js +0 -9
- package/dist/openai/react/hooks/useToolName.js.map +0 -1
- package/dist/react/index.mcp.d.ts +0 -3
- package/dist/react/index.mcp.d.ts.map +0 -1
- package/dist/react/index.mcp.js +0 -3
- package/dist/react/index.mcp.js.map +0 -1
- package/dist/react/index.openai.d.ts +0 -3
- package/dist/react/index.openai.d.ts.map +0 -1
- package/dist/react/index.openai.js +0 -3
- package/dist/react/index.openai.js.map +0 -1
- package/dist/react/missingHook.d.ts +0 -2
- package/dist/react/missingHook.d.ts.map +0 -1
- package/dist/react/missingHook.js +0 -6
- package/dist/react/missingHook.js.map +0 -1
- package/src/mcp/core/McpAppManager.ts +0 -136
- package/src/mcp/link/ToolCallLink.ts +0 -40
- package/src/mcp/link/__tests__/ToolCallLink.test.ts +0 -113
- package/src/mcp/react/hooks/__tests__/createHydrationUtils.test.tsx +0 -1228
- package/src/mcp/react/hooks/__tests__/useApp.test.tsx +0 -46
- package/src/mcp/react/hooks/__tests__/useHostContext.test.tsx +0 -95
- package/src/mcp/react/hooks/__tests__/useToolInfo.test.tsx +0 -53
- package/src/mcp/react/hooks/__tests__/useToolInput.test.tsx +0 -50
- package/src/mcp/react/hooks/__tests__/useToolMetadata.test.tsx +0 -53
- package/src/mcp/react/hooks/__tests__/useToolName.test.tsx +0 -50
- package/src/mcp/react/hooks/useHostContext.ts +0 -14
- package/src/mcp/react/hooks/useToolInfo.ts +0 -13
- package/src/mcp/react/hooks/useToolInput.ts +0 -10
- package/src/mcp/react/hooks/useToolMetadata.ts +0 -5
- package/src/mcp/react/hooks/useToolName.ts +0 -10
- package/src/mcp/react/index.ts +0 -7
- package/src/openai/core/McpAppManager.ts +0 -148
- package/src/openai/link/ToolCallLink.ts +0 -40
- package/src/openai/react/hooks/__tests__/createHydrationUtils.test.tsx +0 -1333
- package/src/openai/react/hooks/__tests__/useToolInfo.test.tsx +0 -92
- package/src/openai/react/hooks/__tests__/useToolInput.test.tsx +0 -85
- package/src/openai/react/hooks/__tests__/useToolMetadata.test.tsx +0 -86
- package/src/openai/react/hooks/__tests__/useToolName.test.tsx +0 -50
- package/src/openai/react/hooks/createHydrationUtils.ts +0 -182
- package/src/openai/react/hooks/useApp.ts +0 -5
- package/src/openai/react/hooks/useToolInfo.ts +0 -13
- package/src/openai/react/hooks/useToolInput.ts +0 -10
- package/src/openai/react/hooks/useToolMetadata.ts +0 -5
- package/src/openai/react/hooks/useToolName.ts +0 -10
- package/src/react/index.mcp.ts +0 -10
- package/src/react/index.openai.ts +0 -10
- package/src/react/missingHook.ts +0 -9
- /package/dist/{mcp/react → react}/hooks/useApp.d.ts +0 -0
- /package/dist/{mcp/react → react}/hooks/useHostContext.d.ts +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utilities/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,qCAAqC,EAAE,MAAM,4CAA4C,CAAC;AACnG,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC","sourcesContent":["export { aiClientSymbol } from \"./constants.js\";\nexport { getVariablesForOperationFromToolInput } from \"./getVariablesForOperationFromToolInput.js\";\nexport { getToolNamesFromDocument } from \"./getToolNamesFromDocument.js\";\nexport { getVariableNamesFromDocument } from \"./getVariableNamesFromDocument.js\";\nexport { cacheAsync } from \"./cacheAsync.js\";\nexport { invariant } from \"./invariant.js\";\nexport { promiseWithResolvers } from \"./promiseWithResolvers.js\";\nexport { warnOnVariableMismatch } from \"./warnOnVariableMismatch.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utilities/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,qCAAqC,EAAE,MAAM,4CAA4C,CAAC;AACnG,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC","sourcesContent":["export { aiClientSymbol } from \"./constants.js\";\nexport { connectToHost } from \"./connectToHost.js\";\nexport { getVariablesForOperationFromToolInput } from \"./getVariablesForOperationFromToolInput.js\";\nexport { getToolNamesFromDocument } from \"./getToolNamesFromDocument.js\";\nexport { getVariableNamesFromDocument } from \"./getVariableNamesFromDocument.js\";\nexport { cacheAsync } from \"./cacheAsync.js\";\nexport { invariant } from \"./invariant.js\";\nexport { promiseWithResolvers } from \"./promiseWithResolvers.js\";\nexport { warnOnVariableMismatch } from \"./warnOnVariableMismatch.js\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://www.schemastore.org/package.json",
|
|
3
3
|
"name": "@apollo/client-ai-apps",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -38,13 +38,6 @@
|
|
|
38
38
|
},
|
|
39
39
|
"default": "./dist/utilities/emptyModule.js"
|
|
40
40
|
},
|
|
41
|
-
"./mcp/react": {
|
|
42
|
-
"mcp": {
|
|
43
|
-
"types": "./dist/mcp/react/index.d.ts",
|
|
44
|
-
"default": "./dist/mcp/react/index.js"
|
|
45
|
-
},
|
|
46
|
-
"default": "./dist/utilities/emptyModule.js"
|
|
47
|
-
},
|
|
48
41
|
"./openai": {
|
|
49
42
|
"openai": {
|
|
50
43
|
"types": "./dist/openai/index.d.ts",
|
|
@@ -67,18 +60,8 @@
|
|
|
67
60
|
"default": "./dist/utilities/emptyModule.js"
|
|
68
61
|
},
|
|
69
62
|
"./react": {
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
"default": "./dist/react/index.mcp.js"
|
|
73
|
-
},
|
|
74
|
-
"openai": {
|
|
75
|
-
"types": "./dist/react/index.openai.d.ts",
|
|
76
|
-
"default": "./dist/react/index.openai.js"
|
|
77
|
-
},
|
|
78
|
-
"default": {
|
|
79
|
-
"types": "./dist/react/index.d.ts",
|
|
80
|
-
"default": "./dist/react/index.js"
|
|
81
|
-
}
|
|
63
|
+
"types": "./dist/react/index.d.ts",
|
|
64
|
+
"default": "./dist/react/index.js"
|
|
82
65
|
},
|
|
83
66
|
"./tsconfig/core": "./dist/tsconfig/core/tsconfig.json",
|
|
84
67
|
"./tsconfig/mcp": "./dist/tsconfig/mcp/tsconfig.json",
|
|
@@ -123,7 +106,7 @@
|
|
|
123
106
|
"@types/node": "^24.10.4",
|
|
124
107
|
"@types/react": "^19.2.2",
|
|
125
108
|
"@vitejs/plugin-react": "^5.1.1",
|
|
126
|
-
"@vitest/coverage-v8": "^4.0
|
|
109
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
127
110
|
"copyfiles": "^2.4.1",
|
|
128
111
|
"esbuild": "^0.25.12",
|
|
129
112
|
"graphql": "^16.12.0",
|
|
@@ -136,7 +119,7 @@
|
|
|
136
119
|
"rxjs": "^7.8.1",
|
|
137
120
|
"typescript": "^5.9.3",
|
|
138
121
|
"vite": "^7.3.1",
|
|
139
|
-
"vitest": "^4.0
|
|
122
|
+
"vitest": "^4.1.0"
|
|
140
123
|
},
|
|
141
124
|
"peerDependencies": {
|
|
142
125
|
"@apollo/client": "^4.0.0",
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ApolloLink,
|
|
3
|
+
ApolloClient as NativeApolloClient,
|
|
4
|
+
DocumentTransform,
|
|
5
|
+
ObservableQuery,
|
|
6
|
+
type OperationVariables,
|
|
7
|
+
type WatchQueryOptions,
|
|
8
|
+
} from "@apollo/client";
|
|
9
|
+
import { __DEV__ } from "@apollo/client/utilities/environment";
|
|
10
|
+
import { removeDirectivesFromDocument } from "@apollo/client/utilities/internal";
|
|
11
|
+
import { parse, visit } from "graphql";
|
|
12
|
+
import { equal } from "@wry/equality";
|
|
13
|
+
import type { ApplicationManifest } from "../types/application-manifest.js";
|
|
14
|
+
import { aiClientSymbol } from "../utilities/constants.js";
|
|
15
|
+
import {
|
|
16
|
+
McpAppManager,
|
|
17
|
+
type ConnectToHostImplementation,
|
|
18
|
+
} from "./McpAppManager.js";
|
|
19
|
+
import { ToolHydrationLink } from "../link/ToolHydrationLink.js";
|
|
20
|
+
import { ToolCallLink } from "../link/ToolCallLink.js";
|
|
21
|
+
import {
|
|
22
|
+
cacheAsync,
|
|
23
|
+
getToolNamesFromDocument,
|
|
24
|
+
getVariableNamesFromDocument,
|
|
25
|
+
getVariablesForOperationFromToolInput,
|
|
26
|
+
warnOnVariableMismatch,
|
|
27
|
+
} from "../utilities/index.js";
|
|
28
|
+
import type { ApolloMcpServerApps } from "./types.js";
|
|
29
|
+
import type { ToolInfo } from "./typeRegistration.js";
|
|
30
|
+
|
|
31
|
+
export declare namespace AbstractApolloClient {
|
|
32
|
+
export interface Options extends Omit<NativeApolloClient.Options, "link"> {
|
|
33
|
+
link?: NativeApolloClient.Options["link"];
|
|
34
|
+
manifest: ApplicationManifest;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class AbstractApolloClient extends NativeApolloClient {
|
|
39
|
+
manifest: ApplicationManifest;
|
|
40
|
+
private readonly appManager: McpAppManager;
|
|
41
|
+
|
|
42
|
+
/** @internal */
|
|
43
|
+
readonly [aiClientSymbol] = true;
|
|
44
|
+
|
|
45
|
+
#hydratedToolInput: Record<string, unknown> | undefined;
|
|
46
|
+
#toolHydrationLink: ToolHydrationLink;
|
|
47
|
+
|
|
48
|
+
#toolInfo: ToolInfo | undefined;
|
|
49
|
+
#toolMetadata: ApolloMcpServerApps.CallToolResult["_meta"] | undefined;
|
|
50
|
+
|
|
51
|
+
constructor(
|
|
52
|
+
options: AbstractApolloClient.Options,
|
|
53
|
+
connectToHost: ConnectToHostImplementation
|
|
54
|
+
) {
|
|
55
|
+
const toolHydrationLink = new ToolHydrationLink();
|
|
56
|
+
const link = options.link ?? new ToolCallLink();
|
|
57
|
+
|
|
58
|
+
if (__DEV__) {
|
|
59
|
+
validateTerminatingLink(link);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
super({
|
|
63
|
+
...options,
|
|
64
|
+
link: toolHydrationLink.concat(link),
|
|
65
|
+
// Strip out the prefetch/tool directives so they don't get sent with the operation to the server
|
|
66
|
+
documentTransform: new DocumentTransform((document) => {
|
|
67
|
+
const serverDocument = removeDirectivesFromDocument(
|
|
68
|
+
[{ name: "prefetch" }, { name: "tool" }],
|
|
69
|
+
document
|
|
70
|
+
)!;
|
|
71
|
+
|
|
72
|
+
return visit(serverDocument, {
|
|
73
|
+
OperationDefinition(node) {
|
|
74
|
+
return { ...node, description: undefined };
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
}).concat(options.documentTransform ?? DocumentTransform.identity()),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
this.#toolHydrationLink = toolHydrationLink;
|
|
81
|
+
this.manifest = options.manifest;
|
|
82
|
+
this.appManager = new McpAppManager(this.manifest, connectToHost);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get toolInfo() {
|
|
86
|
+
return this.#toolInfo;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get toolMetadata() {
|
|
90
|
+
return this.#toolMetadata;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
setLink(newLink: ApolloLink): void {
|
|
94
|
+
super.setLink(this.#toolHydrationLink.concat(newLink));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
stop() {
|
|
98
|
+
super.stop();
|
|
99
|
+
this.appManager.close().catch(() => {});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
protected get hydratedToolInput() {
|
|
103
|
+
return this.#hydratedToolInput;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
protected clearHydratedToolInput() {
|
|
107
|
+
this.#hydratedToolInput = undefined;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
watchQuery<
|
|
111
|
+
T = any,
|
|
112
|
+
TVariables extends OperationVariables = OperationVariables,
|
|
113
|
+
>(options: WatchQueryOptions<TVariables, T>): ObservableQuery<T, TVariables> {
|
|
114
|
+
if (__DEV__) {
|
|
115
|
+
const toolInput = this.#hydratedToolInput;
|
|
116
|
+
|
|
117
|
+
if (toolInput) {
|
|
118
|
+
const toolName = this.toolInfo?.toolName;
|
|
119
|
+
const hasMatchingTool =
|
|
120
|
+
!!toolName && getToolNamesFromDocument(options.query).has(toolName);
|
|
121
|
+
|
|
122
|
+
if (hasMatchingTool) {
|
|
123
|
+
// Clear after first matching comparison so this only fires once and
|
|
124
|
+
// remounting doesn't produce spurious warnings.
|
|
125
|
+
this.#hydratedToolInput = undefined;
|
|
126
|
+
|
|
127
|
+
const variableNames = getVariableNamesFromDocument(options.query);
|
|
128
|
+
|
|
129
|
+
if (variableNames.size > 0) {
|
|
130
|
+
const { variables } = options;
|
|
131
|
+
const toolInputVariables = Object.entries(toolInput).filter(
|
|
132
|
+
([key]) => variableNames.has(key)
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const hasToolInputMismatch = toolInputVariables.some(
|
|
136
|
+
([key, value]) => !equal(value, variables?.[key])
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
if (hasToolInputMismatch) {
|
|
140
|
+
warnOnVariableMismatch(
|
|
141
|
+
options.query,
|
|
142
|
+
Object.fromEntries(toolInputVariables),
|
|
143
|
+
variables
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return super.watchQuery(options);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
connect = cacheAsync(async () => {
|
|
155
|
+
const { structuredContent, toolName, toolInput, _meta } =
|
|
156
|
+
await this.appManager.connect();
|
|
157
|
+
|
|
158
|
+
this.#hydratedToolInput = toolInput;
|
|
159
|
+
this.#toolMetadata = _meta;
|
|
160
|
+
|
|
161
|
+
if (toolName != null) {
|
|
162
|
+
this.#toolInfo = { toolName, toolInput };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
this.manifest.operations.forEach((operation) => {
|
|
166
|
+
if (
|
|
167
|
+
operation.prefetchID &&
|
|
168
|
+
structuredContent.prefetch?.[operation.prefetchID]
|
|
169
|
+
) {
|
|
170
|
+
this.writeQuery({
|
|
171
|
+
query: parse(operation.body),
|
|
172
|
+
data: structuredContent.prefetch[operation.prefetchID].data,
|
|
173
|
+
});
|
|
174
|
+
this.#toolHydrationLink.hydrate(operation, {
|
|
175
|
+
result: structuredContent.prefetch[operation.prefetchID],
|
|
176
|
+
variables: {},
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (
|
|
181
|
+
structuredContent.result &&
|
|
182
|
+
operation.tools.find((tool) => tool.name === toolName)
|
|
183
|
+
) {
|
|
184
|
+
this.#toolHydrationLink.hydrate(operation, {
|
|
185
|
+
result: structuredContent.result,
|
|
186
|
+
variables: getVariablesForOperationFromToolInput(
|
|
187
|
+
operation,
|
|
188
|
+
toolInput
|
|
189
|
+
),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
this.#toolHydrationLink.complete();
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function validateTerminatingLink(link: ApolloLink) {
|
|
199
|
+
let terminatingLink = link;
|
|
200
|
+
|
|
201
|
+
while (terminatingLink.right) {
|
|
202
|
+
terminatingLink = terminatingLink.right;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (
|
|
206
|
+
!isNamedLink(terminatingLink) ||
|
|
207
|
+
terminatingLink.name !== "ToolCallLink"
|
|
208
|
+
) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
"The terminating link must be a `ToolCallLink`. If you are using a `split` link, ensure the `right` branch uses a `ToolCallLink` as the terminating link."
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function isNamedLink(link: ApolloLink): link is ApolloLink & { name: string } {
|
|
216
|
+
return "name" in link;
|
|
217
|
+
}
|
package/src/core/ApolloClient.ts
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { ApplicationManifest } from "../types/application-manifest.js";
|
|
1
|
+
import { AbstractApolloClient } from "./AbstractApolloClient.js";
|
|
3
2
|
import { aiClientSymbol } from "../utilities/constants.js";
|
|
4
3
|
|
|
5
4
|
export declare namespace ApolloClient {
|
|
6
|
-
export interface Options extends
|
|
7
|
-
link?: BaseApolloClient.Options["link"];
|
|
8
|
-
manifest: ApplicationManifest;
|
|
9
|
-
}
|
|
5
|
+
export interface Options extends AbstractApolloClient.Options {}
|
|
10
6
|
}
|
|
11
7
|
|
|
12
|
-
export class ApolloClient extends
|
|
8
|
+
export class ApolloClient extends AbstractApolloClient {
|
|
13
9
|
/** @internal */
|
|
14
10
|
readonly [aiClientSymbol] = true;
|
|
15
11
|
|
|
16
12
|
constructor(options: ApolloClient.Options) {
|
|
17
|
-
super(options as any)
|
|
13
|
+
super(options as any, () => {
|
|
14
|
+
throw new Error(
|
|
15
|
+
"Cannot connect an `ApolloClient` instance from `@apollo/client-ai-apps` without export conditions. Please set conditions or import from the `/openai` or `/mcp` subpath directly."
|
|
16
|
+
);
|
|
17
|
+
});
|
|
18
18
|
|
|
19
19
|
throw new Error(
|
|
20
20
|
"Cannot construct an `ApolloClient` instance from `@apollo/client-ai-apps` without export conditions. Please set conditions or import from the `/openai` or `/mcp` subpath directly."
|
|
21
21
|
);
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
async connect() {}
|
|
25
23
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import {
|
|
2
|
+
App,
|
|
3
|
+
type McpUiHostContextChangedNotification,
|
|
4
|
+
} from "@modelcontextprotocol/ext-apps";
|
|
5
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
import type { ApplicationManifest } from "../types/application-manifest.js";
|
|
7
|
+
import type { FormattedExecutionResult } from "graphql";
|
|
8
|
+
import type { DocumentNode, OperationVariables } from "@apollo/client";
|
|
9
|
+
import { print } from "@apollo/client/utilities";
|
|
10
|
+
import { cacheAsync } from "../utilities/index.js";
|
|
11
|
+
import type { ApolloMcpServerApps } from "./types.js";
|
|
12
|
+
|
|
13
|
+
type ExecuteQueryCallToolResult = Omit<CallToolResult, "structuredContent"> & {
|
|
14
|
+
structuredContent: FormattedExecutionResult;
|
|
15
|
+
_meta?: { structuredContent?: FormattedExecutionResult };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
interface ConnectToHostResult {
|
|
19
|
+
structuredContent: ApolloMcpServerApps.StructuredContent;
|
|
20
|
+
toolInput: Record<string, unknown> | undefined;
|
|
21
|
+
_meta: ApolloMcpServerApps.Meta | undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type ConnectToHostImplementation = (
|
|
25
|
+
app: App
|
|
26
|
+
) => Promise<ConnectToHostResult>;
|
|
27
|
+
|
|
28
|
+
/** @internal */
|
|
29
|
+
export class McpAppManager {
|
|
30
|
+
readonly app: App;
|
|
31
|
+
|
|
32
|
+
#connectToHost: ConnectToHostImplementation;
|
|
33
|
+
|
|
34
|
+
#hostContextCallbacks = new Set<
|
|
35
|
+
(params: McpUiHostContextChangedNotification["params"]) => void
|
|
36
|
+
>();
|
|
37
|
+
|
|
38
|
+
constructor(
|
|
39
|
+
manifest: ApplicationManifest,
|
|
40
|
+
connectToHost: ConnectToHostImplementation
|
|
41
|
+
) {
|
|
42
|
+
this.app = new App({ name: manifest.name, version: manifest.appVersion });
|
|
43
|
+
this.#connectToHost = connectToHost;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
onHostContextChanged(
|
|
47
|
+
cb: (params: McpUiHostContextChangedNotification["params"]) => void
|
|
48
|
+
) {
|
|
49
|
+
this.#hostContextCallbacks.add(cb);
|
|
50
|
+
|
|
51
|
+
return () => {
|
|
52
|
+
this.#hostContextCallbacks.delete(cb);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
connect = cacheAsync(async () => {
|
|
57
|
+
this.app.onhostcontextchanged = (params) => {
|
|
58
|
+
this.#hostContextCallbacks.forEach((cb) => cb(params));
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const { structuredContent, _meta, toolInput } = await this.#connectToHost(
|
|
62
|
+
this.app
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
structuredContent: {
|
|
67
|
+
...structuredContent,
|
|
68
|
+
..._meta?.structuredContent,
|
|
69
|
+
},
|
|
70
|
+
toolInput,
|
|
71
|
+
// Some hosts do not provide toolInfo in the ui/initialize response, so we
|
|
72
|
+
// fallback to `_meta.toolName` provided by Apollo MCP server if the value
|
|
73
|
+
// is not available.
|
|
74
|
+
toolName:
|
|
75
|
+
this.app.getHostContext()?.toolInfo?.tool.name ??
|
|
76
|
+
_meta?.toolName ??
|
|
77
|
+
// Some hosts do not forward `_meta` nor do they provide `toolInfo`. Our
|
|
78
|
+
// MCP server provides `toolName` in `structuredContent` as a workaround
|
|
79
|
+
// that we can use if all else fails
|
|
80
|
+
structuredContent.toolName,
|
|
81
|
+
_meta,
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
close() {
|
|
86
|
+
return this.app.close();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async executeQuery({
|
|
90
|
+
query,
|
|
91
|
+
variables,
|
|
92
|
+
}: {
|
|
93
|
+
query: DocumentNode;
|
|
94
|
+
variables: OperationVariables | undefined;
|
|
95
|
+
}) {
|
|
96
|
+
const result = (await this.app.callServerTool({
|
|
97
|
+
name: "execute",
|
|
98
|
+
arguments: { query: print(query), variables },
|
|
99
|
+
})) as ExecuteQueryCallToolResult;
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
...result.structuredContent,
|
|
103
|
+
...result._meta?.structuredContent,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
export interface Register {}
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* @deprecated Please use the `ToolInfo` type instead. `ToolName` will be
|
|
5
|
-
* removed in the next major version.
|
|
6
|
-
*/
|
|
7
|
-
export type ToolName =
|
|
8
|
-
Register extends { toolName: infer T extends string } ? T : string;
|
|
9
|
-
|
|
10
3
|
type RegisteredToolInputs =
|
|
11
4
|
Register extends { toolInputs: infer T extends Record<string, unknown> } ? T
|
|
12
5
|
: never;
|
|
13
6
|
|
|
14
|
-
/**
|
|
15
|
-
* @deprecated Please use the `ToolInfo` type instead. `ToolInput` will be
|
|
16
|
-
* removed in the next major version.
|
|
17
|
-
*/
|
|
18
|
-
export type ToolInput =
|
|
19
|
-
[RegisteredToolInputs] extends [never] ? Record<string, unknown>
|
|
20
|
-
: RegisteredToolInputs[keyof RegisteredToolInputs];
|
|
21
|
-
|
|
22
7
|
type ToolInfoFromInputs<T extends Record<string, unknown>> = {
|
|
23
8
|
[K in keyof T]: {
|
|
24
9
|
toolName: K;
|
package/src/index.mcp.ts
CHANGED
package/src/index.openai.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -8,12 +8,7 @@ export type {
|
|
|
8
8
|
ManifestWidgetSettings,
|
|
9
9
|
} from "./types/application-manifest.js";
|
|
10
10
|
|
|
11
|
-
export type {
|
|
12
|
-
Register,
|
|
13
|
-
ToolInfo,
|
|
14
|
-
ToolInput,
|
|
15
|
-
ToolName,
|
|
16
|
-
} from "./core/typeRegistration.js";
|
|
11
|
+
export type { Register, ToolInfo } from "./core/typeRegistration.js";
|
|
17
12
|
|
|
18
13
|
export { ApolloClient } from "./core/ApolloClient.js";
|
|
19
14
|
export { ToolCallLink } from "./link/ToolCallLink.js";
|
package/src/link/ToolCallLink.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import { ApolloLink } from "@apollo/client";
|
|
1
|
+
import { ApolloClient, ApolloLink } from "@apollo/client";
|
|
2
|
+
import { __DEV__ } from "@apollo/client/utilities/environment";
|
|
3
|
+
import { from } from "rxjs";
|
|
4
|
+
|
|
5
|
+
import type { McpAppManager } from "../core/McpAppManager";
|
|
6
|
+
import { aiClientSymbol, invariant } from "../utilities/index.js";
|
|
2
7
|
|
|
3
8
|
/**
|
|
4
9
|
* A terminating link that sends a GraphQL request through an agent tool call.
|
|
@@ -23,11 +28,28 @@ import { ApolloLink } from "@apollo/client";
|
|
|
23
28
|
* ```
|
|
24
29
|
*/
|
|
25
30
|
export class ToolCallLink extends ApolloLink {
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
readonly name = "ToolCallLink";
|
|
32
|
+
request(operation: ApolloLink.Operation) {
|
|
33
|
+
const client = getPrivateAccess(operation.client);
|
|
34
|
+
|
|
35
|
+
return from(
|
|
36
|
+
client.appManager.executeQuery({
|
|
37
|
+
query: operation.query,
|
|
38
|
+
variables: operation.variables,
|
|
39
|
+
})
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
28
43
|
|
|
29
|
-
|
|
30
|
-
|
|
44
|
+
function getPrivateAccess(
|
|
45
|
+
client: ApolloClient
|
|
46
|
+
): ApolloClient & { appManager: McpAppManager } {
|
|
47
|
+
if (__DEV__) {
|
|
48
|
+
invariant(
|
|
49
|
+
(client as any)[aiClientSymbol],
|
|
50
|
+
'The "client" instance used with `ToolCallLink` is the wrong instance. You might have imported `ApolloClient` from `@apollo/client`. Please import `ApolloClient` from `@apollo/client-ai-apps` instead.'
|
|
31
51
|
);
|
|
32
52
|
}
|
|
53
|
+
|
|
54
|
+
return client as any;
|
|
33
55
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { ApolloLink, Observable } from "@apollo/client";
|
|
2
|
+
import type { OperationVariables } from "@apollo/client";
|
|
3
|
+
import { canonicalStringify } from "@apollo/client/utilities";
|
|
4
|
+
import type { FormattedExecutionResult } from "graphql";
|
|
5
|
+
import { of } from "rxjs";
|
|
6
|
+
import type { ManifestOperation } from "../types/application-manifest.js";
|
|
7
|
+
|
|
8
|
+
type ResolveFn = () => void;
|
|
9
|
+
type OperationKey = string & { __type: "PendingKey" };
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @internal
|
|
13
|
+
* Holds requests until the client is fully hydrated after a tool call. It is
|
|
14
|
+
* particularly useful for `network-only` and `cache-and-network` fetch policies
|
|
15
|
+
* where the request makes it to the link chain because it prevents a followup
|
|
16
|
+
* tool call to the MCP server for the just fetched data from the MCP server.
|
|
17
|
+
*/
|
|
18
|
+
export class ToolHydrationLink extends ApolloLink {
|
|
19
|
+
#hydrated = false;
|
|
20
|
+
#pending: ResolveFn[] = [];
|
|
21
|
+
#operations = new Map<OperationKey, FormattedExecutionResult>();
|
|
22
|
+
|
|
23
|
+
hydrate(
|
|
24
|
+
operation: ManifestOperation,
|
|
25
|
+
{
|
|
26
|
+
result,
|
|
27
|
+
variables,
|
|
28
|
+
}: { result: FormattedExecutionResult; variables: OperationVariables }
|
|
29
|
+
) {
|
|
30
|
+
this.#operations.set(
|
|
31
|
+
getKey({ operationName: operation.name, variables }),
|
|
32
|
+
result
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
complete(): void {
|
|
37
|
+
this.#hydrated = true;
|
|
38
|
+
|
|
39
|
+
for (const resolve of this.#pending.splice(0)) {
|
|
40
|
+
resolve();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
request(
|
|
45
|
+
operation: ApolloLink.Operation,
|
|
46
|
+
forward: ApolloLink.ForwardFunction
|
|
47
|
+
): Observable<ApolloLink.Result> {
|
|
48
|
+
const maybeSendToTerminatingLink = (): Observable<ApolloLink.Result> => {
|
|
49
|
+
const key = getKey(operation);
|
|
50
|
+
const result = this.#operations.get(key);
|
|
51
|
+
|
|
52
|
+
if (result) {
|
|
53
|
+
this.#operations.delete(key);
|
|
54
|
+
return of(result);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return forward(operation);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
if (this.#hydrated) {
|
|
61
|
+
return maybeSendToTerminatingLink();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return new Observable((observer) => {
|
|
65
|
+
let active = true;
|
|
66
|
+
|
|
67
|
+
const resolve = () => {
|
|
68
|
+
if (!active) return;
|
|
69
|
+
maybeSendToTerminatingLink().subscribe(observer);
|
|
70
|
+
};
|
|
71
|
+
this.#pending.push(resolve);
|
|
72
|
+
|
|
73
|
+
return () => {
|
|
74
|
+
active = false;
|
|
75
|
+
const idx = this.#pending.indexOf(resolve);
|
|
76
|
+
if (idx !== -1) this.#pending.splice(idx, 1);
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getKey({
|
|
83
|
+
operationName,
|
|
84
|
+
variables,
|
|
85
|
+
}: {
|
|
86
|
+
operationName: string | undefined;
|
|
87
|
+
variables?: OperationVariables;
|
|
88
|
+
}): OperationKey {
|
|
89
|
+
return `${operationName}:${canonicalStringify(variables ?? {})}` as OperationKey;
|
|
90
|
+
}
|