@apollo/client-ai-apps 0.4.0 → 0.5.1

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.
Files changed (404) hide show
  1. package/.github/CODEOWNERS +1 -0
  2. package/.github/workflows/pr.yaml +23 -1
  3. package/.github/workflows/release.yaml +1 -5
  4. package/.github/workflows/verify-changeset.yml +112 -21
  5. package/CHANGELOG.md +361 -0
  6. package/__mocks__/fs/promises.cjs +3 -0
  7. package/__mocks__/fs.cjs +3 -0
  8. package/dist/config/defineConfig.d.ts +28 -0
  9. package/dist/config/defineConfig.d.ts.map +1 -0
  10. package/dist/config/defineConfig.js +7 -0
  11. package/dist/config/defineConfig.js.map +1 -0
  12. package/dist/config/index.d.ts +3 -0
  13. package/dist/config/index.d.ts.map +1 -0
  14. package/dist/config/index.js +2 -0
  15. package/dist/config/index.js.map +1 -0
  16. package/dist/config/schema.d.ts +29 -0
  17. package/dist/config/schema.d.ts.map +1 -0
  18. package/dist/config/schema.js +51 -0
  19. package/dist/config/schema.js.map +1 -0
  20. package/dist/config/types.d.ts +7 -0
  21. package/dist/config/types.d.ts.map +1 -0
  22. package/dist/config/types.js +2 -0
  23. package/dist/config/types.js.map +1 -0
  24. package/dist/core/ApolloClient.d.ts +4 -3
  25. package/dist/core/ApolloClient.d.ts.map +1 -1
  26. package/dist/core/ApolloClient.js +6 -59
  27. package/dist/core/ApolloClient.js.map +1 -1
  28. package/dist/core/Platform.d.ts +8 -0
  29. package/dist/core/Platform.d.ts.map +1 -0
  30. package/dist/core/Platform.js +20 -0
  31. package/dist/core/Platform.js.map +1 -0
  32. package/dist/core/types.d.ts +13 -0
  33. package/dist/core/types.d.ts.map +1 -0
  34. package/dist/core/types.js +2 -0
  35. package/dist/core/types.js.map +1 -0
  36. package/dist/index.d.ts +1 -14
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1 -13
  39. package/dist/index.js.map +1 -1
  40. package/dist/index.mcp.d.ts +5 -0
  41. package/dist/index.mcp.d.ts.map +1 -0
  42. package/dist/index.mcp.js +5 -0
  43. package/dist/index.mcp.js.map +1 -0
  44. package/dist/index.openai.d.ts +5 -0
  45. package/dist/index.openai.d.ts.map +1 -0
  46. package/dist/index.openai.js +5 -0
  47. package/dist/index.openai.js.map +1 -0
  48. package/dist/link/ToolCallLink.d.ts +3 -3
  49. package/dist/link/ToolCallLink.d.ts.map +1 -1
  50. package/dist/link/ToolCallLink.js +5 -14
  51. package/dist/link/ToolCallLink.js.map +1 -1
  52. package/dist/mcp/core/ApolloClient.d.ts +21 -0
  53. package/dist/mcp/core/ApolloClient.d.ts.map +1 -0
  54. package/dist/mcp/core/ApolloClient.js +65 -0
  55. package/dist/mcp/core/ApolloClient.js.map +1 -0
  56. package/dist/mcp/core/McpAppManager.d.ts +34 -0
  57. package/dist/mcp/core/McpAppManager.d.ts.map +1 -0
  58. package/dist/mcp/core/McpAppManager.js +63 -0
  59. package/dist/mcp/core/McpAppManager.js.map +1 -0
  60. package/dist/mcp/core/Platform.d.ts +8 -0
  61. package/dist/mcp/core/Platform.d.ts.map +1 -0
  62. package/dist/mcp/core/Platform.js +8 -0
  63. package/dist/mcp/core/Platform.js.map +1 -0
  64. package/dist/mcp/index.d.ts +3 -0
  65. package/dist/mcp/index.d.ts.map +1 -0
  66. package/dist/mcp/index.js +3 -0
  67. package/dist/mcp/index.js.map +1 -0
  68. package/dist/mcp/link/ToolCallLink.d.ts +28 -0
  69. package/dist/mcp/link/ToolCallLink.d.ts.map +1 -0
  70. package/dist/mcp/link/ToolCallLink.js +35 -0
  71. package/dist/mcp/link/ToolCallLink.js.map +1 -0
  72. package/dist/mcp/react/hooks/useApolloClient.d.ts +3 -0
  73. package/dist/mcp/react/hooks/useApolloClient.d.ts.map +1 -0
  74. package/dist/mcp/react/hooks/useApolloClient.js +9 -0
  75. package/dist/mcp/react/hooks/useApolloClient.js.map +1 -0
  76. package/dist/mcp/react/hooks/useApp.d.ts +2 -0
  77. package/dist/mcp/react/hooks/useApp.d.ts.map +1 -0
  78. package/dist/mcp/react/hooks/useApp.js +5 -0
  79. package/dist/mcp/react/hooks/useApp.js.map +1 -0
  80. package/dist/mcp/react/hooks/useToolInput.d.ts +2 -0
  81. package/dist/mcp/react/hooks/useToolInput.d.ts.map +1 -0
  82. package/dist/mcp/react/hooks/useToolInput.js +5 -0
  83. package/dist/mcp/react/hooks/useToolInput.js.map +1 -0
  84. package/dist/mcp/react/hooks/useToolMetadata.d.ts +8 -0
  85. package/dist/mcp/react/hooks/useToolMetadata.d.ts.map +1 -0
  86. package/dist/mcp/react/hooks/useToolMetadata.js +5 -0
  87. package/dist/mcp/react/hooks/useToolMetadata.js.map +1 -0
  88. package/dist/mcp/react/hooks/useToolName.d.ts +2 -0
  89. package/dist/mcp/react/hooks/useToolName.d.ts.map +1 -0
  90. package/dist/mcp/react/hooks/useToolName.js +5 -0
  91. package/dist/mcp/react/hooks/useToolName.js.map +1 -0
  92. package/dist/mcp/react/index.d.ts +5 -0
  93. package/dist/mcp/react/index.d.ts.map +1 -0
  94. package/dist/mcp/react/index.js +5 -0
  95. package/dist/mcp/react/index.js.map +1 -0
  96. package/dist/openai/core/ApolloClient.d.ts +21 -0
  97. package/dist/openai/core/ApolloClient.d.ts.map +1 -0
  98. package/dist/openai/core/ApolloClient.js +66 -0
  99. package/dist/openai/core/ApolloClient.js.map +1 -0
  100. package/dist/openai/core/McpAppManager.d.ts +28 -0
  101. package/dist/openai/core/McpAppManager.d.ts.map +1 -0
  102. package/dist/openai/core/McpAppManager.js +73 -0
  103. package/dist/openai/core/McpAppManager.js.map +1 -0
  104. package/dist/openai/core/Platform.d.ts +8 -0
  105. package/dist/openai/core/Platform.d.ts.map +1 -0
  106. package/dist/openai/core/Platform.js +8 -0
  107. package/dist/openai/core/Platform.js.map +1 -0
  108. package/dist/openai/globals.d.ts +12 -0
  109. package/dist/openai/globals.d.ts.map +1 -0
  110. package/dist/openai/globals.js +2 -0
  111. package/dist/openai/globals.js.map +1 -0
  112. package/dist/openai/index.d.ts +3 -0
  113. package/dist/openai/index.d.ts.map +1 -0
  114. package/dist/openai/index.js +3 -0
  115. package/dist/openai/index.js.map +1 -0
  116. package/dist/openai/link/ToolCallLink.d.ts +28 -0
  117. package/dist/openai/link/ToolCallLink.d.ts.map +1 -0
  118. package/dist/openai/link/ToolCallLink.js +35 -0
  119. package/dist/openai/link/ToolCallLink.js.map +1 -0
  120. package/dist/openai/react/hooks/useApolloClient.d.ts +3 -0
  121. package/dist/openai/react/hooks/useApolloClient.d.ts.map +1 -0
  122. package/dist/openai/react/hooks/useApolloClient.js +9 -0
  123. package/dist/openai/react/hooks/useApolloClient.js.map +1 -0
  124. package/dist/openai/react/hooks/useApp.d.ts +2 -0
  125. package/dist/openai/react/hooks/useApp.d.ts.map +1 -0
  126. package/dist/openai/react/hooks/useApp.js +5 -0
  127. package/dist/openai/react/hooks/useApp.js.map +1 -0
  128. package/dist/openai/react/hooks/useOpenAiGlobal.d.ts +3 -0
  129. package/dist/openai/react/hooks/useOpenAiGlobal.d.ts.map +1 -0
  130. package/dist/{react → openai/react}/hooks/useOpenAiGlobal.js +1 -1
  131. package/dist/openai/react/hooks/useOpenAiGlobal.js.map +1 -0
  132. package/dist/openai/react/hooks/useToolInput.d.ts +2 -0
  133. package/dist/openai/react/hooks/useToolInput.d.ts.map +1 -0
  134. package/dist/openai/react/hooks/useToolInput.js +5 -0
  135. package/dist/openai/react/hooks/useToolInput.js.map +1 -0
  136. package/dist/openai/react/hooks/useToolMetadata.d.ts +2 -0
  137. package/dist/openai/react/hooks/useToolMetadata.d.ts.map +1 -0
  138. package/dist/openai/react/hooks/useToolMetadata.js +5 -0
  139. package/dist/openai/react/hooks/useToolMetadata.js.map +1 -0
  140. package/dist/openai/react/hooks/useToolName.d.ts.map +1 -0
  141. package/dist/openai/react/hooks/useToolName.js +5 -0
  142. package/dist/openai/react/hooks/useToolName.js.map +1 -0
  143. package/dist/{react → openai/react}/hooks/useWidgetState.d.ts +1 -1
  144. package/dist/openai/react/hooks/useWidgetState.d.ts.map +1 -0
  145. package/dist/openai/react/hooks/useWidgetState.js.map +1 -0
  146. package/dist/openai/react/index.d.ts +6 -0
  147. package/dist/openai/react/index.d.ts.map +1 -0
  148. package/dist/openai/react/index.js +6 -0
  149. package/dist/openai/react/index.js.map +1 -0
  150. package/dist/{types/openai.d.ts → openai/types.d.ts} +7 -11
  151. package/dist/openai/types.d.ts.map +1 -0
  152. package/dist/{types/openai.js → openai/types.js} +1 -1
  153. package/dist/openai/types.js.map +1 -0
  154. package/dist/react/ApolloProvider.d.ts +6 -2
  155. package/dist/react/ApolloProvider.d.ts.map +1 -1
  156. package/dist/react/ApolloProvider.js +12 -27
  157. package/dist/react/ApolloProvider.js.map +1 -1
  158. package/dist/react/index.d.ts +6 -0
  159. package/dist/react/index.d.ts.map +1 -0
  160. package/dist/react/index.js +9 -0
  161. package/dist/react/index.js.map +1 -0
  162. package/dist/react/index.mcp.d.ts +3 -0
  163. package/dist/react/index.mcp.d.ts.map +1 -0
  164. package/dist/react/index.mcp.js +3 -0
  165. package/dist/react/index.mcp.js.map +1 -0
  166. package/dist/react/index.openai.d.ts +3 -0
  167. package/dist/react/index.openai.d.ts.map +1 -0
  168. package/dist/react/index.openai.js +3 -0
  169. package/dist/react/index.openai.js.map +1 -0
  170. package/dist/react/missingHook.d.ts +2 -0
  171. package/dist/react/missingHook.d.ts.map +1 -0
  172. package/dist/react/missingHook.js +6 -0
  173. package/dist/react/missingHook.js.map +1 -0
  174. package/dist/tsconfig/core/tsconfig.json +5 -0
  175. package/dist/tsconfig/mcp/tsconfig.json +6 -0
  176. package/dist/tsconfig/openai/tsconfig.json +7 -0
  177. package/dist/types/application-manifest.d.ts +5 -1
  178. package/dist/types/application-manifest.d.ts.map +1 -1
  179. package/dist/types/application-manifest.js.map +1 -1
  180. package/dist/utilities/cacheAsync.d.ts +4 -0
  181. package/dist/utilities/cacheAsync.d.ts.map +1 -0
  182. package/dist/utilities/cacheAsync.js +19 -0
  183. package/dist/utilities/cacheAsync.js.map +1 -0
  184. package/dist/utilities/constants.d.ts +6 -0
  185. package/dist/utilities/constants.d.ts.map +1 -0
  186. package/dist/utilities/constants.js +6 -0
  187. package/dist/utilities/constants.js.map +1 -0
  188. package/dist/utilities/emptyModule.d.ts +2 -0
  189. package/dist/utilities/emptyModule.d.ts.map +1 -0
  190. package/dist/utilities/emptyModule.js +2 -0
  191. package/dist/utilities/emptyModule.js.map +1 -0
  192. package/dist/utilities/getVariablesForOperationFromToolInput.d.ts +5 -0
  193. package/dist/utilities/getVariablesForOperationFromToolInput.d.ts.map +1 -0
  194. package/dist/utilities/getVariablesForOperationFromToolInput.js +18 -0
  195. package/dist/utilities/getVariablesForOperationFromToolInput.js.map +1 -0
  196. package/dist/utilities/index.d.ts +6 -0
  197. package/dist/utilities/index.d.ts.map +1 -0
  198. package/dist/utilities/index.js +6 -0
  199. package/dist/utilities/index.js.map +1 -0
  200. package/dist/utilities/invariant.d.ts +2 -0
  201. package/dist/utilities/invariant.d.ts.map +1 -0
  202. package/dist/utilities/invariant.js +6 -0
  203. package/dist/utilities/invariant.js.map +1 -0
  204. package/dist/utilities/promiseWithResolvers.d.ts +7 -0
  205. package/dist/utilities/promiseWithResolvers.d.ts.map +1 -0
  206. package/dist/utilities/promiseWithResolvers.js +16 -0
  207. package/dist/utilities/promiseWithResolvers.js.map +1 -0
  208. package/dist/vite/__tests__/utilities/build.d.ts +41 -0
  209. package/dist/vite/__tests__/utilities/build.d.ts.map +1 -0
  210. package/dist/vite/__tests__/utilities/build.js +63 -0
  211. package/dist/vite/__tests__/utilities/build.js.map +1 -0
  212. package/dist/vite/apolloClientAiApps.d.ts +14 -0
  213. package/dist/vite/apolloClientAiApps.d.ts.map +1 -0
  214. package/dist/vite/apolloClientAiApps.js +350 -0
  215. package/dist/vite/apolloClientAiApps.js.map +1 -0
  216. package/dist/vite/index.d.ts +1 -2
  217. package/dist/vite/index.d.ts.map +1 -1
  218. package/dist/vite/index.js +1 -2
  219. package/dist/vite/index.js.map +1 -1
  220. package/dist/vite/utilities/config.d.ts +2 -0
  221. package/dist/vite/utilities/config.d.ts.map +1 -0
  222. package/dist/vite/utilities/config.js +11 -0
  223. package/dist/vite/utilities/config.js.map +1 -0
  224. package/dist/vite/utilities/graphql.d.ts +20 -0
  225. package/dist/vite/utilities/graphql.d.ts.map +1 -0
  226. package/dist/vite/utilities/graphql.js +42 -0
  227. package/dist/vite/utilities/graphql.js.map +1 -0
  228. package/knope.toml +1 -1
  229. package/package.json +105 -9
  230. package/src/config/defineConfig.ts +8 -0
  231. package/src/config/index.ts +2 -0
  232. package/src/config/schema.ts +73 -0
  233. package/src/config/types.ts +7 -0
  234. package/src/core/ApolloClient.ts +7 -95
  235. package/src/core/Platform.ts +27 -0
  236. package/src/core/types.ts +14 -0
  237. package/src/index.mcp.ts +5 -0
  238. package/src/index.openai.ts +5 -0
  239. package/src/index.ts +2 -27
  240. package/src/link/ToolCallLink.ts +6 -22
  241. package/src/mcp/core/ApolloClient.ts +102 -0
  242. package/src/mcp/core/McpAppManager.ts +98 -0
  243. package/src/mcp/core/Platform.ts +11 -0
  244. package/src/mcp/core/__tests__/ApolloClient.test.ts +464 -0
  245. package/src/mcp/index.ts +2 -0
  246. package/src/mcp/link/ToolCallLink.ts +40 -0
  247. package/src/mcp/link/__tests__/ToolCallLink.test.ts +53 -0
  248. package/src/mcp/react/hooks/__tests__/useApp.test.tsx +46 -0
  249. package/src/mcp/react/hooks/__tests__/useToolInput.test.tsx +50 -0
  250. package/src/mcp/react/hooks/__tests__/useToolMetadata.test.tsx +53 -0
  251. package/src/mcp/react/hooks/__tests__/useToolName.test.tsx +50 -0
  252. package/src/mcp/react/hooks/useApolloClient.ts +14 -0
  253. package/src/mcp/react/hooks/useApp.ts +5 -0
  254. package/src/mcp/react/hooks/useToolInput.ts +5 -0
  255. package/src/mcp/react/hooks/useToolMetadata.ts +5 -0
  256. package/src/mcp/react/hooks/useToolName.ts +5 -0
  257. package/src/mcp/react/index.ts +4 -0
  258. package/src/openai/core/ApolloClient.ts +100 -0
  259. package/src/openai/core/McpAppManager.ts +110 -0
  260. package/src/openai/core/Platform.ts +11 -0
  261. package/src/openai/core/__tests__/ApolloClient.test.ts +537 -0
  262. package/src/openai/globals.ts +14 -0
  263. package/src/openai/index.ts +2 -0
  264. package/src/openai/link/ToolCallLink.ts +40 -0
  265. package/src/{react → openai/react}/hooks/__tests__/useOpenAiGlobal.test.ts +1 -1
  266. package/src/openai/react/hooks/__tests__/useToolInput.test.tsx +85 -0
  267. package/src/openai/react/hooks/__tests__/useToolMetadata.test.tsx +86 -0
  268. package/src/openai/react/hooks/__tests__/useToolName.test.tsx +50 -0
  269. package/src/{react → openai/react}/hooks/__tests__/useWidgetState.test.tsx +1 -1
  270. package/src/openai/react/hooks/useApolloClient.ts +14 -0
  271. package/src/openai/react/hooks/useApp.ts +5 -0
  272. package/src/{react → openai/react}/hooks/useOpenAiGlobal.ts +2 -2
  273. package/src/openai/react/hooks/useToolInput.ts +5 -0
  274. package/src/openai/react/hooks/useToolMetadata.ts +5 -0
  275. package/src/openai/react/hooks/useToolName.ts +5 -0
  276. package/src/{react → openai/react}/hooks/useWidgetState.ts +1 -1
  277. package/src/openai/react/index.ts +5 -0
  278. package/src/{types/openai.ts → openai/types.ts} +9 -13
  279. package/src/react/ApolloProvider.tsx +23 -31
  280. package/src/react/__tests__/ApolloProvider/mcp.test.tsx +74 -0
  281. package/src/react/__tests__/ApolloProvider/openai.test.tsx +146 -0
  282. package/src/react/index.mcp.ts +7 -0
  283. package/src/react/index.openai.ts +7 -0
  284. package/src/react/index.ts +19 -0
  285. package/src/react/missingHook.ts +9 -0
  286. package/src/testing/internal/index.ts +8 -0
  287. package/src/testing/internal/matchers/index.ts +2 -0
  288. package/src/testing/internal/matchers/toComplete.ts +46 -0
  289. package/src/testing/internal/matchers/toEmitValue.ts +71 -0
  290. package/src/testing/internal/matchers/types.ts +3 -0
  291. package/src/testing/internal/mcp/graphqlToolResult.ts +31 -0
  292. package/src/testing/internal/mcp/minimalHostContextWithToolName.ts +9 -0
  293. package/src/testing/internal/mcp/mockMcpHost.ts +188 -0
  294. package/src/testing/internal/openai/dispatchStateChange.ts +1 -1
  295. package/src/testing/internal/openai/stubOpenAiGlobals.ts +22 -9
  296. package/src/testing/internal/react/renderAsync.ts +7 -0
  297. package/src/testing/internal/utilities/ObservableStream.ts +172 -0
  298. package/src/testing/internal/utilities/getSerializableProperties.ts +55 -0
  299. package/src/testing/internal/utilities/mockApplicationManifest.ts +39 -0
  300. package/src/testing/internal/utilities/spyOnConsole.ts +29 -0
  301. package/src/testing/internal/utilities/wait.ts +3 -0
  302. package/src/tsconfig/core/tsconfig.json +5 -0
  303. package/src/tsconfig/mcp/tsconfig.json +6 -0
  304. package/src/tsconfig/openai/tsconfig.json +7 -0
  305. package/src/types/application-manifest.ts +7 -1
  306. package/src/utilities/__tests__/cacheAsync.test.ts +64 -0
  307. package/src/utilities/cacheAsync.ts +25 -0
  308. package/src/utilities/constants.ts +5 -0
  309. package/src/utilities/emptyModule.ts +1 -0
  310. package/src/utilities/getVariablesForOperationFromToolInput.ts +27 -0
  311. package/src/utilities/index.ts +5 -0
  312. package/src/utilities/invariant.ts +5 -0
  313. package/src/utilities/promiseWithResolvers.ts +18 -0
  314. package/src/vite/__tests__/apolloClientAiApps.test.ts +1521 -0
  315. package/src/vite/__tests__/utilities/build.ts +72 -0
  316. package/src/vite/apolloClientAiApps.ts +515 -0
  317. package/src/vite/index.ts +1 -2
  318. package/src/vite/utilities/config.ts +13 -0
  319. package/src/vite/utilities/graphql.ts +123 -0
  320. package/tsconfig.base.json +2 -2
  321. package/tsconfig.vite.build.json +4 -1
  322. package/tsconfig.vite.json +8 -2
  323. package/vitest-setup.ts +28 -0
  324. package/dist/react/context/ToolUseContext.d.ts +0 -16
  325. package/dist/react/context/ToolUseContext.d.ts.map +0 -1
  326. package/dist/react/context/ToolUseContext.js +0 -11
  327. package/dist/react/context/ToolUseContext.js.map +0 -1
  328. package/dist/react/hooks/useCallTool.d.ts +0 -4
  329. package/dist/react/hooks/useCallTool.d.ts.map +0 -1
  330. package/dist/react/hooks/useCallTool.js +0 -5
  331. package/dist/react/hooks/useCallTool.js.map +0 -1
  332. package/dist/react/hooks/useOpenAiGlobal.d.ts +0 -3
  333. package/dist/react/hooks/useOpenAiGlobal.d.ts.map +0 -1
  334. package/dist/react/hooks/useOpenAiGlobal.js.map +0 -1
  335. package/dist/react/hooks/useOpenExternal.d.ts +0 -4
  336. package/dist/react/hooks/useOpenExternal.d.ts.map +0 -1
  337. package/dist/react/hooks/useOpenExternal.js +0 -5
  338. package/dist/react/hooks/useOpenExternal.js.map +0 -1
  339. package/dist/react/hooks/useRequestDisplayMode.d.ts +0 -7
  340. package/dist/react/hooks/useRequestDisplayMode.d.ts.map +0 -1
  341. package/dist/react/hooks/useRequestDisplayMode.js +0 -6
  342. package/dist/react/hooks/useRequestDisplayMode.js.map +0 -1
  343. package/dist/react/hooks/useSendFollowUpMessage.d.ts +0 -2
  344. package/dist/react/hooks/useSendFollowUpMessage.d.ts.map +0 -1
  345. package/dist/react/hooks/useSendFollowUpMessage.js +0 -8
  346. package/dist/react/hooks/useSendFollowUpMessage.js.map +0 -1
  347. package/dist/react/hooks/useToolEffect.d.ts +0 -3
  348. package/dist/react/hooks/useToolEffect.d.ts.map +0 -1
  349. package/dist/react/hooks/useToolEffect.js +0 -28
  350. package/dist/react/hooks/useToolEffect.js.map +0 -1
  351. package/dist/react/hooks/useToolInput.d.ts +0 -2
  352. package/dist/react/hooks/useToolInput.d.ts.map +0 -1
  353. package/dist/react/hooks/useToolInput.js +0 -6
  354. package/dist/react/hooks/useToolInput.js.map +0 -1
  355. package/dist/react/hooks/useToolName.d.ts.map +0 -1
  356. package/dist/react/hooks/useToolName.js +0 -6
  357. package/dist/react/hooks/useToolName.js.map +0 -1
  358. package/dist/react/hooks/useToolOutput.d.ts +0 -2
  359. package/dist/react/hooks/useToolOutput.d.ts.map +0 -1
  360. package/dist/react/hooks/useToolOutput.js +0 -5
  361. package/dist/react/hooks/useToolOutput.js.map +0 -1
  362. package/dist/react/hooks/useToolResponseMetadata.d.ts +0 -2
  363. package/dist/react/hooks/useToolResponseMetadata.d.ts.map +0 -1
  364. package/dist/react/hooks/useToolResponseMetadata.js +0 -5
  365. package/dist/react/hooks/useToolResponseMetadata.js.map +0 -1
  366. package/dist/react/hooks/useWidgetState.d.ts.map +0 -1
  367. package/dist/react/hooks/useWidgetState.js.map +0 -1
  368. package/dist/types/openai.d.ts.map +0 -1
  369. package/dist/types/openai.js.map +0 -1
  370. package/dist/vite/absolute_asset_imports_plugin.d.ts +0 -5
  371. package/dist/vite/absolute_asset_imports_plugin.d.ts.map +0 -1
  372. package/dist/vite/absolute_asset_imports_plugin.js +0 -17
  373. package/dist/vite/absolute_asset_imports_plugin.js.map +0 -1
  374. package/dist/vite/application_manifest_plugin.d.ts +0 -10
  375. package/dist/vite/application_manifest_plugin.d.ts.map +0 -1
  376. package/dist/vite/application_manifest_plugin.js +0 -317
  377. package/dist/vite/application_manifest_plugin.js.map +0 -1
  378. package/src/core/__tests__/ApolloClient.test.ts +0 -646
  379. package/src/react/__tests__/ApolloProvider.test.tsx +0 -41
  380. package/src/react/context/ToolUseContext.tsx +0 -31
  381. package/src/react/hooks/__tests__/useCallTool.test.ts +0 -46
  382. package/src/react/hooks/__tests__/useOpenExternal.test.tsx +0 -24
  383. package/src/react/hooks/__tests__/useRequestDisplayMode.test.ts +0 -17
  384. package/src/react/hooks/__tests__/useSendFollowUpMessage.test.ts +0 -15
  385. package/src/react/hooks/__tests__/useToolEffect.test.tsx +0 -67
  386. package/src/react/hooks/__tests__/useToolInput.test.ts +0 -13
  387. package/src/react/hooks/__tests__/useToolName.test.ts +0 -13
  388. package/src/react/hooks/__tests__/useToolOutput.test.tsx +0 -49
  389. package/src/react/hooks/__tests__/useToolResponseMetadata.test.tsx +0 -49
  390. package/src/react/hooks/useCallTool.ts +0 -13
  391. package/src/react/hooks/useOpenExternal.ts +0 -11
  392. package/src/react/hooks/useRequestDisplayMode.ts +0 -7
  393. package/src/react/hooks/useSendFollowUpMessage.ts +0 -7
  394. package/src/react/hooks/useToolEffect.tsx +0 -37
  395. package/src/react/hooks/useToolInput.ts +0 -7
  396. package/src/react/hooks/useToolName.ts +0 -7
  397. package/src/react/hooks/useToolOutput.ts +0 -5
  398. package/src/react/hooks/useToolResponseMetadata.ts +0 -5
  399. package/src/vite/__tests__/absolute_asset_imports_plugin.test.ts +0 -102
  400. package/src/vite/__tests__/application_manifest_plugin.test.ts +0 -1199
  401. package/src/vite/absolute_asset_imports_plugin.ts +0 -22
  402. package/src/vite/application_manifest_plugin.ts +0 -539
  403. /package/dist/{react → openai/react}/hooks/useToolName.d.ts +0 -0
  404. /package/dist/{react → openai/react}/hooks/useWidgetState.js +0 -0
@@ -0,0 +1,71 @@
1
+ import { iterableEquality } from "@jest/expect-utils";
2
+ import { expect } from "vitest";
3
+
4
+ import type { TakeOptions } from "../utilities/ObservableStream.js";
5
+ import {
6
+ ObservableStream,
7
+ EventMismatchError,
8
+ } from "../utilities/ObservableStream.js";
9
+
10
+ import { getSerializableProperties } from "../utilities/getSerializableProperties.js";
11
+
12
+ expect.extend({
13
+ async toEmitValue(actual, expected, options: TakeOptions) {
14
+ const stream = actual as ObservableStream<any>;
15
+ const hint = this.utils.matcherHint("toEmitValue", "stream", "expected", {
16
+ isNot: this.isNot,
17
+ });
18
+
19
+ try {
20
+ const value = await stream.takeNext(options);
21
+ const serializableProperties = getSerializableProperties(value);
22
+
23
+ const pass = this.equals(
24
+ serializableProperties,
25
+ expected,
26
+ // https://github.com/jestjs/jest/blob/22029ba06b69716699254bb9397f2b3bc7b3cf3b/packages/expect/src/matchers.ts#L62-L67
27
+ [...this.customTesters, iterableEquality],
28
+ true
29
+ );
30
+
31
+ return {
32
+ pass,
33
+ message: () => {
34
+ if (pass) {
35
+ return (
36
+ hint +
37
+ "\n\nExpected stream not to emit a fetch result equal to expected but it did."
38
+ );
39
+ }
40
+
41
+ return (
42
+ hint +
43
+ "\n\n" +
44
+ this.utils.printDiffOrStringify(serializableProperties, expected)
45
+ );
46
+ },
47
+ };
48
+ } catch (error) {
49
+ if (
50
+ error instanceof Error &&
51
+ error.message === "Timeout waiting for next event"
52
+ ) {
53
+ return {
54
+ pass: false,
55
+ message: () =>
56
+ hint + "\n\nExpected stream to emit a value but it did not.",
57
+ };
58
+ } else if (EventMismatchError.is(error)) {
59
+ return {
60
+ pass: false,
61
+ message: () =>
62
+ this.utils.matcherHint("toEmitNext", "stream", "expected") +
63
+ "\n\n" +
64
+ this.utils.printDiffOrStringify(error.actual, error.expected),
65
+ };
66
+ } else {
67
+ throw error;
68
+ }
69
+ }
70
+ },
71
+ });
@@ -1,7 +1,10 @@
1
1
  import type { NextRenderOptions } from "@testing-library/react-render-stream";
2
+ import type { TakeOptions } from "../utilities/ObservableStream.js";
2
3
 
3
4
  interface CustomMatchers<R = unknown> {
4
5
  toRerender: (options?: NextRenderOptions) => Promise<R>;
6
+ toComplete: (options?: TakeOptions) => Promise<R>;
7
+ toEmitValue: (expected: unknown, options?: TakeOptions) => Promise<R>;
5
8
  }
6
9
 
7
10
  declare module "vitest" {
@@ -0,0 +1,31 @@
1
+ import type { McpUiToolResultNotification } from "@modelcontextprotocol/ext-apps";
2
+ import type { FormattedExecutionResult } from "graphql";
3
+ import type { ApolloMcpServerApps } from "../../../core/types";
4
+
5
+ export function graphqlToolResult(
6
+ options:
7
+ | FormattedExecutionResult
8
+ | {
9
+ prefetch?: Record<string, FormattedExecutionResult>;
10
+ result: FormattedExecutionResult;
11
+ }
12
+ ): McpUiToolResultNotification["params"] {
13
+ let structuredContent: ApolloMcpServerApps.StructuredContent;
14
+
15
+ if ("data" in options) {
16
+ structuredContent = { result: options };
17
+ } else if ("result" in options) {
18
+ structuredContent = { result: options.result };
19
+
20
+ if (options.prefetch) {
21
+ structuredContent.prefetch = options.prefetch;
22
+ }
23
+ } else {
24
+ throw new Error("Mock tool result could not be parsed");
25
+ }
26
+
27
+ return {
28
+ content: [{ type: "text", text: JSON.stringify(structuredContent) }],
29
+ structuredContent,
30
+ };
31
+ }
@@ -0,0 +1,9 @@
1
+ import type { McpUiHostContext } from "@modelcontextprotocol/ext-apps";
2
+
3
+ export function minimalHostContextWithToolName(
4
+ toolName: string
5
+ ): McpUiHostContext {
6
+ return {
7
+ toolInfo: { tool: { name: toolName, inputSchema: { type: "object" } } },
8
+ };
9
+ }
@@ -0,0 +1,188 @@
1
+ import {
2
+ LATEST_PROTOCOL_VERSION,
3
+ type McpUiHostCapabilities,
4
+ type McpUiHostContext,
5
+ type McpUiToolResultNotification,
6
+ type McpUiToolInputNotification,
7
+ } from "@modelcontextprotocol/ext-apps";
8
+ import type {
9
+ CallToolRequest,
10
+ CallToolResult,
11
+ Implementation,
12
+ } from "@modelcontextprotocol/sdk/types.js";
13
+ import { invariant, promiseWithResolvers } from "../../../utilities/index.js";
14
+
15
+ export interface MockMcpHost extends Disposable {
16
+ sendToolResult(params: McpUiToolResultNotification["params"]): Promise<void>;
17
+ sendToolInput(params: McpUiToolInputNotification["params"]): Promise<void>;
18
+ mockToolCall(
19
+ name: string,
20
+ handler: (params: CallToolRequest["params"]) => CallToolResult
21
+ ): () => void;
22
+ /**
23
+ * Register an MCP App to be closed during cleanup. This prevents the App's
24
+ * transport from interfering with subsequent tests by responding to messages
25
+ * it shouldn't be handling.
26
+ */
27
+ onCleanup(cleanup: () => void): void;
28
+ cleanup(): void;
29
+ }
30
+
31
+ /**
32
+ * In vitest's happy-dom environment, `window` is a Proxy around the real
33
+ * `GlobalWindow` object. `event.source` on `MessageEvent` returns the real
34
+ * `GlobalWindow`, which !== the proxied `window`. `PostMessageTransport` uses
35
+ * `event.source !== eventSource` to validate messages, so all messages get
36
+ * rejected when `eventSource` is the proxy.
37
+ *
38
+ * We work around this by discovering the real `GlobalWindow` via a probe
39
+ * `postMessage` and overriding `window.parent` so `PostMessageTransport`
40
+ * (which is constructed with `window.parent` as both target and eventSource)
41
+ * can properly match `event.source`.
42
+ */
43
+ async function patchWindowParent(): Promise<() => void> {
44
+ const realWindow = await new Promise<Window>((resolve) => {
45
+ const probe = (event: MessageEvent) => {
46
+ window.removeEventListener("message", probe);
47
+ resolve(event.source as Window);
48
+ };
49
+ window.addEventListener("message", probe);
50
+ window.postMessage({ __mockMcpHostProbe: true }, "*");
51
+ });
52
+
53
+ // If event.source already matches window.parent, no patch needed
54
+ if (realWindow === window.parent) {
55
+ return () => {};
56
+ }
57
+
58
+ const originalParent = window.parent;
59
+ Object.defineProperty(window, "parent", {
60
+ value: realWindow,
61
+ writable: true,
62
+ configurable: true,
63
+ });
64
+
65
+ return () => {
66
+ Object.defineProperty(window, "parent", {
67
+ value: originalParent,
68
+ writable: true,
69
+ configurable: true,
70
+ });
71
+ };
72
+ }
73
+
74
+ export declare namespace mockMcpHost {
75
+ export interface Options {
76
+ hostCapabilities?: McpUiHostCapabilities;
77
+ hostContext?: McpUiHostContext;
78
+ hostInfo?: Implementation;
79
+ }
80
+ }
81
+
82
+ export async function mockMcpHost(
83
+ options?: mockMcpHost.Options
84
+ ): Promise<MockMcpHost> {
85
+ const {
86
+ hostCapabilities = {},
87
+ hostContext = {},
88
+ hostInfo = { name: "MockMcpHost", version: "1.0.0" },
89
+ } = options ?? {};
90
+
91
+ const restore = await patchWindowParent();
92
+
93
+ const { promise: initialized, resolve: resolveInitialized } =
94
+ promiseWithResolvers<void>();
95
+
96
+ const cleanupFns = new Set<() => void>();
97
+ const toolCallHandlers = new Map<
98
+ string,
99
+ (params: CallToolRequest["params"]) => CallToolResult
100
+ >();
101
+
102
+ const listener = (event: MessageEvent<unknown>) => {
103
+ const data = event.data;
104
+
105
+ if (!data || typeof data !== "object" || !("jsonrpc" in data)) return;
106
+ if (!("method" in data)) return;
107
+
108
+ if (data.method === "ui/initialize" && "id" in data) {
109
+ window.postMessage({
110
+ jsonrpc: "2.0",
111
+ id: data.id,
112
+ result: {
113
+ protocolVersion: LATEST_PROTOCOL_VERSION,
114
+ hostCapabilities,
115
+ hostInfo,
116
+ hostContext,
117
+ },
118
+ });
119
+ }
120
+
121
+ // The App sends this notification after processing the initialize response
122
+ if (data.method === "ui/notifications/initialized") {
123
+ resolveInitialized();
124
+ }
125
+
126
+ if (data.method === "tools/call" && "id" in data) {
127
+ const { params } = data as unknown as CallToolRequest;
128
+
129
+ const handler = toolCallHandlers.get(params.name);
130
+
131
+ invariant(
132
+ handler,
133
+ `mockMcpHost: A mock tool call handler for '${params.name}' is not registered.`
134
+ );
135
+
136
+ window.postMessage({
137
+ jsonrpc: "2.0",
138
+ id: data.id,
139
+ result: handler(params),
140
+ });
141
+ }
142
+ };
143
+
144
+ window.addEventListener("message", listener);
145
+
146
+ function cleanup() {
147
+ window.removeEventListener("message", listener);
148
+ cleanupFns.forEach((fn) => fn());
149
+ restore();
150
+ }
151
+
152
+ return {
153
+ async sendToolResult(params) {
154
+ await initialized;
155
+ window.postMessage({
156
+ jsonrpc: "2.0",
157
+ method: "ui/notifications/tool-result",
158
+ params,
159
+ });
160
+ },
161
+ async sendToolInput(params) {
162
+ await initialized;
163
+ window.postMessage({
164
+ jsonrpc: "2.0",
165
+ method: "ui/notifications/tool-input",
166
+ params,
167
+ });
168
+ },
169
+ mockToolCall(name, handler) {
170
+ if (toolCallHandlers.has(name)) {
171
+ console.warn(
172
+ `mockMcpHost: a handler is already registered for tool "${name}"`
173
+ );
174
+ }
175
+
176
+ toolCallHandlers.set(name, handler);
177
+
178
+ return () => toolCallHandlers.delete(name);
179
+ },
180
+ onCleanup(fn) {
181
+ cleanupFns.add(fn);
182
+ },
183
+ cleanup,
184
+ [Symbol.dispose]() {
185
+ cleanup();
186
+ },
187
+ } satisfies MockMcpHost;
188
+ }
@@ -1,4 +1,4 @@
1
- import { SET_GLOBALS_EVENT_TYPE } from "../../../types/openai.js";
1
+ import { SET_GLOBALS_EVENT_TYPE } from "../../../openai/types.js";
2
2
 
3
3
  export function dispatchStateChange() {
4
4
  window.dispatchEvent(
@@ -3,15 +3,28 @@ import type {
3
3
  API,
4
4
  OpenAiGlobals,
5
5
  UnknownObject,
6
- } from "../../../types/openai.js";
6
+ } from "../../../openai/types.js";
7
+ import "../../../openai/globals.js";
7
8
  import { dispatchStateChange } from "./dispatchStateChange.js";
8
9
 
9
- export function stubOpenAiGlobals(globals?: Partial<API<any> & OpenAiGlobals>) {
10
- vi.stubGlobal("openai", {
11
- setWidgetState: (state: UnknownObject) => {
12
- window.openai.widgetState = state;
13
- dispatchStateChange();
14
- },
15
- ...globals,
16
- });
10
+ type Globals = API<any> & OpenAiGlobals;
11
+
12
+ const DEFAULTS = Object.freeze({
13
+ setWidgetState: async (state: UnknownObject) => {
14
+ window.openai.widgetState = state;
15
+ dispatchStateChange();
16
+ },
17
+ toolOutput: null,
18
+ toolResponseMetadata: null,
19
+ }) satisfies Partial<Globals>;
20
+
21
+ export function stubOpenAiGlobals(
22
+ globals?: Partial<Globals> | ((defaults: typeof DEFAULTS) => Partial<Globals>)
23
+ ) {
24
+ vi.stubGlobal(
25
+ "openai",
26
+ typeof globals === "function" ?
27
+ globals(DEFAULTS)
28
+ : { ...DEFAULTS, ...globals }
29
+ );
17
30
  }
@@ -0,0 +1,7 @@
1
+ import { act, render } from "@testing-library/react";
2
+
3
+ // Helper to silence act warnings when testing a component that suspends.
4
+ // See https://github.com/testing-library/react-testing-library/issues/1375
5
+ export async function renderAsync(...args: Parameters<typeof render>) {
6
+ return await act(async () => render(...args));
7
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Adapted from
3
+ * https://github.com/apollographql/apollo-client/blob/1d165ba37eca7e5d667055553aacc4c26be56065/src/testing/internal/ObservableStream.ts
4
+ */
5
+ import {
6
+ ReadableStream,
7
+ type ReadableStreamDefaultReader,
8
+ } from "node:stream/web";
9
+ import type { Observable, Subscribable, Unsubscribable } from "rxjs";
10
+ import { expect } from "vitest";
11
+ import { equals, iterableEquality, JEST_MATCHERS_OBJECT } from "@vitest/expect";
12
+ import { printDiffOrStringify } from "@vitest/utils/diff";
13
+
14
+ export interface TakeOptions {
15
+ timeout?: number;
16
+ }
17
+ type ObservableEvent<T> =
18
+ | { type: "next"; value: T }
19
+ | { type: "error"; error: any }
20
+ | { type: "complete" };
21
+
22
+ function formatMessage(
23
+ expected: ObservableEvent<any>,
24
+ actual: ObservableEvent<any>
25
+ ) {
26
+ return printDiffOrStringify(expected, actual, { expand: true });
27
+ }
28
+
29
+ export class EventMismatchError extends Error {
30
+ readonly actual: ObservableEvent<any>;
31
+ readonly expected: ObservableEvent<any>;
32
+
33
+ static is(error: unknown): error is EventMismatchError {
34
+ return error instanceof Error && error.name === "EventMismatchError";
35
+ }
36
+
37
+ constructor(expected: ObservableEvent<any>, actual: ObservableEvent<any>) {
38
+ super(formatMessage(expected, actual));
39
+ this.name = "EventMismatchError";
40
+ this.actual = actual;
41
+ this.expected = expected;
42
+
43
+ Object.setPrototypeOf(this, EventMismatchError.prototype);
44
+ }
45
+ }
46
+
47
+ export class ObservableStream<T> {
48
+ private reader: ReadableStreamDefaultReader<ObservableEvent<T>>;
49
+ private subscription!: Unsubscribable;
50
+ private readerQueue: Array<Promise<ObservableEvent<T>>> = [];
51
+
52
+ constructor(observable: Observable<T> | Subscribable<T>) {
53
+ this.unsubscribe = this.unsubscribe.bind(this);
54
+ this.reader = new ReadableStream<ObservableEvent<T>>({
55
+ start: (controller) => {
56
+ this.subscription = observable.subscribe({
57
+ next: (value) => controller.enqueue({ type: "next", value }),
58
+ error: (error) => controller.enqueue({ type: "error", error }),
59
+ complete: () => controller.enqueue({ type: "complete" }),
60
+ });
61
+ },
62
+ }).getReader();
63
+ }
64
+
65
+ peek({ timeout = 100 }: TakeOptions = {}) {
66
+ // Calling `peek` multiple times in a row should not advance the reader
67
+ // multiple times until this value has been consumed.
68
+ let readerPromise = this.readerQueue[0];
69
+
70
+ if (!readerPromise) {
71
+ // Since this.reader.read() advances the reader in the stream, we don't
72
+ // want to consume this promise entirely, otherwise we will miss it when
73
+ // calling `take`. Instead, we push it into a queue that can be consumed
74
+ // by `take` the next time its called so that we avoid advancing the
75
+ // reader until we are finished processing all peeked values.
76
+ readerPromise = this.readNextValue();
77
+ this.readerQueue.push(readerPromise);
78
+ }
79
+
80
+ return Promise.race([
81
+ readerPromise,
82
+ new Promise<ObservableEvent<T>>((_, reject) => {
83
+ setTimeout(
84
+ reject,
85
+ timeout,
86
+ new Error("Timeout waiting for next event")
87
+ );
88
+ }),
89
+ ]);
90
+ }
91
+
92
+ take({ timeout = 100 }: TakeOptions = {}) {
93
+ return Promise.race([
94
+ this.readerQueue.shift() || this.readNextValue(),
95
+ new Promise<ObservableEvent<T>>((_, reject) => {
96
+ setTimeout(
97
+ reject,
98
+ timeout,
99
+ new Error("Timeout waiting for next event")
100
+ );
101
+ }),
102
+ ]).then((value) => {
103
+ if (value.type === "next") {
104
+ this.current = value.value;
105
+ }
106
+ return value;
107
+ });
108
+ }
109
+
110
+ [Symbol.dispose]() {
111
+ this.unsubscribe();
112
+ }
113
+
114
+ unsubscribe() {
115
+ this.subscription.unsubscribe();
116
+ }
117
+
118
+ async takeNext(options?: TakeOptions): Promise<T> {
119
+ const event = await this.take(options);
120
+ if (event.type !== "next") {
121
+ throw new EventMismatchError(
122
+ { type: "next", value: expect.anything() },
123
+ event
124
+ );
125
+ }
126
+ return (event as ObservableEvent<T> & { type: "next" }).value;
127
+ }
128
+
129
+ async takeError(options?: TakeOptions): Promise<any> {
130
+ const event = await this.take(options);
131
+ validateEquals(event, { type: "error", error: expect.anything() });
132
+ return (event as ObservableEvent<T> & { type: "error" }).error;
133
+ }
134
+
135
+ async takeComplete(options?: TakeOptions): Promise<void> {
136
+ const event = await this.take(options);
137
+ validateEquals(event, { type: "complete" });
138
+ }
139
+
140
+ private async readNextValue() {
141
+ return this.reader.read().then((result) => result.value!);
142
+ }
143
+
144
+ private current?: T;
145
+ getCurrent() {
146
+ return this.current;
147
+ }
148
+ }
149
+
150
+ // Lightweight expect(...).toEqual(...) check that avoids using `expect` so that
151
+ // `expect.assertions(num)` does not double count assertions when using the take*
152
+ // functions inside of expect(stream).toEmit* matchers.
153
+ function validateEquals(
154
+ actualEvent: ObservableEvent<any>,
155
+ expectedEvent: ObservableEvent<any>
156
+ ) {
157
+ // Uses the same matchers as expect(...).toEqual(...)
158
+ // https://github.com/vitest-dev/vitest/blob/438c44e7fb8f3a6a36db8ff504f852c01963ba88/packages/expect/src/jest-expect.ts#L107-L110
159
+ const isEqual = equals(actualEvent, expectedEvent, [
160
+ ...getCustomEqualityTesters(),
161
+ iterableEquality,
162
+ ]);
163
+
164
+ if (!isEqual) {
165
+ throw new EventMismatchError(expectedEvent, actualEvent);
166
+ }
167
+ }
168
+
169
+ // https://github.com/vitest-dev/vitest/blob/438c44e7fb8f3a6a36db8ff504f852c01963ba88/packages/expect/src/jest-matcher-utils.ts#L157-L159
170
+ function getCustomEqualityTesters() {
171
+ return (globalThis as any)[JEST_MATCHERS_OBJECT].customEqualityTesters;
172
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Adapted from
3
+ * https://github.com/apollographql/apollo-client/blob/39adac005bfc947948960ec32635272d7d252bd5/src/testing/matchers/utils/getSerializableProperties.ts
4
+ */
5
+ import { ApolloClient, ObservableQuery } from "@apollo/client";
6
+ import { isPlainObject } from "@apollo/client/utilities/internal";
7
+
8
+ function isKnownClassInstance(value: unknown) {
9
+ return [ApolloClient, ObservableQuery].some((c) => value instanceof c);
10
+ }
11
+
12
+ export function getSerializableProperties(
13
+ obj: unknown,
14
+ {
15
+ includeKnownClassInstances = false,
16
+ }: {
17
+ includeKnownClassInstances?: boolean;
18
+ } = {}
19
+ ): any {
20
+ if (Array.isArray(obj)) {
21
+ return obj.map((item) =>
22
+ getSerializableProperties(item, {
23
+ includeKnownClassInstances,
24
+ })
25
+ );
26
+ }
27
+
28
+ if (isPlainObject(obj)) {
29
+ return [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)].reduce(
30
+ (memo, key) => {
31
+ const value = obj[key as any];
32
+ if (
33
+ typeof value === "function" ||
34
+ (!includeKnownClassInstances && isKnownClassInstance(value))
35
+ ) {
36
+ return memo;
37
+ }
38
+
39
+ // Recurse if we have a nested object/array
40
+ if (isPlainObject(value) || Array.isArray(value)) {
41
+ return {
42
+ ...memo,
43
+ [key]: getSerializableProperties(value, {
44
+ includeKnownClassInstances,
45
+ }),
46
+ };
47
+ }
48
+ return { ...memo, [key]: value };
49
+ },
50
+ {} as Record<string, any>
51
+ );
52
+ }
53
+
54
+ return obj;
55
+ }
@@ -0,0 +1,39 @@
1
+ import type { ApplicationManifest } from "../../../types/application-manifest";
2
+
3
+ export function mockApplicationManifest(
4
+ overrides?: Partial<ApplicationManifest>
5
+ ): ApplicationManifest {
6
+ return {
7
+ format: "apollo-ai-app-manifest",
8
+ version: "1",
9
+ appVersion: "1.0.0",
10
+ name: "the-store",
11
+ description:
12
+ "An online store selling a variety of high quality products across many different categories.",
13
+ hash: "f6a24922f6ad6ed8c2aa57baf3b8242ae5f38a09a6df3f2693077732434c4256",
14
+ operations: [
15
+ {
16
+ id: "c43af26552874026c3fb346148c5795896aa2f3a872410a0a2621cffee25291c",
17
+ name: "Product",
18
+ type: "query",
19
+ body: "query Product($id: ID!) {\n product(id: $id) {\n id\n title\n rating\n price\n description\n images\n __typename\n }\n}",
20
+ variables: { id: "ID" },
21
+ prefetch: false,
22
+ tools: [
23
+ {
24
+ name: "GetProduct",
25
+ description: "Shows the details page for a specific product.",
26
+ },
27
+ ],
28
+ },
29
+ ],
30
+ resource: "index.html",
31
+ csp: {
32
+ resourceDomains: [],
33
+ connectDomains: [],
34
+ frameDomains: [],
35
+ redirectDomains: [],
36
+ },
37
+ ...overrides,
38
+ };
39
+ }
@@ -0,0 +1,29 @@
1
+ import { vi, type Mock } from "vitest";
2
+
3
+ const noop = () => {};
4
+
5
+ type ConsoleMethod = "log" | "info" | "warn" | "error" | "debug";
6
+
7
+ type Spies<Keys extends ConsoleMethod[]> = Record<
8
+ Keys[number],
9
+ Mock<(message?: any, ...args: any[]) => void>
10
+ >;
11
+
12
+ export function spyOnConsole<Keys extends ConsoleMethod[]>(
13
+ ...spyOn: Keys
14
+ ): Spies<Keys> & Disposable {
15
+ const spies = {} as Spies<Keys>;
16
+ for (const key of spyOn) {
17
+ // @ts-ignore
18
+ spies[key] = vi.spyOn(console, key).mockImplementation(noop);
19
+ }
20
+
21
+ return {
22
+ ...spies,
23
+ [Symbol.dispose]() {
24
+ for (const spy of Object.values(spies) as Mock[]) {
25
+ spy.mockRestore();
26
+ }
27
+ },
28
+ };
29
+ }
@@ -0,0 +1,3 @@
1
+ export async function wait(ms: number) {
2
+ return new Promise<void>((res) => setTimeout(res, ms));
3
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "compilerOptions": {
3
+ "moduleSuffixes": [".mcp", ".openai", ""]
4
+ }
5
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "compilerOptions": {
3
+ "customConditions": ["mcp"],
4
+ "moduleSuffixes": [".mcp", ""]
5
+ }
6
+ }