@apollo/client-ai-apps 0.4.0 → 0.5.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.
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 +353 -0
  6. package/__mocks__/fs/promises.cjs +3 -0
  7. package/__mocks__/fs.cjs +3 -0
  8. package/dist/config/defineConfig.d.ts +26 -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
@@ -1,1199 +0,0 @@
1
- import type { Mock } from "vitest";
2
- import { expect, test, vi, describe, beforeEach } from "vitest";
3
- import { ApplicationManifestPlugin } from "../application_manifest_plugin.js";
4
- import fs from "fs";
5
- import * as glob from "glob";
6
- import path from "path";
7
- import type { ManifestWidgetSettings } from "../../types/application-manifest.js";
8
-
9
- const root = process.cwd();
10
-
11
- vi.mock(import("fs"), async (importOriginal) => {
12
- const actual = await importOriginal();
13
- return {
14
- default: {
15
- ...actual.default,
16
- readFileSync: vi.fn(),
17
- writeFileSync: vi.fn(),
18
- mkdirSync: vi.fn(),
19
- },
20
- };
21
- });
22
-
23
- vi.mock(import("path"), async (importOriginal) => {
24
- const actual = await importOriginal();
25
- return {
26
- default: {
27
- ...actual.default,
28
- resolve: vi.fn((...args) =>
29
- args.map((a, i) => (i === 0 ? a : a.replace(/^\//, ""))).join("/")
30
- ),
31
- dirname: vi.fn(),
32
- },
33
- };
34
- });
35
-
36
- vi.mock(import("glob"));
37
-
38
- beforeEach(() => {
39
- vi.clearAllMocks();
40
- });
41
-
42
- describe("buildStart", () => {
43
- test("Should write to dev application manifest file when using a serve command", async () => {
44
- mockReadFile({
45
- "package.json": JSON.stringify({
46
- labels: {
47
- toolInvocation: {
48
- invoking: "Testing global...",
49
- invoked: "Tested global!",
50
- },
51
- },
52
- widgetSettings: {
53
- description: "Test",
54
- domain: "https://example.com",
55
- prefersBorder: true,
56
- } satisfies ManifestWidgetSettings,
57
- }),
58
- [`${root}/my-component.tsx`]: `
59
- const MY_QUERY = gql\`query HelloWorldQuery($name: string!) @tool(
60
- name: "hello-world",
61
- description: "This is an awesome tool!",
62
- extraInputs: [{
63
- name: "doStuff",
64
- type: "boolean",
65
- description: "Should we do stuff?"
66
- }],
67
- labels: {
68
- toolInvocation: {
69
- invoking: "Testing tool...",
70
- invoked: "Tested tool!"
71
- }
72
- }
73
- ) { helloWorld(name: $name) }\`;
74
- `,
75
- });
76
-
77
- vi.spyOn(glob, "glob").mockImplementation(() =>
78
- Promise.resolve(["my-component.tsx"])
79
- );
80
- vi.spyOn(fs, "writeFileSync");
81
-
82
- const plugin = ApplicationManifestPlugin();
83
- plugin.configResolved({
84
- command: "serve",
85
- server: {},
86
- build: { outDir: "/dist" },
87
- });
88
- await plugin.buildStart();
89
- let [file, content] = (fs.writeFileSync as unknown as Mock).mock.calls[0];
90
-
91
- // Ignore the hash so we can do a snapshot that doesn't constantly change
92
- let contentObj = JSON.parse(content);
93
- contentObj.hash = "abc";
94
-
95
- expect(fs.writeFileSync).toHaveBeenCalledTimes(2);
96
- expect(file).toBe(root + "/dist/.application-manifest.json");
97
- expect(contentObj).toMatchInlineSnapshot(`
98
- {
99
- "csp": {
100
- "connectDomains": [],
101
- "frameDomains": [],
102
- "redirectDomains": [],
103
- "resourceDomains": [],
104
- },
105
- "format": "apollo-ai-app-manifest",
106
- "hash": "abc",
107
- "labels": {
108
- "toolInvocation/invoked": "Tested global!",
109
- "toolInvocation/invoking": "Testing global...",
110
- },
111
- "operations": [
112
- {
113
- "body": "query HelloWorldQuery($name: string!) {
114
- helloWorld(name: $name)
115
- }",
116
- "id": "c2ceb00338549909d9a8cd5cc601bda78d8c27654294dfe408a6c3735beb26a6",
117
- "name": "HelloWorldQuery",
118
- "prefetch": false,
119
- "tools": [
120
- {
121
- "description": "This is an awesome tool!",
122
- "extraInputs": [
123
- {
124
- "description": "Should we do stuff?",
125
- "name": "doStuff",
126
- "type": "boolean",
127
- },
128
- ],
129
- "labels": {
130
- "toolInvocation/invoked": "Tested tool!",
131
- "toolInvocation/invoking": "Testing tool...",
132
- },
133
- "name": "hello-world",
134
- },
135
- ],
136
- "type": "query",
137
- "variables": {
138
- "name": "string",
139
- },
140
- },
141
- ],
142
- "resource": "http://localhost:undefined",
143
- "version": "1",
144
- "widgetSettings": {
145
- "description": "Test",
146
- "domain": "https://example.com",
147
- "prefersBorder": true,
148
- },
149
- }
150
- `);
151
- });
152
-
153
- test("Should NOT write to dev application manifest file when using a build command", async () => {
154
- mockReadFile({
155
- "package.json": JSON.stringify({}),
156
- "my-component.tsx": `
157
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello-world", description: "This is an awesome tool!") { helloWorld }\`;
158
- `,
159
- });
160
- vi.spyOn(glob, "glob").mockImplementation(() =>
161
- Promise.resolve(["my-component.tsx"])
162
- );
163
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
164
- vi.spyOn(fs, "writeFileSync");
165
-
166
- const plugin = ApplicationManifestPlugin();
167
- plugin.configResolved({ command: "build", server: {} });
168
- await plugin.buildStart();
169
-
170
- expect(fs.writeFileSync).not.toHaveBeenCalled();
171
- });
172
-
173
- test("Should not process files that do not contain gql tags", async () => {
174
- mockReadFile({
175
- "package.json": JSON.stringify({}),
176
- [`${root}/my-component.tsx`]: `
177
- const MY_QUERY = \`query HelloWorldQuery @tool(name: "hello-world", description: "This is an awesome tool!") { helloWorld }\`;
178
- `,
179
- });
180
- vi.spyOn(glob, "glob").mockImplementation(() =>
181
- Promise.resolve(["my-component.tsx"])
182
- );
183
- vi.spyOn(fs, "writeFileSync");
184
-
185
- const plugin = ApplicationManifestPlugin();
186
- plugin.configResolved({
187
- command: "serve",
188
- server: {},
189
- build: { outDir: "/dist" },
190
- });
191
- await plugin.buildStart();
192
- let [file, content] = (fs.writeFileSync as unknown as Mock).mock.calls[0];
193
-
194
- // Ignore the hash so we can do a snapshot that doesn't constantly change
195
- let contentObj = JSON.parse(content);
196
- contentObj.hash = "abc";
197
-
198
- expect(fs.writeFileSync).toHaveBeenCalledTimes(2);
199
- expect(file).toBe(root + "/dist/.application-manifest.json");
200
- expect(contentObj).toMatchInlineSnapshot(`
201
- {
202
- "csp": {
203
- "connectDomains": [],
204
- "frameDomains": [],
205
- "redirectDomains": [],
206
- "resourceDomains": [],
207
- },
208
- "format": "apollo-ai-app-manifest",
209
- "hash": "abc",
210
- "operations": [],
211
- "resource": "http://localhost:undefined",
212
- "version": "1",
213
- }
214
- `);
215
- });
216
-
217
- test("Should capture queries when writing to manifest file", async () => {
218
- mockReadFile({
219
- "package.json": JSON.stringify({}),
220
- [`${root}/my-component.tsx`]: `
221
- const MY_QUERY = gql\`query HelloWorldQuery { helloWorld }\`;
222
- `,
223
- });
224
- vi.spyOn(glob, "glob").mockImplementation(() =>
225
- Promise.resolve(["my-component.tsx"])
226
- );
227
- vi.spyOn(fs, "writeFileSync");
228
-
229
- const plugin = ApplicationManifestPlugin();
230
- plugin.configResolved({
231
- command: "serve",
232
- server: {},
233
- build: { outDir: "/dist" },
234
- });
235
- await plugin.buildStart();
236
- let [file, content] = (fs.writeFileSync as unknown as Mock).mock.calls[0];
237
-
238
- // Ignore the hash so we can do a snapshot that doesn't constantly change
239
- let contentObj = JSON.parse(content);
240
- contentObj.hash = "abc";
241
-
242
- expect(fs.writeFileSync).toHaveBeenCalledTimes(2);
243
- expect(file).toBe(root + "/dist/.application-manifest.json");
244
- expect(contentObj).toMatchInlineSnapshot(`
245
- {
246
- "csp": {
247
- "connectDomains": [],
248
- "frameDomains": [],
249
- "redirectDomains": [],
250
- "resourceDomains": [],
251
- },
252
- "format": "apollo-ai-app-manifest",
253
- "hash": "abc",
254
- "operations": [
255
- {
256
- "body": "query HelloWorldQuery {
257
- helloWorld
258
- }",
259
- "id": "f8604bba13e2f589608c0eb36c3039c5ef3a4c5747bc1596f9dbcbe924dc90f9",
260
- "name": "HelloWorldQuery",
261
- "prefetch": false,
262
- "tools": [],
263
- "type": "query",
264
- "variables": {},
265
- },
266
- ],
267
- "resource": "http://localhost:undefined",
268
- "version": "1",
269
- }
270
- `);
271
- });
272
-
273
- test("Should capture queries as prefetch when query is marked with @prefetch directive", async () => {
274
- mockReadFile({
275
- "package.json": JSON.stringify({}),
276
- [`${root}/my-component.tsx`]: `
277
- const MY_QUERY = gql\`query HelloWorldQuery @prefetch { helloWorld }\`;
278
- `,
279
- });
280
- vi.spyOn(glob, "glob").mockImplementation(() =>
281
- Promise.resolve(["my-component.tsx"])
282
- );
283
- vi.spyOn(fs, "writeFileSync");
284
-
285
- const plugin = ApplicationManifestPlugin();
286
- plugin.configResolved({
287
- command: "serve",
288
- server: {},
289
- build: { outDir: "/dist" },
290
- });
291
- await plugin.buildStart();
292
- let [file, content] = (fs.writeFileSync as unknown as Mock).mock.calls[0];
293
-
294
- // Ignore the hash so we can do a snapshot that doesn't constantly change
295
- let contentObj = JSON.parse(content);
296
- contentObj.hash = "abc";
297
-
298
- expect(fs.writeFileSync).toHaveBeenCalledTimes(2);
299
- expect(file).toBe(root + "/dist/.application-manifest.json");
300
- expect(contentObj).toMatchInlineSnapshot(`
301
- {
302
- "csp": {
303
- "connectDomains": [],
304
- "frameDomains": [],
305
- "redirectDomains": [],
306
- "resourceDomains": [],
307
- },
308
- "format": "apollo-ai-app-manifest",
309
- "hash": "abc",
310
- "operations": [
311
- {
312
- "body": "query HelloWorldQuery {
313
- helloWorld
314
- }",
315
- "id": "f8604bba13e2f589608c0eb36c3039c5ef3a4c5747bc1596f9dbcbe924dc90f9",
316
- "name": "HelloWorldQuery",
317
- "prefetch": true,
318
- "prefetchID": "__anonymous",
319
- "tools": [],
320
- "type": "query",
321
- "variables": {},
322
- },
323
- ],
324
- "resource": "http://localhost:undefined",
325
- "version": "1",
326
- }
327
- `);
328
- });
329
-
330
- test("Should error when multiple operations are marked with @prefetch", async () => {
331
- mockReadFile({
332
- "package.json": JSON.stringify({}),
333
- "my-component.tsx": `
334
- const MY_QUERY = gql\`query HelloWorldQuery @prefetch { helloWorld }\`;
335
- const MY_QUERY2 = gql\`query HelloWorldQuery2 @prefetch { helloWorld }\`;
336
- `,
337
- });
338
- vi.spyOn(glob, "glob").mockImplementation(() =>
339
- Promise.resolve(["my-component.tsx"])
340
- );
341
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
342
- vi.spyOn(fs, "writeFileSync");
343
-
344
- const plugin = ApplicationManifestPlugin();
345
- plugin.configResolved({ command: "serve", server: {} });
346
- await expect(
347
- async () => await plugin.buildStart()
348
- ).rejects.toThrowErrorMatchingInlineSnapshot(
349
- `[Error: Found multiple operations marked as \`@prefetch\`. You can only mark 1 operation with \`@prefetch\`.]`
350
- );
351
- });
352
-
353
- test("Should capture mutations when writing to manifest file", async () => {
354
- mockReadFile({
355
- "package.json": JSON.stringify({}),
356
- [`${root}/my-component.tsx`]: `
357
- const MY_QUERY = gql\`mutation HelloWorldQuery @tool(name: "hello-world", description: "This is an awesome tool!") { helloWorld }\`;
358
- `,
359
- });
360
- vi.spyOn(glob, "glob").mockImplementation(() =>
361
- Promise.resolve(["my-component.tsx"])
362
- );
363
- vi.spyOn(fs, "writeFileSync");
364
-
365
- const plugin = ApplicationManifestPlugin();
366
- plugin.configResolved({
367
- command: "serve",
368
- server: {},
369
- build: { outDir: "/dist" },
370
- });
371
- await plugin.buildStart();
372
- let [file, content] = (fs.writeFileSync as unknown as Mock).mock.calls[0];
373
-
374
- // Ignore the hash so we can do a snapshot that doesn't constantly change
375
- let contentObj = JSON.parse(content);
376
- contentObj.hash = "abc";
377
-
378
- expect(fs.writeFileSync).toHaveBeenCalledTimes(2);
379
- expect(file).toBe(root + "/dist/.application-manifest.json");
380
- expect(contentObj).toMatchInlineSnapshot(`
381
- {
382
- "csp": {
383
- "connectDomains": [],
384
- "frameDomains": [],
385
- "redirectDomains": [],
386
- "resourceDomains": [],
387
- },
388
- "format": "apollo-ai-app-manifest",
389
- "hash": "abc",
390
- "operations": [
391
- {
392
- "body": "mutation HelloWorldQuery {
393
- helloWorld
394
- }",
395
- "id": "0c98e15f08542215c9c268192aaff732800bc33b79dddea7dc6fdf69c21b61a7",
396
- "name": "HelloWorldQuery",
397
- "prefetch": false,
398
- "tools": [
399
- {
400
- "description": "This is an awesome tool!",
401
- "name": "hello-world",
402
- },
403
- ],
404
- "type": "mutation",
405
- "variables": {},
406
- },
407
- ],
408
- "resource": "http://localhost:undefined",
409
- "version": "1",
410
- }
411
- `);
412
- });
413
-
414
- test("Should throw error when a subscription operation type is discovered", async () => {
415
- mockReadFile({
416
- "package.json": JSON.stringify({}),
417
- "my-component.tsx": `
418
- const MY_QUERY = gql\`subscription HelloWorldQuery @tool(name: "hello-world", description: "This is an awesome tool!") { helloWorld }\`;
419
- `,
420
- });
421
- vi.spyOn(glob, "glob").mockImplementation(() =>
422
- Promise.resolve(["my-component.tsx"])
423
- );
424
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
425
- vi.spyOn(fs, "writeFileSync");
426
-
427
- const plugin = ApplicationManifestPlugin();
428
- plugin.configResolved({ command: "serve", server: {} });
429
-
430
- await expect(
431
- async () => await plugin.buildStart()
432
- ).rejects.toThrowErrorMatchingInlineSnapshot(
433
- `[Error: Found an unsupported operation type. Only Query and Mutation are supported.]`
434
- );
435
- });
436
-
437
- test("Should use custom entry point when in serve mode and provided in package.json", async () => {
438
- mockReadFile({
439
- "package.json": JSON.stringify({
440
- entry: {
441
- staging: "http://staging.awesome.com",
442
- },
443
- }),
444
- "my-component.tsx": `
445
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello-world", description: "This is an awesome tool!") { helloWorld }\`;
446
- `,
447
- });
448
- vi.spyOn(glob, "glob").mockImplementation(() =>
449
- Promise.resolve(["my-component.tsx"])
450
- );
451
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
452
- vi.spyOn(fs, "writeFileSync");
453
-
454
- const plugin = ApplicationManifestPlugin();
455
- plugin.configResolved({
456
- command: "serve",
457
- mode: "staging",
458
- server: {},
459
- build: { outDir: "/dist" },
460
- });
461
- await plugin.buildStart();
462
-
463
- let [, content] = (fs.writeFileSync as unknown as Mock).mock.calls[0];
464
- let contentObj = JSON.parse(content);
465
-
466
- expect(contentObj.resource).toBe("http://staging.awesome.com");
467
- });
468
-
469
- test("Should use https when enabled in server config", async () => {
470
- mockReadFile({
471
- "package.json": JSON.stringify({}),
472
- "my-component.tsx": `
473
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello-world", description: "This is an awesome tool!") { helloWorld }\`;
474
- `,
475
- });
476
- vi.spyOn(glob, "glob").mockImplementation(() =>
477
- Promise.resolve(["my-component.tsx"])
478
- );
479
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
480
- vi.spyOn(fs, "writeFileSync");
481
-
482
- const plugin = ApplicationManifestPlugin();
483
- plugin.configResolved({
484
- command: "serve",
485
- server: { https: {}, port: "5678" },
486
- build: { outDir: "/dist" },
487
- });
488
- await plugin.buildStart();
489
-
490
- let [, content] = (fs.writeFileSync as unknown as Mock).mock.calls[0];
491
- let contentObj = JSON.parse(content);
492
-
493
- expect(contentObj.resource).toBe("https://localhost:5678");
494
- });
495
-
496
- test("Should use custom host when specified in server config", async () => {
497
- mockReadFile({
498
- "package.json": JSON.stringify({}),
499
- "my-component.tsx": `
500
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello-world", description: "This is an awesome tool!") { helloWorld }\`;
501
- `,
502
- });
503
- vi.spyOn(glob, "glob").mockImplementation(() =>
504
- Promise.resolve(["my-component.tsx"])
505
- );
506
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
507
- vi.spyOn(fs, "writeFileSync");
508
-
509
- const plugin = ApplicationManifestPlugin();
510
- plugin.configResolved({
511
- command: "serve",
512
- server: { port: "5678", host: "awesome.com" },
513
- build: { outDir: "/dist" },
514
- });
515
- await plugin.buildStart();
516
-
517
- let [, content] = (fs.writeFileSync as unknown as Mock).mock.calls[0];
518
- let contentObj = JSON.parse(content);
519
-
520
- expect(contentObj.resource).toBe("http://awesome.com:5678");
521
- });
522
-
523
- test("Should error when tool name is not provided", async () => {
524
- mockReadFile({
525
- "package.json": JSON.stringify({}),
526
- "my-component.tsx": `
527
- const MY_QUERY = gql\`query HelloWorldQuery @tool { helloWorld }\`;
528
- `,
529
- });
530
- vi.spyOn(glob, "glob").mockImplementation(() =>
531
- Promise.resolve(["my-component.tsx"])
532
- );
533
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
534
- vi.spyOn(fs, "writeFileSync");
535
-
536
- const plugin = ApplicationManifestPlugin();
537
- plugin.configResolved({ command: "serve", server: {} });
538
-
539
- await expect(
540
- async () => await plugin.buildStart()
541
- ).rejects.toThrowErrorMatchingInlineSnapshot(
542
- `[Error: 'name' argument must be supplied for @tool]`
543
- );
544
- });
545
-
546
- test("Should error when tool description is not provided", async () => {
547
- mockReadFile({
548
- "package.json": JSON.stringify({}),
549
- "my-component.tsx": `
550
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello-world") { helloWorld }\`;
551
- `,
552
- });
553
- vi.spyOn(glob, "glob").mockImplementation(() =>
554
- Promise.resolve(["my-component.tsx"])
555
- );
556
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
557
- vi.spyOn(fs, "writeFileSync");
558
-
559
- const plugin = ApplicationManifestPlugin();
560
- plugin.configResolved({ command: "serve", server: {} });
561
-
562
- await expect(
563
- async () => await plugin.buildStart()
564
- ).rejects.toThrowErrorMatchingInlineSnapshot(
565
- `[Error: 'description' argument must be supplied for @tool]`
566
- );
567
- });
568
-
569
- test("Should error when tool name contains spaces", async () => {
570
- mockReadFile({
571
- "package.json": JSON.stringify({}),
572
- "my-component.tsx": `
573
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello world", description: "A tool") { helloWorld }\`;
574
- `,
575
- });
576
- vi.spyOn(glob, "glob").mockImplementation(() =>
577
- Promise.resolve(["my-component.tsx"])
578
- );
579
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
580
- vi.spyOn(fs, "writeFileSync");
581
-
582
- const plugin = ApplicationManifestPlugin();
583
- plugin.configResolved({ command: "serve", server: {} });
584
-
585
- await expect(
586
- async () => await plugin.buildStart()
587
- ).rejects.toThrowErrorMatchingInlineSnapshot(
588
- `[Error: Tool with name "hello world" contains spaces which is not allowed.]`
589
- );
590
- });
591
-
592
- test("Should error when tool name is not a string", async () => {
593
- mockReadFile({
594
- "package.json": JSON.stringify({}),
595
- "my-component.tsx": `
596
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: true) { helloWorld }\`;
597
- `,
598
- });
599
- vi.spyOn(glob, "glob").mockImplementation(() =>
600
- Promise.resolve(["my-component.tsx"])
601
- );
602
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
603
- vi.spyOn(fs, "writeFileSync");
604
-
605
- const plugin = ApplicationManifestPlugin();
606
- plugin.configResolved({ command: "serve", server: {} });
607
-
608
- await expect(
609
- async () => await plugin.buildStart()
610
- ).rejects.toThrowErrorMatchingInlineSnapshot(
611
- `[Error: Expected argument 'name' to be of type 'StringValue' but found 'BooleanValue' instead.]`
612
- );
613
- });
614
-
615
- test("Should error when tool description is not a string", async () => {
616
- mockReadFile({
617
- "package.json": JSON.stringify({}),
618
- "my-component.tsx": `
619
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello-world", description: false) { helloWorld }\`;
620
- `,
621
- });
622
- vi.spyOn(glob, "glob").mockImplementation(() =>
623
- Promise.resolve(["my-component.tsx"])
624
- );
625
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
626
- vi.spyOn(fs, "writeFileSync");
627
-
628
- const plugin = ApplicationManifestPlugin();
629
- plugin.configResolved({ command: "serve", server: {} });
630
-
631
- await expect(
632
- async () => await plugin.buildStart()
633
- ).rejects.toThrowErrorMatchingInlineSnapshot(
634
- `[Error: Expected argument 'description' to be of type 'StringValue' but found 'BooleanValue' instead.]`
635
- );
636
- });
637
-
638
- test("Should error when extraInputs is not an array", async () => {
639
- mockReadFile({
640
- "package.json": JSON.stringify({}),
641
- "my-component.tsx": `
642
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello-world", description: "hello", extraInputs: false ) { helloWorld }\`;
643
- `,
644
- });
645
- vi.spyOn(glob, "glob").mockImplementation(() =>
646
- Promise.resolve(["my-component.tsx"])
647
- );
648
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
649
- vi.spyOn(fs, "writeFileSync");
650
-
651
- const plugin = ApplicationManifestPlugin();
652
- plugin.configResolved({ command: "serve", server: {} });
653
-
654
- await expect(
655
- async () => await plugin.buildStart()
656
- ).rejects.toThrowErrorMatchingInlineSnapshot(
657
- `[Error: Expected argument 'extraInputs' to be of type 'ListValue' but found 'BooleanValue' instead.]`
658
- );
659
- });
660
-
661
- test("Should error when widgetSettings.prefersBorder is not a boolean", async () => {
662
- mockReadFile({
663
- "package.json": JSON.stringify({
664
- widgetSettings: {
665
- prefersBorder: "test",
666
- },
667
- }),
668
- "my-component.tsx": `
669
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "test", description: "Test") { helloWorld }\`;
670
- `,
671
- });
672
- vi.spyOn(glob, "glob").mockImplementation(() =>
673
- Promise.resolve(["my-component.tsx"])
674
- );
675
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
676
- vi.spyOn(fs, "writeFileSync");
677
-
678
- const plugin = ApplicationManifestPlugin();
679
- plugin.configResolved({ command: "serve", server: {} });
680
-
681
- await expect(
682
- async () => await plugin.buildStart()
683
- ).rejects.toThrowErrorMatchingInlineSnapshot(
684
- `[Error: Expected 'widgetSettings.prefersBorder' to be of type 'boolean' but found 'string' instead.]`
685
- );
686
- });
687
-
688
- test("Should error when widgetSettings.description is not a string", async () => {
689
- mockReadFile({
690
- "package.json": JSON.stringify({
691
- widgetSettings: {
692
- description: true,
693
- },
694
- }),
695
- "my-component.tsx": `
696
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "test", description: "Test") { helloWorld }\`;
697
- `,
698
- });
699
- vi.spyOn(glob, "glob").mockImplementation(() =>
700
- Promise.resolve(["my-component.tsx"])
701
- );
702
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
703
- vi.spyOn(fs, "writeFileSync");
704
-
705
- const plugin = ApplicationManifestPlugin();
706
- plugin.configResolved({ command: "serve", server: {} });
707
-
708
- await expect(
709
- async () => await plugin.buildStart()
710
- ).rejects.toThrowErrorMatchingInlineSnapshot(
711
- `[Error: Expected 'widgetSettings.description' to be of type 'string' but found 'boolean' instead.]`
712
- );
713
- });
714
-
715
- test("Should error when widgetSettings.domain is not a string", async () => {
716
- mockReadFile({
717
- "package.json": JSON.stringify({
718
- widgetSettings: {
719
- domain: true,
720
- },
721
- }),
722
- "my-component.tsx": `
723
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "test", description: "Test") { helloWorld }\`;
724
- `,
725
- });
726
- vi.spyOn(glob, "glob").mockImplementation(() =>
727
- Promise.resolve(["my-component.tsx"])
728
- );
729
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
730
- vi.spyOn(fs, "writeFileSync");
731
-
732
- const plugin = ApplicationManifestPlugin();
733
- plugin.configResolved({ command: "serve", server: {} });
734
-
735
- await expect(
736
- async () => await plugin.buildStart()
737
- ).rejects.toThrowErrorMatchingInlineSnapshot(
738
- `[Error: Expected 'widgetSettings.domain' to be of type 'string' but found 'boolean' instead.]`
739
- );
740
- });
741
-
742
- test("Should allow empty widgetSettings value", async () => {
743
- mockReadFile({
744
- "package.json": JSON.stringify({
745
- widgetSettings: {},
746
- }),
747
- "my-component.tsx": `
748
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "test", description: "Test") { helloWorld }\`;
749
- `,
750
- });
751
- vi.spyOn(glob, "glob").mockImplementation(() =>
752
- Promise.resolve(["my-component.tsx"])
753
- );
754
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
755
- vi.spyOn(fs, "writeFileSync");
756
-
757
- const plugin = ApplicationManifestPlugin();
758
- plugin.configResolved({ command: "serve", server: {}, build: {} });
759
-
760
- await expect(plugin.buildStart()).resolves.toBeUndefined();
761
- });
762
-
763
- test("Should error when labels.toolInvocation.invoking in package.json is not a string", async () => {
764
- mockReadFile({
765
- "package.json": JSON.stringify({
766
- labels: {
767
- toolInvocation: {
768
- invoking: true,
769
- },
770
- },
771
- }),
772
- "my-component.tsx": `
773
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "test", description: "Test") { helloWorld }\`;
774
- `,
775
- });
776
- vi.spyOn(glob, "glob").mockImplementation(() =>
777
- Promise.resolve(["my-component.tsx"])
778
- );
779
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
780
- vi.spyOn(fs, "writeFileSync");
781
-
782
- const plugin = ApplicationManifestPlugin();
783
- plugin.configResolved({ command: "serve", server: {} });
784
-
785
- await expect(
786
- async () => await plugin.buildStart()
787
- ).rejects.toThrowErrorMatchingInlineSnapshot(
788
- `[Error: Expected 'labels.toolInvocation.invoking' to be of type 'string' but found 'boolean' instead.]`
789
- );
790
- });
791
-
792
- test("Should error when labels.toolInvocation.invoking in @tool is not a string", async () => {
793
- mockReadFile({
794
- "package.json": JSON.stringify({}),
795
- "my-component.tsx": `
796
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "test", description: "Test", labels: { toolInvocation: { invoking: true } }) { helloWorld }\`;
797
- `,
798
- });
799
- vi.spyOn(glob, "glob").mockImplementation(() =>
800
- Promise.resolve(["my-component.tsx"])
801
- );
802
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
803
- vi.spyOn(fs, "writeFileSync");
804
-
805
- const plugin = ApplicationManifestPlugin();
806
- plugin.configResolved({ command: "serve", server: {} });
807
-
808
- await expect(
809
- async () => await plugin.buildStart()
810
- ).rejects.toThrowErrorMatchingInlineSnapshot(
811
- `[Error: Expected 'labels.toolInvocation.invoking' to be of type 'string' but found 'boolean' instead.]`
812
- );
813
- });
814
-
815
- test("Should error when labels.toolInvocation.invoked in package.json is not a string", async () => {
816
- mockReadFile({
817
- "package.json": JSON.stringify({
818
- labels: {
819
- toolInvocation: {
820
- invoked: true,
821
- },
822
- },
823
- }),
824
- "my-component.tsx": `
825
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "test", description: "Test") { helloWorld }\`;
826
- `,
827
- });
828
- vi.spyOn(glob, "glob").mockImplementation(() =>
829
- Promise.resolve(["my-component.tsx"])
830
- );
831
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
832
- vi.spyOn(fs, "writeFileSync");
833
-
834
- const plugin = ApplicationManifestPlugin();
835
- plugin.configResolved({ command: "serve", server: {} });
836
-
837
- await expect(
838
- async () => await plugin.buildStart()
839
- ).rejects.toThrowErrorMatchingInlineSnapshot(
840
- `[Error: Expected 'labels.toolInvocation.invoked' to be of type 'string' but found 'boolean' instead.]`
841
- );
842
- });
843
-
844
- test("Should error when labels.toolInvocation.invoked in @tool is not a string", async () => {
845
- mockReadFile({
846
- "package.json": JSON.stringify({}),
847
- "my-component.tsx": `
848
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "test", description: "Test", labels: { toolInvocation: { invoked: true } }) { helloWorld }\`;
849
- `,
850
- });
851
- vi.spyOn(glob, "glob").mockImplementation(() =>
852
- Promise.resolve(["my-component.tsx"])
853
- );
854
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
855
- vi.spyOn(fs, "writeFileSync");
856
-
857
- const plugin = ApplicationManifestPlugin();
858
- plugin.configResolved({ command: "serve", server: {} });
859
-
860
- await expect(
861
- async () => await plugin.buildStart()
862
- ).rejects.toThrowErrorMatchingInlineSnapshot(
863
- `[Error: Expected 'labels.toolInvocation.invoked' to be of type 'string' but found 'boolean' instead.]`
864
- );
865
- });
866
-
867
- test("Should allow empty labels value", async () => {
868
- mockReadFile({
869
- "package.json": JSON.stringify({
870
- labels: {},
871
- }),
872
- "my-component.tsx": `
873
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "test", description: "Test", labels: {}) { helloWorld }\`;
874
- `,
875
- });
876
- vi.spyOn(glob, "glob").mockImplementation(() =>
877
- Promise.resolve(["my-component.tsx"])
878
- );
879
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
880
- vi.spyOn(fs, "writeFileSync");
881
-
882
- const plugin = ApplicationManifestPlugin();
883
- plugin.configResolved({ command: "serve", server: {}, build: {} });
884
-
885
- await expect(plugin.buildStart()).resolves.toBeUndefined();
886
- });
887
-
888
- test("Should error when an unknown type is discovered", async () => {
889
- mockReadFile({
890
- "package.json": JSON.stringify({}),
891
- "my-component.tsx": `
892
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello-world", description: "hello", extraInputs: [{
893
- name: 3.1
894
- }] ) { helloWorld }\`;
895
- `,
896
- });
897
- vi.spyOn(glob, "glob").mockImplementation(() =>
898
- Promise.resolve(["my-component.tsx"])
899
- );
900
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
901
- vi.spyOn(fs, "writeFileSync");
902
-
903
- const plugin = ApplicationManifestPlugin();
904
- plugin.configResolved({ command: "serve", server: {} });
905
-
906
- await expect(
907
- async () => await plugin.buildStart()
908
- ).rejects.toThrowErrorMatchingInlineSnapshot(
909
- `[Error: Error when parsing directive values: unexpected type 'FloatValue']`
910
- );
911
- });
912
-
913
- test("Should order operations and fragments when generating normalized operation", async () => {
914
- mockReadFile({
915
- "package.json": JSON.stringify({}),
916
- [`${root}/my-component.tsx`]: `
917
- const MY_QUERY = gql\`
918
- fragment A on User { firstName }
919
- fragment B on User { lastName }
920
- query HelloWorldQuery @tool(name: "hello-world", description: "This is an awesome tool!") {
921
- helloWorld {
922
- ...B
923
- ...A
924
- ...C
925
- }
926
-
927
- fragment C on User { middleName }
928
- }\`;
929
- `,
930
- });
931
- vi.spyOn(glob, "glob").mockImplementation(() =>
932
- Promise.resolve(["my-component.tsx"])
933
- );
934
- vi.spyOn(fs, "writeFileSync");
935
-
936
- const plugin = ApplicationManifestPlugin();
937
- plugin.configResolved({
938
- command: "serve",
939
- server: {},
940
- build: { outDir: "/dist" },
941
- });
942
- await plugin.buildStart();
943
- let [file, content] = (fs.writeFileSync as unknown as Mock).mock.calls[0];
944
-
945
- // Ignore the hash so we can do a snapshot that doesn't constantly change
946
- let contentObj = JSON.parse(content);
947
- contentObj.hash = "abc";
948
-
949
- expect(fs.writeFileSync).toHaveBeenCalledTimes(2);
950
- expect(file).toBe(`${root}/dist/.application-manifest.json`);
951
- expect(contentObj).toMatchInlineSnapshot(`
952
- {
953
- "csp": {
954
- "connectDomains": [],
955
- "frameDomains": [],
956
- "redirectDomains": [],
957
- "resourceDomains": [],
958
- },
959
- "format": "apollo-ai-app-manifest",
960
- "hash": "abc",
961
- "operations": [
962
- {
963
- "body": "query HelloWorldQuery {
964
- helloWorld {
965
- ...B
966
- ...A
967
- ...C
968
- __typename
969
- }
970
- fragment
971
- C
972
- on
973
- User {
974
- middleName
975
- __typename
976
- }
977
- }
978
-
979
- fragment A on User {
980
- firstName
981
- __typename
982
- }
983
-
984
- fragment B on User {
985
- lastName
986
- __typename
987
- }",
988
- "id": "58359ad006a8e1a6cdabe4b49c0322e8a41d71c5194a796e6432be055220b9ec",
989
- "name": "HelloWorldQuery",
990
- "prefetch": false,
991
- "tools": [
992
- {
993
- "description": "This is an awesome tool!",
994
- "name": "hello-world",
995
- },
996
- ],
997
- "type": "query",
998
- "variables": {},
999
- },
1000
- ],
1001
- "resource": "http://localhost:undefined",
1002
- "version": "1",
1003
- }
1004
- `);
1005
- });
1006
- });
1007
-
1008
- describe("writeBundle", () => {
1009
- test("Should use custom entry point when in build mode and provided in package.json", async () => {
1010
- mockReadFile({
1011
- "package.json": JSON.stringify({
1012
- entry: {
1013
- staging: "http://staging.awesome.com",
1014
- },
1015
- }),
1016
- "my-component.tsx": `
1017
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello-world", description: "This is an awesome tool!") { helloWorld }\`;
1018
- `,
1019
- });
1020
- vi.spyOn(glob, "glob").mockImplementation(() =>
1021
- Promise.resolve(["my-component.tsx"])
1022
- );
1023
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
1024
- vi.spyOn(path, "dirname").mockImplementation(() => "/dist");
1025
- vi.spyOn(fs, "writeFileSync");
1026
-
1027
- const plugin = ApplicationManifestPlugin();
1028
- plugin.configResolved({
1029
- command: "build",
1030
- mode: "staging",
1031
- server: {},
1032
- build: { outDir: "/dist/" },
1033
- });
1034
- await plugin.buildStart();
1035
- await plugin.writeBundle();
1036
-
1037
- let [, content] = (fs.writeFileSync as unknown as Mock).mock.calls[0];
1038
- let contentObj = JSON.parse(content);
1039
-
1040
- expect(contentObj.resource).toBe("http://staging.awesome.com");
1041
- });
1042
-
1043
- test("Should use index.html when in build production and not provided in package.json", async () => {
1044
- mockReadFile({
1045
- "package.json": JSON.stringify({}),
1046
- "my-component.tsx": `
1047
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello-world", description: "This is an awesome tool!") { helloWorld }\`;
1048
- `,
1049
- });
1050
- vi.spyOn(glob, "glob").mockImplementation(() =>
1051
- Promise.resolve(["my-component.tsx"])
1052
- );
1053
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
1054
- vi.spyOn(path, "dirname").mockImplementation(() => "/dist");
1055
- vi.spyOn(fs, "writeFileSync");
1056
-
1057
- const plugin = ApplicationManifestPlugin();
1058
- plugin.configResolved({
1059
- command: "build",
1060
- mode: "production",
1061
- server: {},
1062
- build: { outDir: "/dist/" },
1063
- });
1064
- await plugin.buildStart();
1065
- await plugin.writeBundle();
1066
-
1067
- let [, content] = (fs.writeFileSync as unknown as Mock).mock.calls[0];
1068
- let contentObj = JSON.parse(content);
1069
-
1070
- expect(contentObj.resource).toBe("index.html");
1071
- });
1072
-
1073
- test("Should throw an error when in build mode and using a mode that is not production and not provided in package.json", async () => {
1074
- mockReadFile({
1075
- "package.json": JSON.stringify({}),
1076
- "my-component.tsx": `
1077
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello-world", description: "This is an awesome tool!") { helloWorld }\`;
1078
- `,
1079
- });
1080
- vi.spyOn(glob, "glob").mockImplementation(() =>
1081
- Promise.resolve(["my-component.tsx"])
1082
- );
1083
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
1084
- vi.spyOn(path, "dirname").mockImplementation(() => "/dist");
1085
- vi.spyOn(fs, "writeFileSync");
1086
-
1087
- const plugin = ApplicationManifestPlugin();
1088
- plugin.configResolved({
1089
- command: "build",
1090
- mode: "staging",
1091
- server: {},
1092
- build: { outDir: "/dist/" },
1093
- });
1094
- await plugin.buildStart();
1095
-
1096
- await expect(
1097
- async () => await plugin.writeBundle()
1098
- ).rejects.toThrowErrorMatchingInlineSnapshot(
1099
- `[Error: No entry point found for mode "staging". Entry points other than "development" and "production" must be defined in package.json file.]`
1100
- );
1101
- });
1102
-
1103
- test("Should always write to both locations when running in build mode", async () => {
1104
- mockReadFile({
1105
- "package.json": JSON.stringify({}),
1106
- "my-component.tsx": `
1107
- const MY_QUERY = gql\`query HelloWorldQuery @tool(name: "hello-world", description: "This is an awesome tool!") { helloWorld }\`;
1108
- `,
1109
- });
1110
- vi.spyOn(glob, "glob").mockImplementation(() =>
1111
- Promise.resolve(["my-component.tsx"])
1112
- );
1113
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
1114
- vi.spyOn(path, "dirname").mockImplementation(() => "/dist");
1115
- vi.spyOn(fs, "writeFileSync");
1116
-
1117
- const plugin = ApplicationManifestPlugin();
1118
- plugin.configResolved({
1119
- command: "build",
1120
- mode: "production",
1121
- server: {},
1122
- build: { outDir: "/dist/" },
1123
- });
1124
- await plugin.buildStart();
1125
- await plugin.writeBundle();
1126
-
1127
- expect(fs.writeFileSync).toBeCalledTimes(2);
1128
- });
1129
- });
1130
-
1131
- describe("configureServer", () => {
1132
- test("Should write to manifest file when package.json or file is updated", async () => {
1133
- mockReadFile({
1134
- "package.json": JSON.stringify({}),
1135
- "my-component.tsx": `
1136
- const MY_QUERY = gql\`query HelloWorldQuery($name: string!) @tool(name: "hello-world", description: "This is an awesome tool!", extraInputs: [{
1137
- name: "doStuff",
1138
- type: "boolean",
1139
- description: "Should we do stuff?"
1140
- }]) { helloWorld(name: $name) }\`;
1141
- `,
1142
- });
1143
- vi.spyOn(glob, "glob").mockImplementation(() =>
1144
- Promise.resolve(["my-component.tsx"])
1145
- );
1146
- vi.spyOn(path, "resolve").mockImplementation((_, file) => file);
1147
- vi.spyOn(fs, "writeFileSync");
1148
-
1149
- let _callbacks: Function[] = [];
1150
-
1151
- const server = {
1152
- watcher: {
1153
- init: () => {
1154
- _callbacks = [];
1155
- },
1156
- on: (_event: string, callback: Function) => {
1157
- _callbacks.push(callback);
1158
- },
1159
- trigger: async (file: string) => {
1160
- for (const callback of _callbacks) {
1161
- await callback(file);
1162
- }
1163
- },
1164
- },
1165
- };
1166
- server.watcher.init();
1167
-
1168
- const plugin = ApplicationManifestPlugin();
1169
- plugin.configResolved({
1170
- command: "serve",
1171
- server: {},
1172
- build: { outDir: "/dist" },
1173
- });
1174
- await plugin.buildStart();
1175
- plugin.configureServer(server);
1176
- await server.watcher.trigger("package.json");
1177
- await server.watcher.trigger("my-component.tsx");
1178
-
1179
- expect(fs.writeFileSync).toBeCalledTimes(6);
1180
- });
1181
- });
1182
-
1183
- type FilePath = string;
1184
-
1185
- function mockReadFile(mocks: Record<FilePath, string | (() => string)>) {
1186
- vi.spyOn(fs, "readFileSync").mockImplementation((path) => {
1187
- const mock = mocks[path.toString()];
1188
-
1189
- if (!mock) {
1190
- throw new Error(`No matched mock for path '${path}'`);
1191
- }
1192
-
1193
- if (typeof mock === "function") {
1194
- return mock();
1195
- }
1196
-
1197
- return mock;
1198
- });
1199
- }