@agent-native/core 0.117.2 → 0.118.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 (776) hide show
  1. package/corpus/README.md +3 -3
  2. package/corpus/core/CHANGELOG.md +51 -0
  3. package/corpus/core/docs/content/custom-design-system.mdx +445 -0
  4. package/corpus/core/docs/content/toolkit-ui.mdx +16 -0
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/a2a/client.ts +32 -10
  7. package/corpus/core/src/a2a/types.ts +1 -0
  8. package/corpus/core/src/agent/types.ts +1 -1
  9. package/corpus/core/src/cli/index.ts +18 -10
  10. package/corpus/core/src/cli/multi-frontier-runs.ts +5 -3
  11. package/corpus/core/src/cli/templates-meta.ts +0 -12
  12. package/corpus/core/src/cli/workspace-dev.ts +1 -1
  13. package/corpus/core/src/client/AgentPanel.tsx +99 -108
  14. package/corpus/core/src/client/AssistantChat.tsx +30 -13
  15. package/corpus/core/src/client/CommandMenu.tsx +68 -178
  16. package/corpus/core/src/client/RunStuckBanner.tsx +39 -47
  17. package/corpus/core/src/client/agent-chat-adapter.ts +3 -1
  18. package/corpus/core/src/client/app-providers.tsx +1 -1
  19. package/corpus/core/src/client/chat/action-chat-ui-surface.tsx +32 -0
  20. package/corpus/core/src/client/chat/message-components.tsx +169 -18
  21. package/corpus/core/src/client/chat/tool-call-display.tsx +50 -14
  22. package/corpus/core/src/client/chat/widgets/InlineExtensionWidget.tsx +13 -40
  23. package/corpus/core/src/client/chat/widgets/builtin-tool-renderers.tsx +7 -3
  24. package/corpus/core/src/client/components/ui/message-scroller.tsx +15 -1
  25. package/corpus/core/src/client/conversation/AgentConversation.tsx +12 -1
  26. package/corpus/core/src/client/error-capture.ts +2 -6
  27. package/corpus/core/src/client/i18n.tsx +22 -0
  28. package/corpus/core/src/client/index.ts +17 -0
  29. package/corpus/core/src/client/org/TeamPage.tsx +257 -153
  30. package/corpus/core/src/client/progress/RunsTray.tsx +89 -88
  31. package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +25 -16
  32. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +34 -13
  33. package/corpus/core/src/client/resources/ResourcesPanel.tsx +5 -1
  34. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +20 -17
  35. package/corpus/core/src/client/resources/mcp-integration-logos.ts +2 -2
  36. package/corpus/core/src/client/route-chunk-recovery.ts +5 -3
  37. package/corpus/core/src/client/session-replay.ts +3 -3
  38. package/corpus/core/src/client/settings/DemoModeSection.tsx +6 -18
  39. package/corpus/core/src/client/settings/SecretsSection.tsx +97 -52
  40. package/corpus/core/src/client/settings/SettingsPanel.tsx +217 -252
  41. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +23 -2
  42. package/corpus/core/src/client/settings/VoiceTranscriptionSection.tsx +7 -18
  43. package/corpus/core/src/client/settings/index.ts +7 -0
  44. package/corpus/core/src/client/settings/useSettingsPanelController.ts +155 -0
  45. package/corpus/core/src/client/setup-connections/BuilderConnectCard.tsx +116 -51
  46. package/corpus/core/src/client/setup-connections/index.ts +10 -0
  47. package/corpus/core/src/client/setup-connections/useBuilderConnectCardController.ts +82 -0
  48. package/corpus/core/src/client/sharing/ShareButton.tsx +64 -586
  49. package/corpus/core/src/client/sharing/ShareDialog.tsx +299 -633
  50. package/corpus/core/src/client/sharing/index.ts +42 -0
  51. package/corpus/core/src/client/sharing/share-controller-helpers.ts +318 -0
  52. package/corpus/core/src/client/sharing/useShareButtonController.ts +600 -0
  53. package/corpus/core/src/client/sharing/useShareDialogController.ts +559 -0
  54. package/corpus/core/src/client/sse-event-processor.ts +23 -0
  55. package/corpus/core/src/client/tool-display.ts +71 -0
  56. package/corpus/core/src/client/transcription/use-live-transcription.ts +64 -45
  57. package/corpus/core/src/client/use-agent-engine-configured.ts +12 -19
  58. package/corpus/core/src/client/use-chat-threads.ts +33 -12
  59. package/corpus/core/src/deploy/build.ts +2 -1
  60. package/corpus/core/src/guards/db-tool-scoping.ts +1 -1
  61. package/corpus/core/src/integrations/adapters/slack.ts +84 -5
  62. package/corpus/core/src/integrations/index.ts +5 -1
  63. package/corpus/core/src/localization/default-messages.ts +6 -1
  64. package/corpus/core/src/mcp-client/oauth-routes.ts +61 -14
  65. package/corpus/core/src/scripts/call-agent.ts +5 -1
  66. package/corpus/core/src/server/realtime-voice.ts +5 -2
  67. package/corpus/core/src/styles/agent-native.css +0 -24
  68. package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  69. package/corpus/core/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  70. package/corpus/core/src/templates/default/.agents/skills/frontend-design/SKILL.md +22 -2
  71. package/corpus/core/src/templates/default/.agents/skills/shadcn-ui/SKILL.md +28 -4
  72. package/corpus/core/src/templates/default/app/components/ui/toolkit-provider.tsx +10 -0
  73. package/corpus/core/src/templates/default/app/design-system.ts +3 -0
  74. package/corpus/core/src/templates/default/app/root.tsx +5 -2
  75. package/corpus/core/src/templates/default/package.json +1 -0
  76. package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  77. package/corpus/core/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  78. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  79. package/corpus/core/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  80. package/corpus/core/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +22 -2
  81. package/corpus/core/src/templates/workspace-core/.agents/skills/shadcn-ui/SKILL.md +28 -4
  82. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +7 -5
  83. package/corpus/core/src/terminal/cli-registry.ts +1 -1
  84. package/corpus/core/src/vite/client.ts +205 -1
  85. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  86. package/corpus/templates/analytics/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  87. package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +22 -2
  88. package/corpus/templates/analytics/.agents/skills/shadcn-ui/SKILL.md +28 -4
  89. package/corpus/templates/analytics/app/components/ui/toolkit-provider.tsx +6 -1
  90. package/corpus/templates/analytics/app/design-system.ts +3 -0
  91. package/corpus/templates/analytics/app/hooks/use-dashboard-views.ts +13 -1
  92. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/ViewsMenu.tsx +10 -0
  93. package/corpus/templates/analytics/changelog/2026-07-22-show-a-useful-error-when-saving-a-dashboard-view-fails.md +6 -0
  94. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  95. package/corpus/templates/assets/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  96. package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +22 -2
  97. package/corpus/templates/assets/.agents/skills/shadcn-ui/SKILL.md +28 -4
  98. package/corpus/templates/assets/app/components/ui/alert.tsx +1 -0
  99. package/corpus/templates/assets/app/components/ui/toolkit-provider.tsx +6 -1
  100. package/corpus/templates/assets/app/design-system.ts +3 -0
  101. package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +26 -30
  102. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  103. package/corpus/templates/brain/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  104. package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +22 -2
  105. package/corpus/templates/brain/.agents/skills/shadcn-ui/SKILL.md +28 -4
  106. package/corpus/templates/brain/app/components/ui/dialog.tsx +1 -0
  107. package/corpus/templates/brain/app/components/ui/toolkit-provider.tsx +6 -1
  108. package/corpus/templates/brain/app/design-system.ts +3 -0
  109. package/corpus/templates/brain/app/routes/sources.tsx +189 -122
  110. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  111. package/corpus/templates/calendar/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  112. package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +22 -2
  113. package/corpus/templates/calendar/.agents/skills/shadcn-ui/SKILL.md +28 -4
  114. package/corpus/templates/calendar/app/components/ui/toolkit-provider.tsx +6 -1
  115. package/corpus/templates/calendar/app/design-system.ts +3 -0
  116. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  117. package/corpus/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  118. package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +22 -2
  119. package/corpus/templates/chat/.agents/skills/shadcn-ui/SKILL.md +28 -4
  120. package/corpus/templates/chat/app/components/ui/toolkit-provider.tsx +6 -1
  121. package/corpus/templates/chat/app/design-system.ts +3 -0
  122. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  123. package/corpus/templates/clips/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  124. package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +22 -2
  125. package/corpus/templates/clips/.agents/skills/shadcn-ui/SKILL.md +28 -4
  126. package/corpus/templates/clips/AGENTS.md +8 -6
  127. package/corpus/templates/clips/actions/request-transcript.ts +90 -420
  128. package/corpus/templates/clips/actions/save-browser-transcript.ts +11 -28
  129. package/corpus/templates/clips/app/components/capture-install-options.tsx +5 -3
  130. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +3 -136
  131. package/corpus/templates/clips/app/components/ui/toolkit-provider.tsx +6 -1
  132. package/corpus/templates/clips/app/design-system.ts +3 -0
  133. package/corpus/templates/clips/app/lib/capture-install-options.ts +15 -4
  134. package/corpus/templates/clips/app/routes/_app.library._index.tsx +1 -1
  135. package/corpus/templates/clips/app/routes/download.tsx +3 -2
  136. package/corpus/templates/clips/changelog/2026-07-22-fixed-an-intermittent-hydration-error-on-the-download-page.md +6 -0
  137. package/corpus/templates/clips/changelog/2026-07-22-fixed-transcript-generation-when-native-speech-capture-retur.md +6 -0
  138. package/corpus/templates/clips/changelog/2026-07-22-fixed-windows-recordings-aborting-during-the-countdown.md +6 -0
  139. package/corpus/templates/clips/changelog/2026-07-22-permissions-and-rewind-controls-are-now-grouped-with-clearer.md +6 -0
  140. package/corpus/templates/clips/changelog/2026-07-22-the-desktop-popover-opens-centered-under-the-menu-bar-icon-o.md +6 -0
  141. package/corpus/templates/clips/changelog/2026-07-22-transcript-generation-now-retries-with-backup-speech-recogni.md +6 -0
  142. package/corpus/templates/clips/desktop/src/app.tsx +86 -82
  143. package/corpus/templates/clips/desktop/src/styles.css +13 -0
  144. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +10 -1
  145. package/corpus/templates/clips/desktop/src-tauri/src/shortcuts.rs +37 -2
  146. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +18 -0
  147. package/corpus/templates/clips/server/lib/public-agent-context.ts +2 -2
  148. package/corpus/templates/clips/server/register-secrets.ts +7 -6
  149. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  150. package/corpus/templates/content/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  151. package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +22 -2
  152. package/corpus/templates/content/.agents/skills/shadcn-ui/SKILL.md +28 -4
  153. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +41 -59
  154. package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +16 -84
  155. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +13 -7
  156. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +41 -41
  157. package/corpus/templates/content/app/components/editor/database/GalleryView.tsx +2 -1
  158. package/corpus/templates/content/app/components/editor/database/ListView.tsx +2 -1
  159. package/corpus/templates/content/app/components/editor/database/TimelineView.tsx +9 -9
  160. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +7 -7
  161. package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +11 -11
  162. package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +2 -2
  163. package/corpus/templates/content/app/components/ui/checkbox.tsx +1 -0
  164. package/corpus/templates/content/app/components/ui/collapsible.tsx +1 -0
  165. package/corpus/templates/content/app/components/ui/toolkit-provider.tsx +6 -1
  166. package/corpus/templates/content/app/design-system.ts +3 -0
  167. package/corpus/templates/content/app/global.css +29 -3
  168. package/corpus/templates/content/app/i18n-data.ts +10 -0
  169. package/corpus/templates/content/changelog/2026-07-22-page-actions-are-grouped-into-the-three-dots-menu-for-a-clea.md +6 -0
  170. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  171. package/corpus/templates/design/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  172. package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +22 -2
  173. package/corpus/templates/design/.agents/skills/shadcn-ui/SKILL.md +28 -4
  174. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +8 -8
  175. package/corpus/templates/design/app/components/ui/command.tsx +1 -0
  176. package/corpus/templates/design/app/components/ui/toolkit-provider.tsx +6 -1
  177. package/corpus/templates/design/app/design-system.ts +3 -0
  178. package/corpus/templates/design/server/lib/fig-file-decoder.ts +1 -0
  179. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  180. package/corpus/templates/dispatch/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  181. package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +22 -2
  182. package/corpus/templates/dispatch/.agents/skills/shadcn-ui/SKILL.md +28 -4
  183. package/corpus/templates/dispatch/app/components/ui/button.tsx +1 -0
  184. package/corpus/templates/dispatch/app/components/ui/toolkit-provider.tsx +17 -0
  185. package/corpus/templates/dispatch/app/design-system.ts +3 -0
  186. package/corpus/templates/dispatch/app/root.tsx +10 -7
  187. package/corpus/templates/dispatch/package.json +1 -0
  188. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  189. package/corpus/templates/forms/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  190. package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +22 -2
  191. package/corpus/templates/forms/.agents/skills/shadcn-ui/SKILL.md +28 -4
  192. package/corpus/templates/forms/app/components/ui/toolkit-provider.tsx +6 -1
  193. package/corpus/templates/forms/app/design-system.ts +3 -0
  194. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  195. package/corpus/templates/macros/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  196. package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +22 -2
  197. package/corpus/templates/macros/.agents/skills/shadcn-ui/SKILL.md +28 -4
  198. package/corpus/templates/macros/app/components/ui/toolkit-provider.tsx +6 -1
  199. package/corpus/templates/macros/app/design-system.ts +3 -0
  200. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  201. package/corpus/templates/mail/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  202. package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +22 -2
  203. package/corpus/templates/mail/.agents/skills/shadcn-ui/SKILL.md +28 -4
  204. package/corpus/templates/mail/app/components/email/EmailThread.tsx +134 -93
  205. package/corpus/templates/mail/app/components/email/email-iframe-document.ts +8 -2
  206. package/corpus/templates/mail/app/components/ui/textarea.tsx +1 -21
  207. package/corpus/templates/mail/app/components/ui/toolkit-provider.tsx +6 -1
  208. package/corpus/templates/mail/app/design-system.ts +3 -0
  209. package/corpus/templates/mail/changelog/2026-07-22-email-messages-no-longer-flash-with-an-unstyled-page-while-l.md +6 -0
  210. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  211. package/corpus/templates/plan/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  212. package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +22 -2
  213. package/corpus/templates/plan/.agents/skills/shadcn-ui/SKILL.md +28 -4
  214. package/corpus/templates/plan/app/components/plan/PlanContentRenderer.tsx +1 -1
  215. package/corpus/templates/plan/app/components/ui/toolkit-provider.tsx +6 -1
  216. package/corpus/templates/plan/app/design-system.ts +3 -0
  217. package/corpus/templates/plan/app/entry.client.tsx +3 -0
  218. package/corpus/templates/plan/changelog/2026-07-22-recover-stale-pages-after-a-deployment-refresh-automatically.md +6 -0
  219. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  220. package/corpus/templates/slides/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  221. package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +22 -2
  222. package/corpus/templates/slides/.agents/skills/shadcn-ui/SKILL.md +28 -4
  223. package/corpus/templates/slides/app/components/ui/toolkit-provider.tsx +6 -1
  224. package/corpus/templates/slides/app/design-system.ts +3 -0
  225. package/corpus/templates/slides/app/hooks/use-agent-generating.ts +10 -3
  226. package/corpus/templates/slides/app/pages/Index.tsx +1 -0
  227. package/corpus/templates/slides/changelog/2026-07-22-new-deck-prompts-now-open-in-their-own-visible-chat-thread.md +6 -0
  228. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  229. package/corpus/templates/tasks/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  230. package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +22 -2
  231. package/corpus/templates/tasks/.agents/skills/shadcn-ui/SKILL.md +28 -4
  232. package/corpus/templates/tasks/app/components/ui/toolkit-provider.tsx +17 -0
  233. package/corpus/templates/tasks/app/design-system.ts +3 -0
  234. package/corpus/templates/tasks/app/root.tsx +5 -2
  235. package/corpus/toolkit/CHANGELOG.md +23 -0
  236. package/corpus/toolkit/agent-native.eject.json +71 -0
  237. package/corpus/toolkit/package.json +31 -1
  238. package/corpus/toolkit/src/chat-history/ChatHistoryRail.tsx +100 -39
  239. package/corpus/toolkit/src/chat-history/index.ts +9 -0
  240. package/corpus/toolkit/src/chat-history/useChatHistoryRailController.ts +76 -0
  241. package/corpus/toolkit/src/chat-history.css +2 -0
  242. package/corpus/toolkit/src/composer/ComposerPlusMenu.tsx +11 -8
  243. package/corpus/toolkit/src/composer/PromptComposer.tsx +32 -7
  244. package/corpus/toolkit/src/composer/RealtimeVoiceMode.tsx +119 -31
  245. package/corpus/toolkit/src/composer/useRealtimeVoiceMode.tsx +124 -9
  246. package/corpus/toolkit/src/conformance/__fixtures__/css-in-js-adapter.tsx +401 -0
  247. package/corpus/toolkit/src/conformance/index.ts +3 -0
  248. package/corpus/toolkit/src/conformance/runner.tsx +862 -0
  249. package/corpus/toolkit/src/conformance/types.ts +45 -0
  250. package/corpus/toolkit/src/conformance/version.ts +22 -0
  251. package/corpus/toolkit/src/design-system/components.tsx +146 -0
  252. package/corpus/toolkit/src/design-system/context.tsx +31 -0
  253. package/corpus/toolkit/src/design-system/default-adapter.tsx +915 -0
  254. package/corpus/toolkit/src/design-system/definition.ts +14 -0
  255. package/corpus/toolkit/src/design-system/error-boundary.tsx +37 -0
  256. package/corpus/toolkit/src/design-system/index.ts +7 -0
  257. package/corpus/toolkit/src/design-system/theme.ts +145 -0
  258. package/corpus/toolkit/src/design-system/types.ts +363 -0
  259. package/corpus/toolkit/src/editor/SharedRichEditor.tsx +13 -2
  260. package/corpus/toolkit/src/editor/SlashCommandMenu.tsx +20 -0
  261. package/corpus/toolkit/src/editor/index.ts +2 -0
  262. package/corpus/toolkit/src/provider.tsx +98 -5
  263. package/corpus/toolkit/src/styles.css +52 -23
  264. package/corpus/toolkit/src/ui/button.tsx +95 -6
  265. package/corpus/toolkit/src/ui/dialog.tsx +48 -23
  266. package/corpus/toolkit/src/ui/popover.tsx +16 -2
  267. package/corpus/toolkit/src/ui/select.tsx +7 -3
  268. package/corpus/toolkit/src/ui/sidebar.tsx +47 -48
  269. package/corpus/toolkit/src/ui/tooltip.tsx +7 -3
  270. package/dist/a2a/client.d.ts +3 -1
  271. package/dist/a2a/client.d.ts.map +1 -1
  272. package/dist/a2a/client.js +17 -12
  273. package/dist/a2a/client.js.map +1 -1
  274. package/dist/a2a/types.d.ts +1 -1
  275. package/dist/a2a/types.d.ts.map +1 -1
  276. package/dist/a2a/types.js.map +1 -1
  277. package/dist/agent/types.d.ts +1 -1
  278. package/dist/agent/types.d.ts.map +1 -1
  279. package/dist/agent/types.js.map +1 -1
  280. package/dist/cli/index.js +18 -8
  281. package/dist/cli/index.js.map +1 -1
  282. package/dist/cli/multi-frontier-runs.js +3 -3
  283. package/dist/cli/multi-frontier-runs.js.map +1 -1
  284. package/dist/cli/templates-meta.d.ts.map +1 -1
  285. package/dist/cli/templates-meta.js +0 -12
  286. package/dist/cli/templates-meta.js.map +1 -1
  287. package/dist/cli/workspace-dev.js +1 -1
  288. package/dist/cli/workspace-dev.js.map +1 -1
  289. package/dist/client/AgentPanel.d.ts.map +1 -1
  290. package/dist/client/AgentPanel.js +18 -15
  291. package/dist/client/AgentPanel.js.map +1 -1
  292. package/dist/client/AssistantChat.d.ts.map +1 -1
  293. package/dist/client/AssistantChat.js +26 -15
  294. package/dist/client/AssistantChat.js.map +1 -1
  295. package/dist/client/CommandMenu.d.ts.map +1 -1
  296. package/dist/client/CommandMenu.js +18 -106
  297. package/dist/client/CommandMenu.js.map +1 -1
  298. package/dist/client/RunStuckBanner.d.ts +3 -5
  299. package/dist/client/RunStuckBanner.d.ts.map +1 -1
  300. package/dist/client/RunStuckBanner.js +17 -18
  301. package/dist/client/RunStuckBanner.js.map +1 -1
  302. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  303. package/dist/client/agent-chat-adapter.js +2 -1
  304. package/dist/client/agent-chat-adapter.js.map +1 -1
  305. package/dist/client/app-providers.d.ts.map +1 -1
  306. package/dist/client/app-providers.js +1 -1
  307. package/dist/client/app-providers.js.map +1 -1
  308. package/dist/client/chat/action-chat-ui-surface.d.ts +8 -0
  309. package/dist/client/chat/action-chat-ui-surface.d.ts.map +1 -0
  310. package/dist/client/chat/action-chat-ui-surface.js +10 -0
  311. package/dist/client/chat/action-chat-ui-surface.js.map +1 -0
  312. package/dist/client/chat/message-components.d.ts +12 -1
  313. package/dist/client/chat/message-components.d.ts.map +1 -1
  314. package/dist/client/chat/message-components.js +102 -14
  315. package/dist/client/chat/message-components.js.map +1 -1
  316. package/dist/client/chat/tool-call-display.d.ts +3 -1
  317. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  318. package/dist/client/chat/tool-call-display.js +33 -14
  319. package/dist/client/chat/tool-call-display.js.map +1 -1
  320. package/dist/client/chat/widgets/InlineExtensionWidget.d.ts.map +1 -1
  321. package/dist/client/chat/widgets/InlineExtensionWidget.js +9 -12
  322. package/dist/client/chat/widgets/InlineExtensionWidget.js.map +1 -1
  323. package/dist/client/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
  324. package/dist/client/chat/widgets/builtin-tool-renderers.js +5 -3
  325. package/dist/client/chat/widgets/builtin-tool-renderers.js.map +1 -1
  326. package/dist/client/components/ui/message-scroller.d.ts +1 -1
  327. package/dist/client/components/ui/message-scroller.d.ts.map +1 -1
  328. package/dist/client/components/ui/message-scroller.js +4 -3
  329. package/dist/client/components/ui/message-scroller.js.map +1 -1
  330. package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
  331. package/dist/client/conversation/AgentConversation.js +3 -2
  332. package/dist/client/conversation/AgentConversation.js.map +1 -1
  333. package/dist/client/error-capture.d.ts.map +1 -1
  334. package/dist/client/error-capture.js +2 -2
  335. package/dist/client/error-capture.js.map +1 -1
  336. package/dist/client/i18n.d.ts.map +1 -1
  337. package/dist/client/i18n.js +9 -0
  338. package/dist/client/i18n.js.map +1 -1
  339. package/dist/client/index.d.ts +2 -2
  340. package/dist/client/index.d.ts.map +1 -1
  341. package/dist/client/index.js +2 -2
  342. package/dist/client/index.js.map +1 -1
  343. package/dist/client/org/TeamPage.d.ts.map +1 -1
  344. package/dist/client/org/TeamPage.js +41 -33
  345. package/dist/client/org/TeamPage.js.map +1 -1
  346. package/dist/client/progress/RunsTray.d.ts.map +1 -1
  347. package/dist/client/progress/RunsTray.js +9 -10
  348. package/dist/client/progress/RunsTray.js.map +1 -1
  349. package/dist/client/resources/McpConnectionSuggestion.d.ts +1 -0
  350. package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
  351. package/dist/client/resources/McpConnectionSuggestion.js +14 -12
  352. package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
  353. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  354. package/dist/client/resources/McpIntegrationDialog.js +10 -8
  355. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  356. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  357. package/dist/client/resources/ResourcesPanel.js +3 -1
  358. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  359. package/dist/client/resources/mcp-integration-catalog.d.ts +2 -0
  360. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  361. package/dist/client/resources/mcp-integration-catalog.js +17 -17
  362. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  363. package/dist/client/resources/mcp-integration-logos.js +2 -2
  364. package/dist/client/resources/mcp-integration-logos.js.map +1 -1
  365. package/dist/client/route-chunk-recovery.d.ts.map +1 -1
  366. package/dist/client/route-chunk-recovery.js +5 -3
  367. package/dist/client/route-chunk-recovery.js.map +1 -1
  368. package/dist/client/session-replay.js +3 -3
  369. package/dist/client/session-replay.js.map +1 -1
  370. package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
  371. package/dist/client/settings/DemoModeSection.js +2 -5
  372. package/dist/client/settings/DemoModeSection.js.map +1 -1
  373. package/dist/client/settings/SecretsSection.d.ts.map +1 -1
  374. package/dist/client/settings/SecretsSection.js +18 -6
  375. package/dist/client/settings/SecretsSection.js.map +1 -1
  376. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  377. package/dist/client/settings/SettingsPanel.js +53 -118
  378. package/dist/client/settings/SettingsPanel.js.map +1 -1
  379. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  380. package/dist/client/settings/SettingsTabsPage.js +16 -1
  381. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  382. package/dist/client/settings/VoiceTranscriptionSection.d.ts.map +1 -1
  383. package/dist/client/settings/VoiceTranscriptionSection.js +2 -5
  384. package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
  385. package/dist/client/settings/index.d.ts +1 -0
  386. package/dist/client/settings/index.d.ts.map +1 -1
  387. package/dist/client/settings/index.js +1 -0
  388. package/dist/client/settings/index.js.map +1 -1
  389. package/dist/client/settings/useSettingsPanelController.d.ts +22 -0
  390. package/dist/client/settings/useSettingsPanelController.d.ts.map +1 -0
  391. package/dist/client/settings/useSettingsPanelController.js +103 -0
  392. package/dist/client/settings/useSettingsPanelController.js.map +1 -0
  393. package/dist/client/setup-connections/BuilderConnectCard.d.ts +14 -6
  394. package/dist/client/setup-connections/BuilderConnectCard.d.ts.map +1 -1
  395. package/dist/client/setup-connections/BuilderConnectCard.js +24 -16
  396. package/dist/client/setup-connections/BuilderConnectCard.js.map +1 -1
  397. package/dist/client/setup-connections/index.d.ts +2 -1
  398. package/dist/client/setup-connections/index.d.ts.map +1 -1
  399. package/dist/client/setup-connections/index.js +2 -1
  400. package/dist/client/setup-connections/index.js.map +1 -1
  401. package/dist/client/setup-connections/useBuilderConnectCardController.d.ts +34 -0
  402. package/dist/client/setup-connections/useBuilderConnectCardController.d.ts.map +1 -0
  403. package/dist/client/setup-connections/useBuilderConnectCardController.js +39 -0
  404. package/dist/client/setup-connections/useBuilderConnectCardController.js.map +1 -0
  405. package/dist/client/sharing/ShareButton.d.ts +2 -1
  406. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  407. package/dist/client/sharing/ShareButton.js +17 -463
  408. package/dist/client/sharing/ShareButton.js.map +1 -1
  409. package/dist/client/sharing/ShareDialog.d.ts +6 -6
  410. package/dist/client/sharing/ShareDialog.d.ts.map +1 -1
  411. package/dist/client/sharing/ShareDialog.js +69 -283
  412. package/dist/client/sharing/ShareDialog.js.map +1 -1
  413. package/dist/client/sharing/index.d.ts +3 -0
  414. package/dist/client/sharing/index.d.ts.map +1 -1
  415. package/dist/client/sharing/index.js +3 -0
  416. package/dist/client/sharing/index.js.map +1 -1
  417. package/dist/client/sharing/share-controller-helpers.d.ts +70 -0
  418. package/dist/client/sharing/share-controller-helpers.d.ts.map +1 -0
  419. package/dist/client/sharing/share-controller-helpers.js +224 -0
  420. package/dist/client/sharing/share-controller-helpers.js.map +1 -0
  421. package/dist/client/sharing/useShareButtonController.d.ts +91 -0
  422. package/dist/client/sharing/useShareButtonController.d.ts.map +1 -0
  423. package/dist/client/sharing/useShareButtonController.js +397 -0
  424. package/dist/client/sharing/useShareButtonController.js.map +1 -0
  425. package/dist/client/sharing/useShareDialogController.d.ts +109 -0
  426. package/dist/client/sharing/useShareDialogController.d.ts.map +1 -0
  427. package/dist/client/sharing/useShareDialogController.js +348 -0
  428. package/dist/client/sharing/useShareDialogController.js.map +1 -0
  429. package/dist/client/sse-event-processor.d.ts.map +1 -1
  430. package/dist/client/sse-event-processor.js +21 -0
  431. package/dist/client/sse-event-processor.js.map +1 -1
  432. package/dist/client/tool-display.d.ts +16 -0
  433. package/dist/client/tool-display.d.ts.map +1 -1
  434. package/dist/client/tool-display.js +52 -0
  435. package/dist/client/tool-display.js.map +1 -1
  436. package/dist/client/transcription/use-live-transcription.d.ts +3 -3
  437. package/dist/client/transcription/use-live-transcription.d.ts.map +1 -1
  438. package/dist/client/transcription/use-live-transcription.js +22 -11
  439. package/dist/client/transcription/use-live-transcription.js.map +1 -1
  440. package/dist/client/use-agent-engine-configured.d.ts +3 -2
  441. package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
  442. package/dist/client/use-agent-engine-configured.js +7 -19
  443. package/dist/client/use-agent-engine-configured.js.map +1 -1
  444. package/dist/client/use-chat-threads.d.ts.map +1 -1
  445. package/dist/client/use-chat-threads.js +21 -8
  446. package/dist/client/use-chat-threads.js.map +1 -1
  447. package/dist/collab/routes.d.ts +1 -1
  448. package/dist/collab/struct-routes.d.ts +1 -1
  449. package/dist/deploy/build.d.ts.map +1 -1
  450. package/dist/deploy/build.js +1 -1
  451. package/dist/deploy/build.js.map +1 -1
  452. package/dist/guards/db-tool-scoping.js +1 -1
  453. package/dist/guards/db-tool-scoping.js.map +1 -1
  454. package/dist/integrations/adapters/slack.d.ts +1 -0
  455. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  456. package/dist/integrations/adapters/slack.js +61 -5
  457. package/dist/integrations/adapters/slack.js.map +1 -1
  458. package/dist/integrations/index.d.ts +1 -1
  459. package/dist/integrations/index.d.ts.map +1 -1
  460. package/dist/integrations/index.js +1 -1
  461. package/dist/integrations/index.js.map +1 -1
  462. package/dist/localization/default-messages.d.ts +4 -0
  463. package/dist/localization/default-messages.d.ts.map +1 -1
  464. package/dist/localization/default-messages.js +5 -1
  465. package/dist/localization/default-messages.js.map +1 -1
  466. package/dist/mcp-client/oauth-routes.d.ts +5 -0
  467. package/dist/mcp-client/oauth-routes.d.ts.map +1 -1
  468. package/dist/mcp-client/oauth-routes.js +53 -14
  469. package/dist/mcp-client/oauth-routes.js.map +1 -1
  470. package/dist/notifications/routes.d.ts +2 -2
  471. package/dist/observability/routes.d.ts +1 -1
  472. package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
  473. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  474. package/dist/scripts/call-agent.d.ts.map +1 -1
  475. package/dist/scripts/call-agent.js +5 -1
  476. package/dist/scripts/call-agent.js.map +1 -1
  477. package/dist/secrets/routes.d.ts +6 -6
  478. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  479. package/dist/server/realtime-voice.d.ts.map +1 -1
  480. package/dist/server/realtime-voice.js +2 -2
  481. package/dist/server/realtime-voice.js.map +1 -1
  482. package/dist/styles/agent-native.css +0 -24
  483. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  484. package/dist/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  485. package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +22 -2
  486. package/dist/templates/chat/.agents/skills/shadcn-ui/SKILL.md +28 -4
  487. package/dist/templates/chat/app/components/ui/toolkit-provider.tsx +6 -1
  488. package/dist/templates/chat/app/design-system.ts +3 -0
  489. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  490. package/dist/templates/default/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  491. package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +22 -2
  492. package/dist/templates/default/.agents/skills/shadcn-ui/SKILL.md +28 -4
  493. package/dist/templates/default/app/components/ui/toolkit-provider.tsx +10 -0
  494. package/dist/templates/default/app/design-system.ts +3 -0
  495. package/dist/templates/default/app/root.tsx +5 -2
  496. package/dist/templates/default/package.json +1 -0
  497. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  498. package/dist/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  499. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  500. package/dist/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  501. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +22 -2
  502. package/dist/templates/workspace-core/.agents/skills/shadcn-ui/SKILL.md +28 -4
  503. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +7 -5
  504. package/dist/terminal/cli-registry.js +1 -1
  505. package/dist/terminal/cli-registry.js.map +1 -1
  506. package/dist/vite/client.d.ts +11 -1
  507. package/dist/vite/client.d.ts.map +1 -1
  508. package/dist/vite/client.js +144 -2
  509. package/dist/vite/client.js.map +1 -1
  510. package/docs/content/custom-design-system.mdx +445 -0
  511. package/docs/content/toolkit-ui.mdx +16 -0
  512. package/package.json +2 -2
  513. package/src/a2a/client.ts +32 -10
  514. package/src/a2a/types.ts +1 -0
  515. package/src/agent/types.ts +1 -1
  516. package/src/cli/index.ts +18 -10
  517. package/src/cli/multi-frontier-runs.ts +5 -3
  518. package/src/cli/templates-meta.ts +0 -12
  519. package/src/cli/workspace-dev.ts +1 -1
  520. package/src/client/AgentPanel.tsx +99 -108
  521. package/src/client/AssistantChat.tsx +30 -13
  522. package/src/client/CommandMenu.tsx +68 -178
  523. package/src/client/RunStuckBanner.tsx +39 -47
  524. package/src/client/agent-chat-adapter.ts +3 -1
  525. package/src/client/app-providers.tsx +1 -1
  526. package/src/client/chat/action-chat-ui-surface.tsx +32 -0
  527. package/src/client/chat/message-components.tsx +169 -18
  528. package/src/client/chat/tool-call-display.tsx +50 -14
  529. package/src/client/chat/widgets/InlineExtensionWidget.tsx +13 -40
  530. package/src/client/chat/widgets/builtin-tool-renderers.tsx +7 -3
  531. package/src/client/components/ui/message-scroller.tsx +15 -1
  532. package/src/client/conversation/AgentConversation.tsx +12 -1
  533. package/src/client/error-capture.ts +2 -6
  534. package/src/client/i18n.tsx +22 -0
  535. package/src/client/index.ts +17 -0
  536. package/src/client/org/TeamPage.tsx +257 -153
  537. package/src/client/progress/RunsTray.tsx +89 -88
  538. package/src/client/resources/McpConnectionSuggestion.tsx +25 -16
  539. package/src/client/resources/McpIntegrationDialog.tsx +34 -13
  540. package/src/client/resources/ResourcesPanel.tsx +5 -1
  541. package/src/client/resources/mcp-integration-catalog.ts +20 -17
  542. package/src/client/resources/mcp-integration-logos.ts +2 -2
  543. package/src/client/route-chunk-recovery.ts +5 -3
  544. package/src/client/session-replay.ts +3 -3
  545. package/src/client/settings/DemoModeSection.tsx +6 -18
  546. package/src/client/settings/SecretsSection.tsx +97 -52
  547. package/src/client/settings/SettingsPanel.tsx +217 -252
  548. package/src/client/settings/SettingsTabsPage.tsx +23 -2
  549. package/src/client/settings/VoiceTranscriptionSection.tsx +7 -18
  550. package/src/client/settings/index.ts +7 -0
  551. package/src/client/settings/useSettingsPanelController.ts +155 -0
  552. package/src/client/setup-connections/BuilderConnectCard.tsx +116 -51
  553. package/src/client/setup-connections/index.ts +10 -0
  554. package/src/client/setup-connections/useBuilderConnectCardController.ts +82 -0
  555. package/src/client/sharing/ShareButton.tsx +64 -586
  556. package/src/client/sharing/ShareDialog.tsx +299 -633
  557. package/src/client/sharing/index.ts +42 -0
  558. package/src/client/sharing/share-controller-helpers.ts +318 -0
  559. package/src/client/sharing/useShareButtonController.ts +600 -0
  560. package/src/client/sharing/useShareDialogController.ts +559 -0
  561. package/src/client/sse-event-processor.ts +23 -0
  562. package/src/client/tool-display.ts +71 -0
  563. package/src/client/transcription/use-live-transcription.ts +64 -45
  564. package/src/client/use-agent-engine-configured.ts +12 -19
  565. package/src/client/use-chat-threads.ts +33 -12
  566. package/src/deploy/build.ts +2 -1
  567. package/src/guards/db-tool-scoping.ts +1 -1
  568. package/src/integrations/adapters/slack.ts +84 -5
  569. package/src/integrations/index.ts +5 -1
  570. package/src/localization/default-messages.ts +6 -1
  571. package/src/mcp-client/oauth-routes.ts +61 -14
  572. package/src/scripts/call-agent.ts +5 -1
  573. package/src/server/realtime-voice.ts +5 -2
  574. package/src/styles/agent-native.css +0 -24
  575. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  576. package/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  577. package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +22 -2
  578. package/src/templates/chat/.agents/skills/shadcn-ui/SKILL.md +28 -4
  579. package/src/templates/chat/app/components/ui/toolkit-provider.tsx +6 -1
  580. package/src/templates/chat/app/design-system.ts +3 -0
  581. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  582. package/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  583. package/src/templates/default/.agents/skills/frontend-design/SKILL.md +22 -2
  584. package/src/templates/default/.agents/skills/shadcn-ui/SKILL.md +28 -4
  585. package/src/templates/default/app/components/ui/toolkit-provider.tsx +10 -0
  586. package/src/templates/default/app/design-system.ts +3 -0
  587. package/src/templates/default/app/root.tsx +5 -2
  588. package/src/templates/default/package.json +1 -0
  589. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  590. package/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  591. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +37 -2
  592. package/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +86 -11
  593. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +22 -2
  594. package/src/templates/workspace-core/.agents/skills/shadcn-ui/SKILL.md +28 -4
  595. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +7 -5
  596. package/src/terminal/cli-registry.ts +1 -1
  597. package/src/vite/client.ts +205 -1
  598. package/corpus/templates/analytics/app/components/ui/calendar.tsx +0 -70
  599. package/corpus/templates/analytics/app/components/ui/chart.tsx +0 -386
  600. package/corpus/templates/calendar/app/components/ui/sonner.tsx +0 -58
  601. package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +0 -115
  602. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +0 -142
  603. package/corpus/templates/crm/.agents/skills/crm/SKILL.md +0 -128
  604. package/corpus/templates/crm/.agents/skills/customizing-agent-native/SKILL.md +0 -145
  605. package/corpus/templates/crm/.agents/skills/feature-flags/SKILL.md +0 -169
  606. package/corpus/templates/crm/.agents/skills/upgrade-agent-native/SKILL.md +0 -100
  607. package/corpus/templates/crm/.env.example +0 -5
  608. package/corpus/templates/crm/AGENTS.md +0 -120
  609. package/corpus/templates/crm/CHANGELOG.md +0 -1
  610. package/corpus/templates/crm/DEVELOPING.md +0 -66
  611. package/corpus/templates/crm/README.md +0 -106
  612. package/corpus/templates/crm/_gitignore +0 -12
  613. package/corpus/templates/crm/actions/_crm-action-utils.ts +0 -87
  614. package/corpus/templates/crm/actions/_crm-dashboard.ts +0 -69
  615. package/corpus/templates/crm/actions/_crm-data-program-actions.ts +0 -15
  616. package/corpus/templates/crm/actions/_crm-signal-utils.ts +0 -79
  617. package/corpus/templates/crm/actions/apply-crm-proposals.ts +0 -203
  618. package/corpus/templates/crm/actions/attach-call-evidence.ts +0 -170
  619. package/corpus/templates/crm/actions/configure-crm-connection.ts +0 -126
  620. package/corpus/templates/crm/actions/configure-native-crm.ts +0 -44
  621. package/corpus/templates/crm/actions/create-crm-record.ts +0 -148
  622. package/corpus/templates/crm/actions/create-crm-signal-tracker.ts +0 -58
  623. package/corpus/templates/crm/actions/delete-staged-dataset.ts +0 -14
  624. package/corpus/templates/crm/actions/get-crm-automation-recipe.ts +0 -36
  625. package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +0 -35
  626. package/corpus/templates/crm/actions/get-crm-dashboard.ts +0 -14
  627. package/corpus/templates/crm/actions/get-crm-overview.ts +0 -13
  628. package/corpus/templates/crm/actions/get-crm-pipeline-data.ts +0 -61
  629. package/corpus/templates/crm/actions/get-crm-record.ts +0 -75
  630. package/corpus/templates/crm/actions/install-crm-pipeline-dashboard.ts +0 -81
  631. package/corpus/templates/crm/actions/list-crm-dashboard-revisions.ts +0 -15
  632. package/corpus/templates/crm/actions/list-crm-dashboards.ts +0 -15
  633. package/corpus/templates/crm/actions/list-crm-proposals.ts +0 -31
  634. package/corpus/templates/crm/actions/list-crm-records.ts +0 -79
  635. package/corpus/templates/crm/actions/list-crm-saved-views.ts +0 -15
  636. package/corpus/templates/crm/actions/list-crm-signal-hits.ts +0 -43
  637. package/corpus/templates/crm/actions/list-crm-signal-trackers.ts +0 -32
  638. package/corpus/templates/crm/actions/list-crm-tasks.ts +0 -22
  639. package/corpus/templates/crm/actions/list-staged-datasets.ts +0 -14
  640. package/corpus/templates/crm/actions/list-workspace-connections.ts +0 -47
  641. package/corpus/templates/crm/actions/manage-crm-signal-tracker.ts +0 -87
  642. package/corpus/templates/crm/actions/manage-crm-task.ts +0 -132
  643. package/corpus/templates/crm/actions/navigate.ts +0 -63
  644. package/corpus/templates/crm/actions/provider-api-catalog.ts +0 -22
  645. package/corpus/templates/crm/actions/provider-api-docs.ts +0 -54
  646. package/corpus/templates/crm/actions/provider-api-request.ts +0 -92
  647. package/corpus/templates/crm/actions/query-staged-dataset.ts +0 -44
  648. package/corpus/templates/crm/actions/record-crm-call-insight.ts +0 -160
  649. package/corpus/templates/crm/actions/record-crm-smart-signal.ts +0 -150
  650. package/corpus/templates/crm/actions/restore-crm-dashboard-revision.ts +0 -23
  651. package/corpus/templates/crm/actions/review-crm-signal.ts +0 -31
  652. package/corpus/templates/crm/actions/run-crm-saved-view-program.ts +0 -103
  653. package/corpus/templates/crm/actions/run-crm-signal-trackers.ts +0 -275
  654. package/corpus/templates/crm/actions/run.ts +0 -7
  655. package/corpus/templates/crm/actions/save-crm-dashboard.ts +0 -51
  656. package/corpus/templates/crm/actions/save-crm-saved-view.ts +0 -119
  657. package/corpus/templates/crm/actions/sync-crm.ts +0 -146
  658. package/corpus/templates/crm/actions/update-crm-record.ts +0 -510
  659. package/corpus/templates/crm/actions/view-screen.ts +0 -218
  660. package/corpus/templates/crm/agent-native.app-skill.json +0 -58
  661. package/corpus/templates/crm/app/components/crm/CreateCrmRecordDialog.tsx +0 -158
  662. package/corpus/templates/crm/app/components/crm/CrmDashboardPanel.tsx +0 -83
  663. package/corpus/templates/crm/app/components/crm/CrmSignalsPanel.tsx +0 -225
  664. package/corpus/templates/crm/app/components/crm/IntelligenceSettings.tsx +0 -413
  665. package/corpus/templates/crm/app/components/crm/RecordActions.tsx +0 -510
  666. package/corpus/templates/crm/app/components/crm/RecordGrid.tsx +0 -134
  667. package/corpus/templates/crm/app/components/crm/RecordWorkspace.tsx +0 -367
  668. package/corpus/templates/crm/app/components/crm/SavedViewDataProgram.tsx +0 -92
  669. package/corpus/templates/crm/app/components/crm/Surface.tsx +0 -96
  670. package/corpus/templates/crm/app/components/crm/WorkOverview.tsx +0 -180
  671. package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +0 -112
  672. package/corpus/templates/crm/app/components/layout/CrmSidebar.tsx +0 -84
  673. package/corpus/templates/crm/app/entry.client.tsx +0 -16
  674. package/corpus/templates/crm/app/entry.server.tsx +0 -10
  675. package/corpus/templates/crm/app/global.css +0 -167
  676. package/corpus/templates/crm/app/hooks/use-navigation-state.ts +0 -60
  677. package/corpus/templates/crm/app/i18n/en-US.ts +0 -89
  678. package/corpus/templates/crm/app/i18n/index.ts +0 -34
  679. package/corpus/templates/crm/app/lib/dashboard.ts +0 -13
  680. package/corpus/templates/crm/app/lib/navigation.ts +0 -54
  681. package/corpus/templates/crm/app/lib/tab-id.ts +0 -1
  682. package/corpus/templates/crm/app/lib/types.ts +0 -172
  683. package/corpus/templates/crm/app/lib/utils.ts +0 -1
  684. package/corpus/templates/crm/app/root.tsx +0 -88
  685. package/corpus/templates/crm/app/routes/_index.tsx +0 -26
  686. package/corpus/templates/crm/app/routes/accounts.tsx +0 -41
  687. package/corpus/templates/crm/app/routes/agent.tsx +0 -5
  688. package/corpus/templates/crm/app/routes/ask.tsx +0 -53
  689. package/corpus/templates/crm/app/routes/dashboard.tsx +0 -118
  690. package/corpus/templates/crm/app/routes/opportunities.tsx +0 -41
  691. package/corpus/templates/crm/app/routes/people.tsx +0 -41
  692. package/corpus/templates/crm/app/routes/proposals.tsx +0 -266
  693. package/corpus/templates/crm/app/routes/records.$recordId.tsx +0 -35
  694. package/corpus/templates/crm/app/routes/settings.tsx +0 -63
  695. package/corpus/templates/crm/app/routes/setup.tsx +0 -308
  696. package/corpus/templates/crm/app/routes/tasks.tsx +0 -252
  697. package/corpus/templates/crm/app/routes/views.tsx +0 -333
  698. package/corpus/templates/crm/app/routes.ts +0 -17
  699. package/corpus/templates/crm/app/vite-env.d.ts +0 -6
  700. package/corpus/templates/crm/changelog/2026-07-21-agent-native-crm.md +0 -6
  701. package/corpus/templates/crm/changelog/2026-07-21-clips-call-evidence-review-recipe.md +0 -6
  702. package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-find-and-review-evidence-grounded-call-signals-w.md +0 -6
  703. package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-manage-keyword-and-smart-call-signal-trackers-fr.md +0 -6
  704. package/corpus/templates/crm/changelog/2026-07-21-delegated-local-crm-automation.md +0 -6
  705. package/corpus/templates/crm/changelog/2026-07-21-native-sql.md +0 -6
  706. package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboard.md +0 -6
  707. package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboards-now-install-correctly-from-the-crm-actio.md +0 -6
  708. package/corpus/templates/crm/changelog/2026-07-21-salesforce-connection.md +0 -6
  709. package/corpus/templates/crm/changelog/2026-07-22-crm-field-validation-now-explains-which-fields-cannot-be-edi.md +0 -6
  710. package/corpus/templates/crm/changelog/2026-07-22-fixed-hubspot-contact-syncs-missing-records-updated-after-th.md +0 -6
  711. package/corpus/templates/crm/changelog/2026-07-22-fixed-pipeline-dashboard-panels-so-their-opportunity-data-lo.md +0 -6
  712. package/corpus/templates/crm/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +0 -6
  713. package/corpus/templates/crm/components.json +0 -20
  714. package/corpus/templates/crm/docs/architecture/crm-contract.md +0 -180
  715. package/corpus/templates/crm/learnings.defaults.md +0 -5
  716. package/corpus/templates/crm/package.json +0 -59
  717. package/corpus/templates/crm/public/favicon.svg +0 -1
  718. package/corpus/templates/crm/public/icon-180.svg +0 -1
  719. package/corpus/templates/crm/public/manifest.json +0 -11
  720. package/corpus/templates/crm/react-router.config.ts +0 -7
  721. package/corpus/templates/crm/server/crm/adapter.ts +0 -32
  722. package/corpus/templates/crm/server/crm/crm-field-firewall.ts +0 -64
  723. package/corpus/templates/crm/server/crm/crm-mirror.ts +0 -711
  724. package/corpus/templates/crm/server/crm/hubspot-adapter.ts +0 -1146
  725. package/corpus/templates/crm/server/crm/native-adapter.ts +0 -1715
  726. package/corpus/templates/crm/server/crm/read-through.ts +0 -207
  727. package/corpus/templates/crm/server/crm/salesforce-adapter.ts +0 -1255
  728. package/corpus/templates/crm/server/db/crm-store.ts +0 -1170
  729. package/corpus/templates/crm/server/db/index.ts +0 -169
  730. package/corpus/templates/crm/server/db/schema.ts +0 -441
  731. package/corpus/templates/crm/server/lib/intelligence/default-detectors.ts +0 -65
  732. package/corpus/templates/crm/server/lib/intelligence/evidence.ts +0 -105
  733. package/corpus/templates/crm/server/lib/intelligence/keyword-detector.ts +0 -100
  734. package/corpus/templates/crm/server/lib/intelligence/smart-detector.ts +0 -144
  735. package/corpus/templates/crm/server/lib/intelligence/summary.ts +0 -141
  736. package/corpus/templates/crm/server/lib/provider-api.ts +0 -64
  737. package/corpus/templates/crm/server/middleware/auth.ts +0 -4
  738. package/corpus/templates/crm/server/plugins/agent-chat.ts +0 -68
  739. package/corpus/templates/crm/server/plugins/auth.ts +0 -14
  740. package/corpus/templates/crm/server/plugins/core-routes.ts +0 -17
  741. package/corpus/templates/crm/server/plugins/db.ts +0 -454
  742. package/corpus/templates/crm/server/routes/[...page].get.ts +0 -5
  743. package/corpus/templates/crm/shared/crm-automation-recipes.ts +0 -132
  744. package/corpus/templates/crm/shared/crm-contract.ts +0 -254
  745. package/corpus/templates/crm/shared/crm-sales-config.ts +0 -63
  746. package/corpus/templates/crm/ssr-entry.ts +0 -11
  747. package/corpus/templates/crm/tsconfig.json +0 -24
  748. package/corpus/templates/crm/vite.config.ts +0 -15
  749. package/corpus/templates/crm/vitest.config.ts +0 -5
  750. package/corpus/templates/forms/app/components/ui/calendar.tsx +0 -214
  751. package/corpus/templates/forms/app/components/ui/chart.tsx +0 -379
  752. package/corpus/templates/forms/app/components/ui/command.tsx +0 -153
  753. package/corpus/templates/forms/app/components/ui/context-menu.tsx +0 -198
  754. package/corpus/templates/forms/app/components/ui/menubar.tsx +0 -254
  755. package/corpus/templates/macros/app/components/ui/menubar.tsx +0 -238
  756. package/corpus/templates/macros/app/components/ui/progress.tsx +0 -26
  757. package/corpus/templates/mail/app/components/ui/calendar.tsx +0 -211
  758. package/corpus/templates/mail/app/components/ui/chart.tsx +0 -379
  759. package/corpus/templates/mail/app/components/ui/command.tsx +0 -153
  760. package/corpus/templates/mail/app/components/ui/context-menu.tsx +0 -198
  761. package/corpus/templates/mail/app/components/ui/menubar.tsx +0 -254
  762. package/corpus/templates/tasks/app/components/ui/accordion.tsx +0 -56
  763. package/corpus/templates/tasks/app/components/ui/aspect-ratio.tsx +0 -5
  764. package/corpus/templates/tasks/app/components/ui/breadcrumb.tsx +0 -115
  765. package/corpus/templates/tasks/app/components/ui/calendar.tsx +0 -70
  766. package/corpus/templates/tasks/app/components/ui/carousel.tsx +0 -260
  767. package/corpus/templates/tasks/app/components/ui/chart.tsx +0 -379
  768. package/corpus/templates/tasks/app/components/ui/form.tsx +0 -177
  769. package/corpus/templates/tasks/app/components/ui/hover-card.tsx +0 -27
  770. package/corpus/templates/tasks/app/components/ui/input-otp.tsx +0 -69
  771. package/corpus/templates/tasks/app/components/ui/menubar.tsx +0 -254
  772. package/corpus/templates/tasks/app/components/ui/navigation-menu.tsx +0 -128
  773. package/corpus/templates/tasks/app/components/ui/pagination.tsx +0 -121
  774. package/corpus/templates/tasks/app/components/ui/resizable.tsx +0 -43
  775. package/corpus/templates/tasks/app/components/ui/sidebar.tsx +0 -782
  776. package/corpus/templates/tasks/app/components/ui/toggle.tsx +0 -43
@@ -1,1146 +0,0 @@
1
- import {
2
- resolveWorkspaceConnectionCredentialForApp,
3
- resolveWorkspaceConnectionForApp,
4
- type ResolvedWorkspaceConnectionForApp,
5
- type WorkspaceConnectionForApp,
6
- } from "@agent-native/core/workspace-connections";
7
-
8
- import type {
9
- CrmAccessScope,
10
- CrmAdapter,
11
- CrmAdapterCapabilities,
12
- CrmConnectionRef,
13
- CrmFieldDefinition,
14
- CrmObjectDefinition,
15
- CrmObjectKind,
16
- CrmObjectRef,
17
- CrmProvenance,
18
- CrmRecord,
19
- CrmRecordRef,
20
- CrmRelationship,
21
- CrmSyncPage,
22
- CrmValue,
23
- } from "../../shared/crm-contract.js";
24
-
25
- const HUBSPOT_API_BASE = "https://api.hubapi.com";
26
- const CRM_APP_ID = "crm";
27
- const HUBSPOT_CREDENTIAL_KEYS = [
28
- "HUBSPOT_ACCESS_TOKEN",
29
- "HUBSPOT_PRIVATE_APP_TOKEN",
30
- ] as const;
31
- const CORE_OBJECT_TYPES = ["companies", "contacts", "deals"] as const;
32
- const MAX_PAGE_SIZE = 100;
33
- const MAX_RETRY_ATTEMPTS = 3;
34
- const MAX_RETRY_DELAY_MS = 1_500;
35
- const MAX_SINGLE_RETRY_DELAY_MS = 1_000;
36
- const REQUEST_TIMEOUT_MS = 10_000;
37
-
38
- type HubSpotObjectType = (typeof CORE_OBJECT_TYPES)[number] | string;
39
-
40
- export interface HubSpotTransportRequest {
41
- path: string;
42
- method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
43
- body?: unknown;
44
- headers?: Record<string, string>;
45
- retrySafe?: boolean;
46
- }
47
-
48
- export interface HubSpotTransportResponse {
49
- status: number;
50
- body?: unknown;
51
- headers?: Record<string, string | undefined>;
52
- }
53
-
54
- export interface HubSpotTransport {
55
- request(input: HubSpotTransportRequest): Promise<HubSpotTransportResponse>;
56
- }
57
-
58
- export interface CreateHubSpotCrmAdapterOptions {
59
- connectionId?: string;
60
- userEmail?: string;
61
- orgId?: string | null;
62
- transport?: HubSpotTransport;
63
- }
64
-
65
- export interface HubSpotCrmAdapterOptions {
66
- connection: WorkspaceConnectionForApp;
67
- transport: HubSpotTransport;
68
- accessScope?: CrmAccessScope;
69
- }
70
-
71
- type HubSpotProperty = {
72
- name?: string;
73
- label?: string;
74
- type?: string;
75
- fieldType?: string;
76
- hidden?: boolean;
77
- readOnlyValue?: boolean;
78
- calculated?: boolean;
79
- required?: boolean;
80
- options?: Array<{ value?: string; label?: string; hidden?: boolean }>;
81
- referencedObjectType?: string;
82
- sensitiveDataCategory?: string;
83
- };
84
-
85
- type HubSpotSchema = {
86
- objectTypeId?: string | number;
87
- name?: string;
88
- labels?: { singular?: string; plural?: string };
89
- metaType?: string;
90
- properties?: HubSpotProperty[];
91
- };
92
-
93
- type HubSpotRecord = {
94
- id?: string | number;
95
- properties?: Record<string, unknown>;
96
- createdAt?: string;
97
- updatedAt?: string;
98
- archived?: boolean;
99
- };
100
-
101
- type HubSpotListResponse = {
102
- results?: HubSpotRecord[];
103
- paging?: { next?: { after?: string } };
104
- };
105
-
106
- type HubSpotAssociation = {
107
- toObjectId?: string | number;
108
- id?: string | number;
109
- associationTypes?: Array<{
110
- associationCategory?: string;
111
- associationTypeId?: string | number;
112
- label?: string | null;
113
- }>;
114
- };
115
-
116
- type HubSpotAssociationResponse = {
117
- results?: HubSpotAssociation[];
118
- paging?: { next?: { after?: string } };
119
- };
120
-
121
- function nonEmpty(value: string | undefined | null): string | undefined {
122
- const trimmed = value?.trim();
123
- return trimmed || undefined;
124
- }
125
-
126
- function uniqueStrings(values: readonly string[]): string[] {
127
- return Array.from(
128
- new Set(values.map((value) => value.trim()).filter(Boolean)),
129
- );
130
- }
131
-
132
- function objectKind(objectType: string): CrmObjectKind {
133
- switch (objectType.toLowerCase()) {
134
- case "companies":
135
- return "account";
136
- case "contacts":
137
- return "person";
138
- case "deals":
139
- return "opportunity";
140
- case "tasks":
141
- return "task";
142
- case "calls":
143
- case "emails":
144
- case "meetings":
145
- case "notes":
146
- return "activity";
147
- default:
148
- return "custom";
149
- }
150
- }
151
-
152
- function objectDisplayProperty(objectType: string): string[] {
153
- switch (objectType.toLowerCase()) {
154
- case "companies":
155
- return ["name", "domain"];
156
- case "contacts":
157
- return ["firstname", "lastname", "email"];
158
- case "deals":
159
- return ["dealname"];
160
- case "tickets":
161
- return ["subject"];
162
- default:
163
- return ["name", "hs_object_id"];
164
- }
165
- }
166
-
167
- function propertyValueType(
168
- property: HubSpotProperty,
169
- ): CrmFieldDefinition["valueType"] {
170
- const type = property.type?.toLowerCase();
171
- const fieldType = property.fieldType?.toLowerCase();
172
- if (fieldType === "checkbox") return "multi-enum";
173
- if (type === "enumeration") return "enum";
174
- if (type === "bool" || type === "boolean") return "boolean";
175
- if (type === "number") return "number";
176
- if (type === "date") return "date";
177
- if (type === "datetime") return "datetime";
178
- if (type === "json") return "json";
179
- if (fieldType === "currency" || property.name === "amount") return "currency";
180
- if (fieldType === "percentage") return "percent";
181
- if (type === "object_coordinates" || type === "reference") return "reference";
182
- return "string";
183
- }
184
-
185
- function propertyIsSensitive(property: HubSpotProperty): boolean {
186
- const category = property.sensitiveDataCategory?.trim().toLowerCase();
187
- return Boolean(
188
- category && category !== "none" && category !== "not_sensitive",
189
- );
190
- }
191
-
192
- function scalarValue(value: unknown): CrmValue | undefined {
193
- if (
194
- value === null ||
195
- typeof value === "string" ||
196
- typeof value === "number" ||
197
- typeof value === "boolean"
198
- ) {
199
- return value;
200
- }
201
- if (Array.isArray(value)) {
202
- const values = value.filter(
203
- (item): item is string | number | boolean | null =>
204
- item === null ||
205
- typeof item === "string" ||
206
- typeof item === "number" ||
207
- typeof item === "boolean",
208
- );
209
- return values.length === value.length ? values : undefined;
210
- }
211
- return undefined;
212
- }
213
-
214
- function toQuery(params: Record<string, string | undefined>): string {
215
- const query = new URLSearchParams();
216
- for (const [key, value] of Object.entries(params)) {
217
- if (value) query.set(key, value);
218
- }
219
- const value = query.toString();
220
- return value ? `?${value}` : "";
221
- }
222
-
223
- function encodeCursorState(value: { index: number; after?: string }): string {
224
- const bytes = new TextEncoder().encode(JSON.stringify(value));
225
- let binary = "";
226
- for (const byte of bytes) binary += String.fromCharCode(byte);
227
- return btoa(binary)
228
- .replace(/\+/g, "-")
229
- .replace(/\//g, "_")
230
- .replace(/=+$/, "");
231
- }
232
-
233
- function decodedCursor(cursor: string | undefined): {
234
- index: number;
235
- after?: string;
236
- } {
237
- if (!cursor) return { index: 0 };
238
- try {
239
- const padded = cursor
240
- .replace(/-/g, "+")
241
- .replace(/_/g, "/")
242
- .padEnd(Math.ceil(cursor.length / 4) * 4, "=");
243
- const binary = atob(padded);
244
- const decoded = JSON.parse(
245
- new TextDecoder().decode(
246
- Uint8Array.from(binary, (character) => character.charCodeAt(0)),
247
- ),
248
- ) as { index?: unknown; after?: unknown };
249
- const index = typeof decoded.index === "number" ? decoded.index : 0;
250
- return {
251
- index: Number.isInteger(index) && index >= 0 ? index : 0,
252
- ...(typeof decoded.after === "string" && decoded.after
253
- ? { after: decoded.after }
254
- : {}),
255
- };
256
- } catch {
257
- // HubSpot's `after` values are already opaque; accept them for one-object callers.
258
- return { index: 0, after: cursor };
259
- }
260
- }
261
-
262
- function encodedCursor(index: number, after?: string): string | undefined {
263
- if (!after) return undefined;
264
- return encodeCursorState({ index, after });
265
- }
266
-
267
- function scopeAllows(
268
- connection: WorkspaceConnectionForApp,
269
- objectType: string,
270
- operation: "read" | "write",
271
- ): boolean {
272
- const scopes = [
273
- ...connection.scopes,
274
- ...(connection.explicitGrant?.scopes ?? []),
275
- ].map((scope) => scope.toLowerCase());
276
- if (scopes.length === 0) return operation === "read";
277
- const singular = objectType.toLowerCase().replace(/s$/, "");
278
- return scopes.some(
279
- (scope) =>
280
- scope === "all" ||
281
- scope === "crm" ||
282
- scope === `crm.${operation}` ||
283
- scope === `crm.objects.${operation}` ||
284
- scope === `crm.objects.${objectType.toLowerCase()}.${operation}` ||
285
- scope === `crm.objects.${singular}.${operation}` ||
286
- (operation === "write" && scope.endsWith(".write")),
287
- );
288
- }
289
-
290
- function accessScopeFor(
291
- connection: WorkspaceConnectionForApp,
292
- objectType: string,
293
- ): CrmAccessScope {
294
- const grantId = connection.appAccess.grantId ?? undefined;
295
- const mode = [
296
- ...connection.credentialRefs,
297
- ...(connection.explicitGrant?.credentialRefs ?? []),
298
- ].some((ref) => ref.scope === "user")
299
- ? "user"
300
- : "service-account";
301
- const readable = scopeAllows(connection, objectType, "read");
302
- const writable = scopeAllows(connection, objectType, "write");
303
- return {
304
- key: `${connection.id}:${grantId ?? connection.appAccess.mode}`,
305
- actorId: connection.ownerEmail,
306
- grantId,
307
- mode,
308
- objectReadable: readable,
309
- objectCreateable: writable,
310
- objectUpdateable: writable,
311
- objectDeleteable: false,
312
- recordVisibility: mode === "user" ? "actor" : "unknown",
313
- };
314
- }
315
-
316
- function definitionFrom(
317
- connection: WorkspaceConnectionForApp,
318
- objectType: string,
319
- schema: HubSpotSchema | undefined,
320
- properties: HubSpotProperty[],
321
- ): CrmObjectDefinition {
322
- const scope = accessScopeFor(connection, objectType);
323
- const custom =
324
- !CORE_OBJECT_TYPES.includes(
325
- objectType as (typeof CORE_OBJECT_TYPES)[number],
326
- ) && schema?.metaType !== "HUBSPOT";
327
- return {
328
- connectionId: connection.id,
329
- provider: "hubspot",
330
- ...(connection.accountId ? { accountId: connection.accountId } : {}),
331
- actorId: connection.ownerEmail,
332
- objectType,
333
- kind: objectKind(objectType),
334
- label: schema?.labels?.singular || objectType,
335
- pluralLabel: schema?.labels?.plural || objectType,
336
- custom,
337
- queryable: scope.objectReadable,
338
- searchable: scope.objectReadable,
339
- createable: scope.objectCreateable,
340
- updateable: scope.objectUpdateable,
341
- deleteable: false,
342
- fields: properties
343
- .map((property): CrmFieldDefinition | null => {
344
- const name = nonEmpty(property.name);
345
- if (!name) return null;
346
- const sensitive = propertyIsSensitive(property);
347
- return {
348
- name,
349
- label: property.label || name,
350
- valueType: propertyValueType(property),
351
- storagePolicy: sensitive ? "redacted" : "remote-only",
352
- sensitive,
353
- readable: !property.hidden && scope.objectReadable,
354
- createable:
355
- !sensitive &&
356
- !property.readOnlyValue &&
357
- !property.calculated &&
358
- scope.objectCreateable,
359
- updateable:
360
- !sensitive &&
361
- !property.readOnlyValue &&
362
- !property.calculated &&
363
- scope.objectUpdateable,
364
- required: property.required === true,
365
- ...(property.options
366
- ? {
367
- options: property.options
368
- .filter((option) => nonEmpty(option.value))
369
- .map((option) => ({
370
- value: option.value!.trim(),
371
- label: option.label || option.value!.trim(),
372
- ...(option.hidden ? { active: false } : {}),
373
- })),
374
- }
375
- : {}),
376
- ...(property.referencedObjectType
377
- ? { referencedObjectType: property.referencedObjectType }
378
- : {}),
379
- };
380
- })
381
- .filter((field): field is CrmFieldDefinition => field !== null),
382
- };
383
- }
384
-
385
- function recordRef(
386
- connection: WorkspaceConnectionForApp,
387
- objectType: string,
388
- remoteId: string,
389
- ): CrmRecordRef {
390
- return {
391
- connectionId: connection.id,
392
- provider: "hubspot",
393
- ...(connection.accountId ? { accountId: connection.accountId } : {}),
394
- actorId: connection.ownerEmail,
395
- objectType,
396
- kind: objectKind(objectType),
397
- remoteId,
398
- };
399
- }
400
-
401
- function provenance(
402
- connection: WorkspaceConnectionForApp,
403
- objectType: string,
404
- remoteId: string,
405
- remoteRevision: string | undefined,
406
- fieldNames: string[],
407
- ): CrmProvenance[] {
408
- const observedAt = new Date().toISOString();
409
- return fieldNames.map((fieldName) => ({
410
- provider: "hubspot",
411
- connectionId: connection.id,
412
- objectType,
413
- remoteId,
414
- fieldName,
415
- ...(remoteRevision ? { remoteRevision } : {}),
416
- observedAt,
417
- }));
418
- }
419
-
420
- function projectRecord(
421
- connection: WorkspaceConnectionForApp,
422
- objectType: string,
423
- source: HubSpotRecord,
424
- fieldAllowList: string[],
425
- ): CrmRecord | null {
426
- const remoteId = source.id == null ? undefined : String(source.id);
427
- if (!remoteId) return null;
428
- const allowed = uniqueStrings(fieldAllowList);
429
- const fields: Record<string, CrmValue> = {};
430
- for (const fieldName of allowed) {
431
- const value = scalarValue(source.properties?.[fieldName]);
432
- if (value !== undefined) fields[fieldName] = value;
433
- }
434
- const displayValues = objectDisplayProperty(objectType)
435
- .map((fieldName) => fields[fieldName])
436
- .filter((value): value is CrmValue => value !== undefined)
437
- .filter(
438
- (value): value is string | number | boolean =>
439
- typeof value === "string" ||
440
- typeof value === "number" ||
441
- typeof value === "boolean",
442
- );
443
- const displayName =
444
- displayValues.map(String).filter(Boolean).join(" ") || remoteId;
445
- const remoteRevision = source.updatedAt;
446
- return {
447
- ref: recordRef(connection, objectType, remoteId),
448
- displayName,
449
- fields,
450
- ...(remoteRevision ? { remoteRevision } : {}),
451
- ...(source.updatedAt ? { remoteUpdatedAt: source.updatedAt } : {}),
452
- deleted: source.archived === true,
453
- accessScope: accessScopeFor(connection, objectType),
454
- provenance: provenance(
455
- connection,
456
- objectType,
457
- remoteId,
458
- remoteRevision,
459
- Object.keys(fields),
460
- ),
461
- };
462
- }
463
-
464
- function isNotFound(error: unknown): boolean {
465
- return error instanceof HubSpotApiError && error.status === 404;
466
- }
467
-
468
- class HubSpotApiError extends Error {
469
- constructor(
470
- readonly status: number,
471
- message: string,
472
- ) {
473
- super(message);
474
- }
475
- }
476
-
477
- function hubSpotErrorMessage(status: number): string {
478
- if (status === 401 || status === 403)
479
- return "HubSpot authentication or authorization failed.";
480
- if (status === 404) return "HubSpot resource was not found.";
481
- if (status === 429) return "HubSpot rate limit exceeded.";
482
- if (status >= 500) return "HubSpot service is temporarily unavailable.";
483
- return "HubSpot request failed.";
484
- }
485
-
486
- function headerValue(
487
- headers: Record<string, string | undefined> | undefined,
488
- name: string,
489
- ): string | undefined {
490
- if (!headers) return undefined;
491
- const expected = name.toLowerCase();
492
- return Object.entries(headers).find(
493
- ([key]) => key.toLowerCase() === expected,
494
- )?.[1];
495
- }
496
-
497
- export function hubSpotRetryDelayMs(
498
- response: HubSpotTransportResponse,
499
- attempt: number,
500
- elapsedMs: number,
501
- now = Date.now(),
502
- ): number {
503
- const retryAfter = headerValue(response.headers, "retry-after")?.trim();
504
- const numericRetryAfter = retryAfter ? Number(retryAfter) : Number.NaN;
505
- const requestedDelay = Number.isFinite(numericRetryAfter)
506
- ? Math.max(0, numericRetryAfter * 1_000)
507
- : retryAfter
508
- ? Math.max(0, Date.parse(retryAfter) - now)
509
- : 100 * 2 ** attempt;
510
- return Math.max(
511
- 0,
512
- Math.min(
513
- requestedDelay,
514
- MAX_SINGLE_RETRY_DELAY_MS,
515
- MAX_RETRY_DELAY_MS - elapsedMs,
516
- ),
517
- );
518
- }
519
-
520
- function canRetryHubSpotResponse(status: number): boolean {
521
- return status === 429 || status >= 500;
522
- }
523
-
524
- function assertOwnedRecord(
525
- connection: WorkspaceConnectionForApp,
526
- record: CrmRecordRef,
527
- ): void {
528
- if (record.provider !== "hubspot" || record.connectionId !== connection.id) {
529
- throw new Error(
530
- "HubSpot record does not belong to this workspace connection.",
531
- );
532
- }
533
- }
534
-
535
- class FetchHubSpotTransport implements HubSpotTransport {
536
- constructor(private readonly token: string) {}
537
-
538
- async request(
539
- input: HubSpotTransportRequest,
540
- ): Promise<HubSpotTransportResponse> {
541
- const response = await fetch(`${HUBSPOT_API_BASE}${input.path}`, {
542
- method: input.method ?? "GET",
543
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
544
- headers: {
545
- Authorization: `Bearer ${this.token}`,
546
- ...(input.body === undefined
547
- ? {}
548
- : { "Content-Type": "application/json" }),
549
- ...input.headers,
550
- },
551
- ...(input.body === undefined ? {} : { body: JSON.stringify(input.body) }),
552
- });
553
- const text = await response.text();
554
- let body: unknown;
555
- if (text) {
556
- try {
557
- body = JSON.parse(text);
558
- } catch {
559
- body = text;
560
- }
561
- }
562
- return {
563
- status: response.status,
564
- body,
565
- headers: {
566
- "retry-after": response.headers.get("retry-after") ?? undefined,
567
- },
568
- };
569
- }
570
- }
571
-
572
- export class HubSpotCrmAdapter implements CrmAdapter {
573
- readonly connection: CrmConnectionRef;
574
- readonly capabilities: CrmAdapterCapabilities = {
575
- schemaDiscovery: true,
576
- customObjects: true,
577
- search: true,
578
- incrementalSync: true,
579
- deletedRecordSync: true,
580
- conditionalMutations: false,
581
- labeledRelationships: true,
582
- perFieldPermissions: false,
583
- perRecordPermissions: false,
584
- };
585
-
586
- private readonly workspaceConnection: WorkspaceConnectionForApp;
587
- private readonly transport: HubSpotTransport;
588
-
589
- constructor(options: HubSpotCrmAdapterOptions) {
590
- this.workspaceConnection = options.connection;
591
- this.transport = options.transport;
592
- this.connection = {
593
- connectionId: options.connection.id,
594
- provider: "hubspot",
595
- ...(options.connection.accountId
596
- ? { accountId: options.connection.accountId }
597
- : {}),
598
- actorId: options.connection.ownerEmail,
599
- };
600
- }
601
-
602
- private async request<T>(input: HubSpotTransportRequest): Promise<T> {
603
- const readRetrySafe =
604
- input.retrySafe === true ||
605
- input.method === undefined ||
606
- input.method === "GET";
607
- let elapsedDelayMs = 0;
608
- for (let attempt = 0; attempt < MAX_RETRY_ATTEMPTS; attempt++) {
609
- const response = await this.transport.request(input);
610
- if (response.status >= 200 && response.status < 300) {
611
- return (response.body ?? {}) as T;
612
- }
613
- const mayRetry =
614
- attempt + 1 < MAX_RETRY_ATTEMPTS &&
615
- readRetrySafe &&
616
- canRetryHubSpotResponse(response.status) &&
617
- elapsedDelayMs < MAX_RETRY_DELAY_MS;
618
- if (!mayRetry) {
619
- throw new HubSpotApiError(
620
- response.status,
621
- `HubSpot API error ${response.status}: ${hubSpotErrorMessage(response.status)}`,
622
- );
623
- }
624
- const delay = hubSpotRetryDelayMs(response, attempt, elapsedDelayMs);
625
- if (delay <= 0) {
626
- continue;
627
- }
628
- await new Promise<void>((resolve) => setTimeout(resolve, delay));
629
- elapsedDelayMs += delay;
630
- }
631
- throw new Error("HubSpot retry budget was exhausted.");
632
- }
633
-
634
- private async schema(objectType: string): Promise<HubSpotSchema | undefined> {
635
- try {
636
- return await this.request<HubSpotSchema>({
637
- path: `/crm/v3/schemas/${encodeURIComponent(objectType)}`,
638
- });
639
- } catch (error) {
640
- if (isNotFound(error)) return undefined;
641
- throw error;
642
- }
643
- }
644
-
645
- private async properties(objectType: string): Promise<HubSpotProperty[]> {
646
- const response = await this.request<{ results?: HubSpotProperty[] }>({
647
- path: `/crm/v3/properties/${encodeURIComponent(objectType)}`,
648
- });
649
- return response.results ?? [];
650
- }
651
-
652
- private async objectDefinition(
653
- objectType: string,
654
- ): Promise<CrmObjectDefinition> {
655
- const [schema, properties] = await Promise.all([
656
- this.schema(objectType),
657
- this.properties(objectType),
658
- ]);
659
- return definitionFrom(
660
- this.workspaceConnection,
661
- objectType,
662
- schema,
663
- properties,
664
- );
665
- }
666
-
667
- async discoverObjects(): Promise<CrmObjectDefinition[]> {
668
- const schemas = await this.request<{ results?: HubSpotSchema[] }>({
669
- path: "/crm/v3/schemas",
670
- });
671
- const objectTypes = uniqueStrings([
672
- ...CORE_OBJECT_TYPES,
673
- ...(schemas.results ?? []).map(
674
- (schema) =>
675
- nonEmpty(schema.name) ??
676
- (schema.objectTypeId == null ? "" : String(schema.objectTypeId)),
677
- ),
678
- ]);
679
- return Promise.all(
680
- objectTypes.map((objectType) => this.objectDefinition(objectType)),
681
- );
682
- }
683
-
684
- async describeObject(objectType: string): Promise<CrmObjectDefinition> {
685
- const normalized = nonEmpty(objectType);
686
- if (!normalized) throw new Error("HubSpot objectType is required.");
687
- return this.objectDefinition(normalized);
688
- }
689
-
690
- getAccessScope(objectType: string): CrmAccessScope {
691
- const normalized = nonEmpty(objectType);
692
- if (!normalized) throw new Error("HubSpot objectType is required.");
693
- return accessScopeFor(this.workspaceConnection, normalized);
694
- }
695
-
696
- private async listPage(input: {
697
- objectType: HubSpotObjectType;
698
- fields: string[];
699
- limit: number;
700
- cursor?: string;
701
- archived?: boolean;
702
- filterGroups?: unknown[];
703
- }): Promise<HubSpotListResponse> {
704
- const objectType = encodeURIComponent(input.objectType);
705
- if (input.filterGroups?.length) {
706
- return this.request<HubSpotListResponse>({
707
- method: "POST",
708
- retrySafe: true,
709
- path: `/crm/v3/objects/${objectType}/search`,
710
- body: {
711
- limit: input.limit,
712
- ...(input.cursor ? { after: input.cursor } : {}),
713
- ...(input.fields.length ? { properties: input.fields } : {}),
714
- filterGroups: input.filterGroups,
715
- },
716
- });
717
- }
718
- return this.request<HubSpotListResponse>({
719
- path: `/crm/v3/objects/${objectType}${toQuery({
720
- limit: String(input.limit),
721
- ...(input.cursor ? { after: input.cursor } : {}),
722
- ...(input.fields.length ? { properties: input.fields.join(",") } : {}),
723
- ...(input.archived ? { archived: "true" } : {}),
724
- })}`,
725
- });
726
- }
727
-
728
- private filtersForScope(scope: {
729
- objectType: string;
730
- pipelineIds?: string[];
731
- ownerIds?: string[];
732
- updatedAfter?: string;
733
- }): unknown[] {
734
- const filters: Array<Record<string, unknown>> = [];
735
- if (
736
- scope.objectType.toLowerCase() === "deals" &&
737
- scope.pipelineIds?.length
738
- ) {
739
- filters.push({
740
- propertyName: "pipeline",
741
- operator: "IN",
742
- values: uniqueStrings(scope.pipelineIds),
743
- });
744
- }
745
- if (scope.ownerIds?.length) {
746
- filters.push({
747
- propertyName: "hubspot_owner_id",
748
- operator: "IN",
749
- values: uniqueStrings(scope.ownerIds),
750
- });
751
- }
752
- if (scope.updatedAfter) {
753
- filters.push({
754
- propertyName:
755
- scope.objectType.toLowerCase() === "contacts"
756
- ? "lastmodifieddate"
757
- : "hs_lastmodifieddate",
758
- operator: "GTE",
759
- value: scope.updatedAfter,
760
- });
761
- }
762
- return filters.length ? [{ filters }] : [];
763
- }
764
-
765
- async syncPage(input: {
766
- scope: {
767
- objectType: string;
768
- pipelineIds?: string[];
769
- ownerIds?: string[];
770
- recordIds?: string[];
771
- associatedRecordIds?: string[];
772
- updatedAfter?: string;
773
- includeDeleted?: boolean;
774
- };
775
- fieldAllowList: string[];
776
- cursor?: string;
777
- limit: number;
778
- }): Promise<CrmSyncPage> {
779
- const objectType = nonEmpty(input.scope.objectType);
780
- if (!objectType)
781
- throw new Error("HubSpot sync scope objectType is required.");
782
- const fields = uniqueStrings(input.fieldAllowList);
783
- const limit = Math.max(1, Math.min(MAX_PAGE_SIZE, input.limit));
784
- const recordIds = uniqueStrings(input.scope.recordIds ?? []);
785
- let page: HubSpotListResponse;
786
- if (recordIds.length) {
787
- const state = decodedCursor(input.cursor);
788
- const offset = Math.min(state.index, recordIds.length);
789
- page = await this.request<HubSpotListResponse>({
790
- method: "POST",
791
- retrySafe: true,
792
- path: `/crm/v3/objects/${encodeURIComponent(objectType)}/batch/read`,
793
- body: {
794
- inputs: recordIds.slice(offset, offset + limit).map((id) => ({ id })),
795
- ...(fields.length ? { properties: fields } : {}),
796
- ...(input.scope.includeDeleted ? { archived: true } : {}),
797
- },
798
- });
799
- } else {
800
- page = await this.listPage({
801
- objectType,
802
- fields,
803
- limit,
804
- cursor: input.cursor,
805
- archived: input.scope.includeDeleted,
806
- filterGroups: this.filtersForScope(input.scope),
807
- });
808
- }
809
- const associatedIds = new Set(
810
- uniqueStrings(input.scope.associatedRecordIds ?? []),
811
- );
812
- const records = (page.results ?? [])
813
- .filter(
814
- (record) => !associatedIds.size || associatedIds.has(String(record.id)),
815
- )
816
- .map((record) =>
817
- projectRecord(this.workspaceConnection, objectType, record, fields),
818
- )
819
- .filter((record): record is CrmRecord => record !== null);
820
- const nextCursor = recordIds.length
821
- ? (() => {
822
- const offset = decodedCursor(input.cursor).index + limit;
823
- return offset < recordIds.length
824
- ? encodeCursorState({ index: offset })
825
- : undefined;
826
- })()
827
- : page.paging?.next?.after;
828
- return {
829
- records,
830
- relationships: [],
831
- ...(nextCursor ? { nextCursor } : {}),
832
- complete: !nextCursor,
833
- };
834
- }
835
-
836
- async getRecord(input: {
837
- record: CrmRecordRef;
838
- fields: string[];
839
- }): Promise<CrmRecord | null> {
840
- assertOwnedRecord(this.workspaceConnection, input.record);
841
- const fields = uniqueStrings(input.fields);
842
- try {
843
- const record = await this.request<HubSpotRecord>({
844
- path: `/crm/v3/objects/${encodeURIComponent(input.record.objectType)}/${encodeURIComponent(input.record.remoteId)}${toQuery(
845
- {
846
- ...(fields.length ? { properties: fields.join(",") } : {}),
847
- },
848
- )}`,
849
- });
850
- return projectRecord(
851
- this.workspaceConnection,
852
- input.record.objectType,
853
- record,
854
- fields,
855
- );
856
- } catch (error) {
857
- if (isNotFound(error)) return null;
858
- throw error;
859
- }
860
- }
861
-
862
- async search(input: {
863
- objectTypes: string[];
864
- query: string;
865
- fields: string[];
866
- limit: number;
867
- cursor?: string;
868
- }): Promise<CrmSyncPage> {
869
- const objectTypes = uniqueStrings(input.objectTypes);
870
- if (!objectTypes.length)
871
- return { records: [], relationships: [], complete: true };
872
- const fields = uniqueStrings(input.fields);
873
- const limit = Math.max(1, Math.min(MAX_PAGE_SIZE, input.limit));
874
- const state = decodedCursor(input.cursor);
875
- const index = Math.min(state.index, objectTypes.length - 1);
876
- const objectType = objectTypes[index]!;
877
- const page = await this.request<HubSpotListResponse>({
878
- method: "POST",
879
- path: `/crm/v3/objects/${encodeURIComponent(objectType)}/search`,
880
- body: {
881
- query: input.query,
882
- limit,
883
- ...(state.after ? { after: state.after } : {}),
884
- ...(fields.length ? { properties: fields } : {}),
885
- },
886
- });
887
- const records = (page.results ?? [])
888
- .map((record) =>
889
- projectRecord(this.workspaceConnection, objectType, record, fields),
890
- )
891
- .filter((record): record is CrmRecord => record !== null);
892
- const after = page.paging?.next?.after;
893
- const nextCursor = after
894
- ? encodedCursor(index, after)
895
- : index + 1 < objectTypes.length
896
- ? encodeCursorState({ index: index + 1 })
897
- : undefined;
898
- return {
899
- records,
900
- relationships: [],
901
- ...(nextCursor ? { nextCursor } : {}),
902
- complete: !nextCursor,
903
- };
904
- }
905
-
906
- async listRelationships(input: {
907
- record: CrmRecordRef;
908
- targetObjectTypes?: string[];
909
- limit: number;
910
- cursor?: string;
911
- }): Promise<{
912
- relationships: CrmRelationship[];
913
- nextCursor?: string;
914
- complete: boolean;
915
- }> {
916
- assertOwnedRecord(this.workspaceConnection, input.record);
917
- const targetObjectTypes = uniqueStrings(
918
- input.targetObjectTypes?.length
919
- ? input.targetObjectTypes
920
- : CORE_OBJECT_TYPES,
921
- ).filter((objectType) => objectType !== input.record.objectType);
922
- if (!targetObjectTypes.length) {
923
- return { relationships: [], complete: true };
924
- }
925
- const state = decodedCursor(input.cursor);
926
- const index = Math.min(state.index, targetObjectTypes.length - 1);
927
- const targetObjectType = targetObjectTypes[index]!;
928
- const response = await this.request<HubSpotAssociationResponse>({
929
- path: `/crm/v4/objects/${encodeURIComponent(input.record.objectType)}/${encodeURIComponent(input.record.remoteId)}/associations/${encodeURIComponent(targetObjectType)}${toQuery(
930
- {
931
- limit: String(Math.max(1, Math.min(MAX_PAGE_SIZE, input.limit))),
932
- ...(state.after ? { after: state.after } : {}),
933
- },
934
- )}`,
935
- });
936
- const relationships: CrmRelationship[] = [];
937
- for (const association of response.results ?? []) {
938
- const remoteId = association.toObjectId ?? association.id;
939
- if (remoteId == null) continue;
940
- const types = association.associationTypes?.length
941
- ? association.associationTypes
942
- : [
943
- {
944
- associationCategory: "HUBSPOT_DEFINED",
945
- associationTypeId: "default",
946
- },
947
- ];
948
- for (const type of types) {
949
- const relationshipType = [
950
- type.associationCategory ?? "HUBSPOT_DEFINED",
951
- type.associationTypeId == null
952
- ? "default"
953
- : String(type.associationTypeId),
954
- ].join(":");
955
- relationships.push({
956
- from: input.record,
957
- to: recordRef(
958
- this.workspaceConnection,
959
- targetObjectType,
960
- String(remoteId),
961
- ),
962
- relationshipType,
963
- ...(type.label ? { label: type.label } : {}),
964
- });
965
- }
966
- }
967
- const after = response.paging?.next?.after;
968
- const nextCursor = after
969
- ? encodedCursor(index, after)
970
- : index + 1 < targetObjectTypes.length
971
- ? encodeCursorState({ index: index + 1 })
972
- : undefined;
973
- return {
974
- relationships,
975
- ...(nextCursor ? { nextCursor } : {}),
976
- complete: !nextCursor,
977
- };
978
- }
979
-
980
- async applyMutation(mutation: Parameters<CrmAdapter["applyMutation"]>[0]) {
981
- assertOwnedRecord(this.workspaceConnection, mutation.record);
982
- if (!mutation.idempotencyKey.trim()) {
983
- return {
984
- status: "rejected" as const,
985
- message: "An idempotency key is required.",
986
- };
987
- }
988
- if (mutation.operation === "delete") {
989
- return {
990
- status: "rejected" as const,
991
- message:
992
- "HubSpot deletion is disabled during the phase-1 CRM transport rollout.",
993
- };
994
- }
995
- if (
996
- mutation.operation === "associate" ||
997
- mutation.operation === "disassociate"
998
- ) {
999
- return {
1000
- status: "rejected" as const,
1001
- message:
1002
- "HubSpot association mutation requires an explicit association definition and is not enabled in phase 1.",
1003
- };
1004
- }
1005
- if (
1006
- !scopeAllows(
1007
- this.workspaceConnection,
1008
- mutation.record.objectType,
1009
- "write",
1010
- )
1011
- ) {
1012
- return {
1013
- status: "rejected" as const,
1014
- message:
1015
- "The workspace connection does not prove write access for this HubSpot object.",
1016
- };
1017
- }
1018
- const fields = Object.entries(mutation.fields ?? {}).reduce<
1019
- Record<string, CrmValue>
1020
- >((result, [key, value]) => {
1021
- if (key.trim()) result[key] = value;
1022
- return result;
1023
- }, {});
1024
- if (!Object.keys(fields).length) {
1025
- return {
1026
- status: "rejected" as const,
1027
- message: "At least one field is required.",
1028
- };
1029
- }
1030
- if (mutation.operation === "update" && !mutation.expectedRemoteRevision) {
1031
- return {
1032
- status: "rejected" as const,
1033
- message: "HubSpot updates require a current remote revision.",
1034
- };
1035
- }
1036
- if (mutation.expectedRemoteRevision) {
1037
- const current = await this.getRecord({
1038
- record: mutation.record,
1039
- fields: [],
1040
- });
1041
- if (
1042
- !current ||
1043
- current.remoteRevision !== mutation.expectedRemoteRevision
1044
- ) {
1045
- return {
1046
- status: "conflict" as const,
1047
- ...(current?.remoteRevision
1048
- ? { remoteRevision: current.remoteRevision }
1049
- : {}),
1050
- message:
1051
- "The HubSpot record changed before this mutation could be applied.",
1052
- };
1053
- }
1054
- if (!this.capabilities.conditionalMutations) {
1055
- return {
1056
- status: "rejected" as const,
1057
- remoteRevision: current.remoteRevision,
1058
- message:
1059
- "HubSpot does not support an atomic conditional update for this record.",
1060
- };
1061
- }
1062
- }
1063
- try {
1064
- const objectType = encodeURIComponent(mutation.record.objectType);
1065
- const response = await this.request<HubSpotRecord>({
1066
- method: mutation.operation === "create" ? "POST" : "PATCH",
1067
- path:
1068
- mutation.operation === "create"
1069
- ? `/crm/v3/objects/${objectType}`
1070
- : `/crm/v3/objects/${objectType}/${encodeURIComponent(mutation.record.remoteId)}`,
1071
- body: { properties: fields },
1072
- headers: { "X-Idempotency-Key": mutation.idempotencyKey },
1073
- });
1074
- const record = projectRecord(
1075
- this.workspaceConnection,
1076
- mutation.record.objectType,
1077
- response,
1078
- Object.keys(fields),
1079
- );
1080
- if (!record) {
1081
- return {
1082
- status: "rejected" as const,
1083
- message: "HubSpot returned no record identity.",
1084
- };
1085
- }
1086
- return {
1087
- status: "applied" as const,
1088
- record,
1089
- ...(record.remoteRevision
1090
- ? { remoteRevision: record.remoteRevision }
1091
- : {}),
1092
- };
1093
- } catch (error) {
1094
- return {
1095
- status: "rejected" as const,
1096
- message:
1097
- error instanceof Error ? error.message : "HubSpot mutation failed.",
1098
- };
1099
- }
1100
- }
1101
- }
1102
-
1103
- function requireResolvedConnection(
1104
- result: ResolvedWorkspaceConnectionForApp,
1105
- ): WorkspaceConnectionForApp {
1106
- if (!result.available || !result.connection) {
1107
- throw new Error(
1108
- `HubSpot workspace connection is unavailable: ${result.reason}`,
1109
- );
1110
- }
1111
- return result.connection;
1112
- }
1113
-
1114
- export async function createHubSpotCrmAdapter(
1115
- options: CreateHubSpotCrmAdapterOptions = {},
1116
- ): Promise<HubSpotCrmAdapter> {
1117
- const resolved = await resolveWorkspaceConnectionForApp({
1118
- appId: CRM_APP_ID,
1119
- provider: "hubspot",
1120
- ...(options.connectionId ? { connectionId: options.connectionId } : {}),
1121
- requireConnected: true,
1122
- });
1123
- const connection = requireResolvedConnection(resolved);
1124
- if (options.transport) {
1125
- return new HubSpotCrmAdapter({ connection, transport: options.transport });
1126
- }
1127
- for (const key of HUBSPOT_CREDENTIAL_KEYS) {
1128
- const credential = await resolveWorkspaceConnectionCredentialForApp({
1129
- appId: CRM_APP_ID,
1130
- provider: "hubspot",
1131
- key,
1132
- connectionId: connection.id,
1133
- ...(options.userEmail ? { userEmail: options.userEmail } : {}),
1134
- ...(options.orgId !== undefined ? { orgId: options.orgId } : {}),
1135
- });
1136
- if (!credential.available || !credential.value) continue;
1137
- if (credential.provenance?.connectionId !== connection.id) continue;
1138
- return new HubSpotCrmAdapter({
1139
- connection,
1140
- transport: new FetchHubSpotTransport(credential.value),
1141
- });
1142
- }
1143
- throw new Error(
1144
- "HubSpot workspace connection is unavailable: no scoped credential was resolved for the granted connection.",
1145
- );
1146
- }