@graph8/sdk 0.303.0 → 0.357.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (664) hide show
  1. package/README.md +81 -0
  2. package/blocks/README.md +32 -0
  3. package/blocks/_foundation/README.md +78 -0
  4. package/blocks/_foundation/block.json +79 -0
  5. package/blocks/_foundation/components/api-error.tsx +62 -0
  6. package/blocks/_foundation/components/confirm-spend-dialog.tsx +142 -0
  7. package/blocks/_foundation/components/empty-state.tsx +24 -0
  8. package/blocks/_foundation/hooks/use-g8-mutation.ts +88 -0
  9. package/blocks/_foundation/hooks/use-g8-query.ts +87 -0
  10. package/blocks/_foundation/hooks/use-job-poll.ts +130 -0
  11. package/blocks/_foundation/hooks/use-paginated.ts +105 -0
  12. package/blocks/_foundation/lib/g8-client.ts +128 -0
  13. package/blocks/_foundation/recipes/verify-proxy-key.ts +18 -0
  14. package/blocks/_foundation/server/proxy.ts +233 -0
  15. package/blocks/_foundation/server/route.ts +30 -0
  16. package/blocks/agents/README.md +133 -0
  17. package/blocks/agents/block.json +223 -0
  18. package/blocks/agents/components/agent-builder.tsx +199 -0
  19. package/blocks/agents/components/agent-knowledge-panel.tsx +144 -0
  20. package/blocks/agents/components/agent-runs.tsx +175 -0
  21. package/blocks/agents/components/agent-skills-panel.tsx +126 -0
  22. package/blocks/agents/components/agent-test-console.tsx +175 -0
  23. package/blocks/agents/lib/agent-types.ts +114 -0
  24. package/blocks/agents/recipes/create-agent-and-attach-skill.ts +50 -0
  25. package/blocks/agents/recipes/run-and-follow-agent-run.ts +46 -0
  26. package/blocks/agents/recipes/test-agent-before-activating.ts +36 -0
  27. package/blocks/analytics/README.md +73 -0
  28. package/blocks/analytics/block.json +178 -0
  29. package/blocks/analytics/components/funnel-chart.tsx +79 -0
  30. package/blocks/analytics/components/kpi-tiles.tsx +74 -0
  31. package/blocks/analytics/components/leaderboard.tsx +86 -0
  32. package/blocks/analytics/components/report-builder.tsx +200 -0
  33. package/blocks/analytics/hooks/use-report.ts +26 -0
  34. package/blocks/analytics/lib/analytics-types.ts +108 -0
  35. package/blocks/analytics/lib/use-debounced.ts +16 -0
  36. package/blocks/analytics/recipes/01-weekly-outbound-report.ts +32 -0
  37. package/blocks/analytics/recipes/02-revenue-snapshot.ts +22 -0
  38. package/blocks/analytics/recipes/03-saved-report.ts +30 -0
  39. package/blocks/appointments/README.md +80 -0
  40. package/blocks/appointments/block.json +218 -0
  41. package/blocks/appointments/components/availability-editor.tsx +192 -0
  42. package/blocks/appointments/components/booking-page.tsx +154 -0
  43. package/blocks/appointments/components/event-type-editor.tsx +214 -0
  44. package/blocks/appointments/components/meeting-detail.tsx +147 -0
  45. package/blocks/appointments/components/meeting-list.tsx +148 -0
  46. package/blocks/appointments/hooks/use-available-slots.ts +29 -0
  47. package/blocks/appointments/hooks/use-schedules.ts +18 -0
  48. package/blocks/appointments/lib/appointments-types.ts +159 -0
  49. package/blocks/appointments/lib/idempotency.ts +30 -0
  50. package/blocks/appointments/recipes/01-create-event-type-and-hours.ts +27 -0
  51. package/blocks/appointments/recipes/02-find-slots-and-book.ts +34 -0
  52. package/blocks/appointments/recipes/03-bookings-digest.ts +22 -0
  53. package/blocks/appointments/recipes/04-calendar-invite.ts +21 -0
  54. package/blocks/block.schema.json +130 -0
  55. package/blocks/block.types.ts +109 -0
  56. package/blocks/campaigns/README.md +118 -0
  57. package/blocks/campaigns/block.json +361 -0
  58. package/blocks/campaigns/components/campaign-assets.tsx +180 -0
  59. package/blocks/campaigns/components/campaign-audience-step.tsx +91 -0
  60. package/blocks/campaigns/components/campaign-launch-step.tsx +147 -0
  61. package/blocks/campaigns/components/campaign-list.tsx +120 -0
  62. package/blocks/campaigns/components/campaign-metrics.tsx +93 -0
  63. package/blocks/campaigns/components/campaign-select.tsx +52 -0
  64. package/blocks/campaigns/components/campaign-sequence-step.tsx +158 -0
  65. package/blocks/campaigns/components/campaign-wizard.tsx +238 -0
  66. package/blocks/campaigns/components/form-field.tsx +29 -0
  67. package/blocks/campaigns/components/icp-editor.tsx +230 -0
  68. package/blocks/campaigns/components/persona-editor.tsx +210 -0
  69. package/blocks/campaigns/hooks/use-company-profile.ts +34 -0
  70. package/blocks/campaigns/lib/campaigns-utils.ts +155 -0
  71. package/blocks/campaigns/recipes/attach-audience-and-launch.ts +33 -0
  72. package/blocks/campaigns/recipes/campaign-report.ts +22 -0
  73. package/blocks/campaigns/recipes/generate-ideas-and-create-campaign.ts +51 -0
  74. package/blocks/campaigns/recipes/set-up-icp-and-personas.ts +37 -0
  75. package/blocks/coach/README.md +93 -0
  76. package/blocks/coach/block.json +125 -0
  77. package/blocks/coach/components/call-scorecard.tsx +126 -0
  78. package/blocks/coach/components/coaching-feed.tsx +140 -0
  79. package/blocks/coach/lib/coach-types.ts +116 -0
  80. package/blocks/coach/recipes/read-a-scorecard.ts +27 -0
  81. package/blocks/coach/recipes/weekly-coaching-digest.ts +53 -0
  82. package/blocks/copilot/README.md +99 -0
  83. package/blocks/copilot/block.json +151 -0
  84. package/blocks/copilot/components/copilot-memory.tsx +87 -0
  85. package/blocks/copilot/components/copilot-panel.tsx +189 -0
  86. package/blocks/copilot/components/copilot-team-chat.tsx +111 -0
  87. package/blocks/copilot/lib/copilot-types.ts +111 -0
  88. package/blocks/copilot/recipes/ask-the-copilot.ts +35 -0
  89. package/blocks/copilot/recipes/post-in-a-work-channel.ts +33 -0
  90. package/blocks/copilot/recipes/remember-and-recall.ts +19 -0
  91. package/blocks/crm/README.md +122 -0
  92. package/blocks/crm/block.json +378 -0
  93. package/blocks/crm/components/activity-timeline.tsx +99 -0
  94. package/blocks/crm/components/company-detail.tsx +118 -0
  95. package/blocks/crm/components/company-table.tsx +173 -0
  96. package/blocks/crm/components/contact-detail.tsx +135 -0
  97. package/blocks/crm/components/contact-table.tsx +217 -0
  98. package/blocks/crm/components/dedupe-review.tsx +164 -0
  99. package/blocks/crm/components/import-wizard.tsx +193 -0
  100. package/blocks/crm/components/notes-panel.tsx +112 -0
  101. package/blocks/crm/components/record-form.tsx +191 -0
  102. package/blocks/crm/components/task-list.tsx +107 -0
  103. package/blocks/crm/hooks/use-custom-fields.ts +18 -0
  104. package/blocks/crm/hooks/use-debounced.ts +13 -0
  105. package/blocks/crm/hooks/use-page-query.ts +52 -0
  106. package/blocks/crm/lib/crm-types.ts +136 -0
  107. package/blocks/crm/recipes/custom-fields-and-values.ts +28 -0
  108. package/blocks/crm/recipes/dedupe-and-merge.ts +30 -0
  109. package/blocks/crm/recipes/notes-tasks-and-activity.ts +23 -0
  110. package/blocks/crm/recipes/upsert-contact-with-company.ts +33 -0
  111. package/blocks/deals/README.md +78 -0
  112. package/blocks/deals/block.json +198 -0
  113. package/blocks/deals/components/deal-detail.tsx +134 -0
  114. package/blocks/deals/components/forecast-view.tsx +112 -0
  115. package/blocks/deals/components/pipeline-board.tsx +142 -0
  116. package/blocks/deals/components/stage-editor.tsx +96 -0
  117. package/blocks/deals/hooks/use-pipeline-deals.ts +67 -0
  118. package/blocks/deals/hooks/use-pipelines.ts +19 -0
  119. package/blocks/deals/lib/deals-types.ts +128 -0
  120. package/blocks/deals/recipes/01-create-deal-and-advance.ts +32 -0
  121. package/blocks/deals/recipes/02-pipeline-report.ts +35 -0
  122. package/blocks/deals/recipes/03-stale-deals-sweep.ts +20 -0
  123. package/blocks/dialer/README.md +114 -0
  124. package/blocks/dialer/block.json +260 -0
  125. package/blocks/dialer/components/call-log.tsx +78 -0
  126. package/blocks/dialer/components/call-queue.tsx +188 -0
  127. package/blocks/dialer/components/dialer-workspace.tsx +47 -0
  128. package/blocks/dialer/components/disposition-panel.tsx +75 -0
  129. package/blocks/dialer/components/live-calls-table.tsx +107 -0
  130. package/blocks/dialer/components/session-start-form.tsx +111 -0
  131. package/blocks/dialer/components/softphone.tsx +122 -0
  132. package/blocks/dialer/components/transcript-viewer.tsx +82 -0
  133. package/blocks/dialer/hooks/use-dialer-numbers.ts +19 -0
  134. package/blocks/dialer/hooks/use-dialer-session.ts +68 -0
  135. package/blocks/dialer/hooks/use-dispositions.ts +29 -0
  136. package/blocks/dialer/lib/dialer-types.ts +158 -0
  137. package/blocks/dialer/lib/softphone-transport.ts +67 -0
  138. package/blocks/dialer/lib/twilio-transport.ts +74 -0
  139. package/blocks/dialer/recipes/01-create-session-and-dial.ts +39 -0
  140. package/blocks/dialer/recipes/02-disposition-calls.ts +26 -0
  141. package/blocks/dialer/recipes/03-review-a-call.ts +23 -0
  142. package/blocks/enrichment/README.md +105 -0
  143. package/blocks/enrichment/block.json +204 -0
  144. package/blocks/enrichment/components/bulk-enrich-panel.tsx +205 -0
  145. package/blocks/enrichment/components/email-verify-badge.tsx +82 -0
  146. package/blocks/enrichment/components/enrich-button.tsx +136 -0
  147. package/blocks/enrichment/components/waterfall-config.tsx +127 -0
  148. package/blocks/enrichment/hooks/use-providers.ts +18 -0
  149. package/blocks/enrichment/lib/enrichment-types.ts +104 -0
  150. package/blocks/enrichment/recipes/bulk-enrich-and-poll.ts +41 -0
  151. package/blocks/enrichment/recipes/lookup-and-verify.ts +25 -0
  152. package/blocks/enrichment/recipes/waterfall-pipeline.ts +26 -0
  153. package/blocks/forms/README.md +112 -0
  154. package/blocks/forms/block.json +200 -0
  155. package/blocks/forms/components/form-builder.tsx +150 -0
  156. package/blocks/forms/components/form-embed.tsx +103 -0
  157. package/blocks/forms/components/form-mapping-editor.tsx +125 -0
  158. package/blocks/forms/components/site-audit-panel.tsx +73 -0
  159. package/blocks/forms/components/submissions-table.tsx +158 -0
  160. package/blocks/forms/lib/form-types.ts +127 -0
  161. package/blocks/forms/recipes/install-snippet-and-form.ts +21 -0
  162. package/blocks/forms/recipes/retry-failed-deliveries.ts +26 -0
  163. package/blocks/forms/recipes/route-form-to-list.ts +44 -0
  164. package/blocks/inbox/README.md +72 -0
  165. package/blocks/inbox/block.json +194 -0
  166. package/blocks/inbox/components/inbox-list.tsx +156 -0
  167. package/blocks/inbox/components/inbox-screen.tsx +49 -0
  168. package/blocks/inbox/components/reply-composer.tsx +183 -0
  169. package/blocks/inbox/components/tag-and-assign.tsx +189 -0
  170. package/blocks/inbox/components/thread-badge.tsx +17 -0
  171. package/blocks/inbox/components/thread-view.tsx +108 -0
  172. package/blocks/inbox/hooks/use-inbox-thread.ts +24 -0
  173. package/blocks/inbox/hooks/use-inbox-threads.ts +40 -0
  174. package/blocks/inbox/lib/idempotency.ts +30 -0
  175. package/blocks/inbox/lib/inbox-types.ts +100 -0
  176. package/blocks/inbox/recipes/01-triage-and-reply.ts +43 -0
  177. package/blocks/inbox/recipes/02-tag-and-assign.ts +31 -0
  178. package/blocks/inbox/recipes/03-hot-contacts-digest.ts +16 -0
  179. package/blocks/integrations/README.md +75 -0
  180. package/blocks/integrations/block.json +172 -0
  181. package/blocks/integrations/components/integration-list.tsx +165 -0
  182. package/blocks/integrations/components/sync-status.tsx +223 -0
  183. package/blocks/integrations/components/webhook-manager.tsx +300 -0
  184. package/blocks/integrations/lib/integrations-utils.ts +62 -0
  185. package/blocks/integrations/recipes/crm-sync-health.ts +19 -0
  186. package/blocks/integrations/recipes/push-contacts-to-crm.ts +20 -0
  187. package/blocks/integrations/recipes/register-webhook.ts +18 -0
  188. package/blocks/integrations/recipes/verify-webhook-route.ts +33 -0
  189. package/blocks/intent/README.md +57 -0
  190. package/blocks/intent/block.json +138 -0
  191. package/blocks/intent/components/account-intent-score.tsx +91 -0
  192. package/blocks/intent/components/intent-feed.tsx +215 -0
  193. package/blocks/intent/components/intent-keyword-manager.tsx +331 -0
  194. package/blocks/intent/hooks/use-account-intent.ts +46 -0
  195. package/blocks/intent/lib/intent-utils.ts +95 -0
  196. package/blocks/intent/recipes/rank-intent-accounts.ts +36 -0
  197. package/blocks/intent/recipes/track-competitor-domain.ts +23 -0
  198. package/blocks/intent/recipes/who-visited-url.ts +18 -0
  199. package/blocks/lifecycle/README.md +79 -0
  200. package/blocks/lifecycle/block.json +198 -0
  201. package/blocks/lifecycle/components/churn-list.tsx +92 -0
  202. package/blocks/lifecycle/components/customer-table.tsx +119 -0
  203. package/blocks/lifecycle/components/lead-queue.tsx +127 -0
  204. package/blocks/lifecycle/components/lifecycle-board.tsx +102 -0
  205. package/blocks/lifecycle/components/stage-move-dialog.tsx +75 -0
  206. package/blocks/lifecycle/hooks/use-debounced.ts +13 -0
  207. package/blocks/lifecycle/hooks/use-lifecycle-stages.ts +27 -0
  208. package/blocks/lifecycle/lib/lifecycle.ts +99 -0
  209. package/blocks/lifecycle/recipes/customer-brief.ts +23 -0
  210. package/blocks/lifecycle/recipes/move-company-stage.ts +17 -0
  211. package/blocks/lifecycle/recipes/read-lifecycle-board.ts +21 -0
  212. package/blocks/lifecycle/recipes/unlock-stage-contacts.ts +25 -0
  213. package/blocks/lists/README.md +96 -0
  214. package/blocks/lists/block.json +166 -0
  215. package/blocks/lists/components/add-to-list-button.tsx +111 -0
  216. package/blocks/lists/components/list-picker.tsx +94 -0
  217. package/blocks/lists/components/list-table.tsx +160 -0
  218. package/blocks/lists/components/suppression-manager.tsx +153 -0
  219. package/blocks/lists/recipes/create-list-and-add-contacts.ts +35 -0
  220. package/blocks/lists/recipes/refresh-and-check-lists.ts +21 -0
  221. package/blocks/lists/recipes/suppress-and-reinstate.ts +30 -0
  222. package/blocks/mailboxes/README.md +71 -0
  223. package/blocks/mailboxes/block.json +187 -0
  224. package/blocks/mailboxes/components/connect-mailbox.tsx +284 -0
  225. package/blocks/mailboxes/components/domain-purchase.tsx +271 -0
  226. package/blocks/mailboxes/components/mailbox-list.tsx +185 -0
  227. package/blocks/mailboxes/components/warmup-health.tsx +232 -0
  228. package/blocks/mailboxes/lib/mailboxes-utils.ts +69 -0
  229. package/blocks/mailboxes/recipes/buy-domain-and-mailboxes.ts +64 -0
  230. package/blocks/mailboxes/recipes/connect-imap-mailbox.ts +38 -0
  231. package/blocks/mailboxes/recipes/is-it-safe-to-send.ts +17 -0
  232. package/blocks/mailboxes/recipes/warmup-report.ts +31 -0
  233. package/blocks/newsletter/README.md +122 -0
  234. package/blocks/newsletter/block.json +224 -0
  235. package/blocks/newsletter/components/issue-form.tsx +124 -0
  236. package/blocks/newsletter/components/issue-scheduler.tsx +152 -0
  237. package/blocks/newsletter/components/newsletter-editor.tsx +131 -0
  238. package/blocks/newsletter/components/newsletter-stats.tsx +93 -0
  239. package/blocks/newsletter/components/subscriber-table.tsx +173 -0
  240. package/blocks/newsletter/lib/newsletter-types.ts +97 -0
  241. package/blocks/newsletter/recipes/create-newsletter-and-draft-issue.ts +27 -0
  242. package/blocks/newsletter/recipes/import-audience-and-send.ts +43 -0
  243. package/blocks/newsletter/recipes/issue-performance-report.ts +26 -0
  244. package/blocks/nurture/README.md +110 -0
  245. package/blocks/nurture/block.json +191 -0
  246. package/blocks/nurture/components/nurture-builder.tsx +114 -0
  247. package/blocks/nurture/components/nurture-enroll.tsx +107 -0
  248. package/blocks/nurture/components/nurture-form.tsx +120 -0
  249. package/blocks/nurture/components/nurture-stats.tsx +81 -0
  250. package/blocks/nurture/lib/nurture-types.ts +109 -0
  251. package/blocks/nurture/recipes/create-a-nurture.ts +34 -0
  252. package/blocks/nurture/recipes/enroll-contacts-and-launch.ts +24 -0
  253. package/blocks/nurture/recipes/nurture-health-check.ts +28 -0
  254. package/blocks/objects/README.md +120 -0
  255. package/blocks/objects/block.json +243 -0
  256. package/blocks/objects/components/attribute-field-input.tsx +82 -0
  257. package/blocks/objects/components/attribute-form-dialog.tsx +159 -0
  258. package/blocks/objects/components/object-not-found.tsx +34 -0
  259. package/blocks/objects/components/object-record-detail.tsx +143 -0
  260. package/blocks/objects/components/object-schema-editor.tsx +197 -0
  261. package/blocks/objects/components/object-table.tsx +130 -0
  262. package/blocks/objects/components/record-form-dialog.tsx +112 -0
  263. package/blocks/objects/components/record-roles-panel.tsx +106 -0
  264. package/blocks/objects/hooks/use-object-schema.ts +36 -0
  265. package/blocks/objects/lib/object-types.ts +214 -0
  266. package/blocks/objects/recipes/define-object-and-add-records.ts +24 -0
  267. package/blocks/objects/recipes/update-audit-and-archive-records.ts +39 -0
  268. package/blocks/objects/recipes/upsert-records-from-your-system.ts +30 -0
  269. package/blocks/pages/README.md +104 -0
  270. package/blocks/pages/block.json +223 -0
  271. package/blocks/pages/components/brand-kit-editor.tsx +152 -0
  272. package/blocks/pages/components/content-library.tsx +163 -0
  273. package/blocks/pages/components/page-editor.tsx +253 -0
  274. package/blocks/pages/components/page-list.tsx +159 -0
  275. package/blocks/pages/components/seo-report.tsx +159 -0
  276. package/blocks/pages/lib/studio.ts +77 -0
  277. package/blocks/pages/recipes/audit-site-seo.ts +28 -0
  278. package/blocks/pages/recipes/create-and-publish-page.ts +26 -0
  279. package/blocks/pages/recipes/edit-page-section.ts +25 -0
  280. package/blocks/pages/recipes/refresh-brand-kit.ts +22 -0
  281. package/blocks/quotes/README.md +79 -0
  282. package/blocks/quotes/block.json +183 -0
  283. package/blocks/quotes/components/product-picker.tsx +80 -0
  284. package/blocks/quotes/components/quote-builder.tsx +195 -0
  285. package/blocks/quotes/components/quote-list.tsx +79 -0
  286. package/blocks/quotes/components/quote-viewer.tsx +135 -0
  287. package/blocks/quotes/components/signature-status.tsx +77 -0
  288. package/blocks/quotes/hooks/use-debounced.ts +13 -0
  289. package/blocks/quotes/lib/quotes.ts +142 -0
  290. package/blocks/quotes/recipes/create-and-send-quote.ts +44 -0
  291. package/blocks/quotes/recipes/revise-sent-quote.ts +18 -0
  292. package/blocks/quotes/recipes/track-quote-signature.ts +22 -0
  293. package/blocks/radar/README.md +106 -0
  294. package/blocks/radar/block.json +189 -0
  295. package/blocks/radar/components/competitor-battle-card.tsx +53 -0
  296. package/blocks/radar/components/competitor-tracker.tsx +158 -0
  297. package/blocks/radar/components/radar-overview.tsx +67 -0
  298. package/blocks/radar/components/radar-report.tsx +86 -0
  299. package/blocks/radar/hooks/use-competitors.ts +23 -0
  300. package/blocks/radar/lib/radar-types.ts +124 -0
  301. package/blocks/radar/recipes/battle-card.ts +28 -0
  302. package/blocks/radar/recipes/deep-dive-report.ts +32 -0
  303. package/blocks/radar/recipes/marketing-snapshot.ts +18 -0
  304. package/blocks/radar/recipes/track-and-scan.ts +39 -0
  305. package/blocks/search/README.md +129 -0
  306. package/blocks/search/block.json +185 -0
  307. package/blocks/search/components/filter-builder.tsx +149 -0
  308. package/blocks/search/components/prospect-results.tsx +175 -0
  309. package/blocks/search/components/save-to-list-dialog.tsx +135 -0
  310. package/blocks/search/components/saved-searches.tsx +95 -0
  311. package/blocks/search/hooks/use-filter-options.ts +41 -0
  312. package/blocks/search/lib/search-types.ts +149 -0
  313. package/blocks/search/recipes/explore-filter-values.ts +27 -0
  314. package/blocks/search/recipes/saved-searches.ts +34 -0
  315. package/blocks/search/recipes/search-and-save-to-list.ts +37 -0
  316. package/blocks/sequencer/README.md +87 -0
  317. package/blocks/sequencer/block.json +214 -0
  318. package/blocks/sequencer/components/enroll-dialog.tsx +93 -0
  319. package/blocks/sequencer/components/sequence-builder.tsx +306 -0
  320. package/blocks/sequencer/components/sequence-list.tsx +200 -0
  321. package/blocks/sequencer/components/sequence-stats.tsx +256 -0
  322. package/blocks/sequencer/components/step-editor.tsx +213 -0
  323. package/blocks/sequencer/lib/sequencer-utils.ts +168 -0
  324. package/blocks/sequencer/recipes/create-multichannel-sequence.ts +51 -0
  325. package/blocks/sequencer/recipes/launch-and-enroll.ts +44 -0
  326. package/blocks/sequencer/recipes/pause-when-unsafe.ts +30 -0
  327. package/blocks/sequencer/recipes/sequence-report.ts +22 -0
  328. package/blocks/social-ads/README.md +128 -0
  329. package/blocks/social-ads/block.json +256 -0
  330. package/blocks/social-ads/components/ad-campaign-list.tsx +136 -0
  331. package/blocks/social-ads/components/audience-sync.tsx +150 -0
  332. package/blocks/social-ads/components/creative-gallery.tsx +121 -0
  333. package/blocks/social-ads/components/post-composer.tsx +122 -0
  334. package/blocks/social-ads/components/social-post-list.tsx +116 -0
  335. package/blocks/social-ads/hooks/use-social-accounts.ts +16 -0
  336. package/blocks/social-ads/lib/social-ads-types.ts +167 -0
  337. package/blocks/social-ads/recipes/creative-to-gallery.ts +41 -0
  338. package/blocks/social-ads/recipes/schedule-post.ts +51 -0
  339. package/blocks/social-ads/recipes/sync-audience-and-launch.ts +41 -0
  340. package/blocks/visitors/README.md +56 -0
  341. package/blocks/visitors/block.json +139 -0
  342. package/blocks/visitors/components/snippet-install.tsx +169 -0
  343. package/blocks/visitors/components/traffic-chart.tsx +156 -0
  344. package/blocks/visitors/components/visitor-company-card.tsx +92 -0
  345. package/blocks/visitors/components/visitor-feed.tsx +157 -0
  346. package/blocks/visitors/lib/visitors-utils.ts +78 -0
  347. package/blocks/visitors/recipes/check-snippet-installed.ts +24 -0
  348. package/blocks/visitors/recipes/recent-company-visits.ts +27 -0
  349. package/blocks/visitors/recipes/traffic-summary.ts +24 -0
  350. package/blocks/webchat/README.md +87 -0
  351. package/blocks/webchat/block.json +134 -0
  352. package/blocks/webchat/components/chat-widget-config.tsx +160 -0
  353. package/blocks/webchat/components/conversation-list.tsx +74 -0
  354. package/blocks/webchat/lib/webchat-types.ts +83 -0
  355. package/blocks/webchat/recipes/create-bot-and-style-widget.ts +24 -0
  356. package/blocks/webchat/recipes/list-chat-visitors.ts +24 -0
  357. package/blocks/workbench/README.md +135 -0
  358. package/blocks/workbench/block.json +259 -0
  359. package/blocks/workbench/components/column-recipe-editor.tsx +183 -0
  360. package/blocks/workbench/components/run-progress.tsx +132 -0
  361. package/blocks/workbench/components/workbench-add-rows.tsx +100 -0
  362. package/blocks/workbench/components/workbench-grid.tsx +159 -0
  363. package/blocks/workbench/components/workbench-row-actions.tsx +102 -0
  364. package/blocks/workbench/components/workbench-table-list.tsx +105 -0
  365. package/blocks/workbench/hooks/use-workbench-table.ts +30 -0
  366. package/blocks/workbench/lib/waterfall-presets.ts +119 -0
  367. package/blocks/workbench/lib/workbench-types.ts +191 -0
  368. package/blocks/workbench/recipes/build-enriched-table.ts +65 -0
  369. package/blocks/workbench/recipes/import-from-search.ts +42 -0
  370. package/blocks/workbench/recipes/scrape-into-table.ts +36 -0
  371. package/blocks/workbench/recipes/waterfall-column.ts +55 -0
  372. package/blocks/workflows/README.md +100 -0
  373. package/blocks/workflows/block.json +188 -0
  374. package/blocks/workflows/components/run-history.tsx +136 -0
  375. package/blocks/workflows/components/trigger-config.tsx +134 -0
  376. package/blocks/workflows/components/workflow-editor.tsx +142 -0
  377. package/blocks/workflows/components/workflow-list.tsx +153 -0
  378. package/blocks/workflows/hooks/use-workflow.ts +51 -0
  379. package/blocks/workflows/lib/graph.ts +187 -0
  380. package/blocks/workflows/recipes/create-workflow.ts +35 -0
  381. package/blocks/workflows/recipes/find-failed-runs.ts +15 -0
  382. package/blocks/workflows/recipes/run-workflow-and-wait.ts +32 -0
  383. package/blocks/workflows/recipes/set-trigger.ts +22 -0
  384. package/dist/cli.js +5330 -29
  385. package/dist/index.browser.js +7740 -0
  386. package/dist/index.browser.js.map +1 -0
  387. package/dist/index.browser.mjs +7717 -0
  388. package/dist/index.browser.mjs.map +1 -0
  389. package/dist/index.d.mts +2220 -23
  390. package/dist/index.d.ts +2220 -23
  391. package/dist/index.js +64 -3
  392. package/dist/index.js.map +1 -1
  393. package/dist/index.mjs +64 -3
  394. package/dist/index.mjs.map +1 -1
  395. package/dist/react.browser.js +7598 -0
  396. package/dist/react.browser.js.map +1 -0
  397. package/dist/react.browser.mjs +7568 -0
  398. package/dist/react.browser.mjs.map +1 -0
  399. package/dist/react.d.mts +2082 -20
  400. package/dist/react.d.ts +2082 -20
  401. package/dist/react.js +63 -2
  402. package/dist/react.js.map +1 -1
  403. package/dist/react.mjs +63 -2
  404. package/dist/react.mjs.map +1 -1
  405. package/dist/types/agentSetup.d.ts +6 -6
  406. package/dist/types/blocks/add.d.ts +53 -0
  407. package/dist/types/blocks/create.d.ts +46 -0
  408. package/dist/types/blocks/doctor.d.ts +26 -0
  409. package/dist/types/blocks/registry.d.ts +134 -0
  410. package/dist/types/cli.d.ts +16 -0
  411. package/dist/types/core.d.ts +1 -1
  412. package/dist/types/crypto-browser.d.ts +2 -0
  413. package/dist/types/crypto-node.d.ts +6 -0
  414. package/dist/types/react.d.ts +1 -1
  415. package/dist/types/version.d.ts +2 -2
  416. package/dist/types/webhooks.d.ts +2 -2
  417. package/dist/ui/index.d.mts +54 -0
  418. package/dist/ui/index.d.ts +54 -0
  419. package/dist/ui/index.js +105 -0
  420. package/dist/ui/index.js.map +1 -0
  421. package/dist/ui/index.mjs +44 -0
  422. package/dist/ui/index.mjs.map +1 -0
  423. package/dist/ui/lib/compose-refs.d.mts +19 -0
  424. package/dist/ui/lib/compose-refs.d.ts +19 -0
  425. package/dist/ui/lib/compose-refs.js +76 -0
  426. package/dist/ui/lib/compose-refs.js.map +1 -0
  427. package/dist/ui/lib/compose-refs.mjs +41 -0
  428. package/dist/ui/lib/compose-refs.mjs.map +1 -0
  429. package/dist/ui/lib/use-mobile.d.mts +4 -0
  430. package/dist/ui/lib/use-mobile.d.ts +4 -0
  431. package/dist/ui/lib/use-mobile.js +57 -0
  432. package/dist/ui/lib/use-mobile.js.map +1 -0
  433. package/dist/ui/lib/use-mobile.mjs +22 -0
  434. package/dist/ui/lib/use-mobile.mjs.map +1 -0
  435. package/dist/ui/lib/utils.d.mts +10 -0
  436. package/dist/ui/lib/utils.d.ts +10 -0
  437. package/dist/ui/lib/utils.js +33 -0
  438. package/dist/ui/lib/utils.js.map +1 -0
  439. package/dist/ui/lib/utils.mjs +9 -0
  440. package/dist/ui/lib/utils.mjs.map +1 -0
  441. package/dist/ui/primitives/alert-dialog.d.mts +22 -0
  442. package/dist/ui/primitives/alert-dialog.d.ts +22 -0
  443. package/dist/ui/primitives/alert-dialog.js +163 -0
  444. package/dist/ui/primitives/alert-dialog.js.map +1 -0
  445. package/dist/ui/primitives/alert-dialog.mjs +119 -0
  446. package/dist/ui/primitives/alert-dialog.mjs.map +1 -0
  447. package/dist/ui/primitives/avatar.d.mts +8 -0
  448. package/dist/ui/primitives/avatar.d.ts +8 -0
  449. package/dist/ui/primitives/avatar.js +91 -0
  450. package/dist/ui/primitives/avatar.js.map +1 -0
  451. package/dist/ui/primitives/avatar.mjs +55 -0
  452. package/dist/ui/primitives/avatar.mjs.map +1 -0
  453. package/dist/ui/primitives/breadcrumb.d.mts +13 -0
  454. package/dist/ui/primitives/breadcrumb.d.ts +13 -0
  455. package/dist/ui/primitives/breadcrumb.js +127 -0
  456. package/dist/ui/primitives/breadcrumb.js.map +1 -0
  457. package/dist/ui/primitives/breadcrumb.mjs +97 -0
  458. package/dist/ui/primitives/breadcrumb.mjs.map +1 -0
  459. package/dist/ui/primitives/button.d.mts +15 -0
  460. package/dist/ui/primitives/button.d.ts +15 -0
  461. package/dist/ui/primitives/button.js +91 -0
  462. package/dist/ui/primitives/button.js.map +1 -0
  463. package/dist/ui/primitives/button.mjs +56 -0
  464. package/dist/ui/primitives/button.mjs.map +1 -0
  465. package/dist/ui/primitives/card.d.mts +10 -0
  466. package/dist/ui/primitives/card.d.ts +10 -0
  467. package/dist/ui/primitives/card.js +101 -0
  468. package/dist/ui/primitives/card.js.map +1 -0
  469. package/dist/ui/primitives/card.mjs +62 -0
  470. package/dist/ui/primitives/card.mjs.map +1 -0
  471. package/dist/ui/primitives/carousel.d.mts +45 -0
  472. package/dist/ui/primitives/carousel.d.ts +45 -0
  473. package/dist/ui/primitives/carousel.js +300 -0
  474. package/dist/ui/primitives/carousel.js.map +1 -0
  475. package/dist/ui/primitives/carousel.mjs +261 -0
  476. package/dist/ui/primitives/carousel.mjs.map +1 -0
  477. package/dist/ui/primitives/chart.d.mts +68 -0
  478. package/dist/ui/primitives/chart.d.ts +68 -0
  479. package/dist/ui/primitives/chart.js +280 -0
  480. package/dist/ui/primitives/chart.js.map +1 -0
  481. package/dist/ui/primitives/chart.mjs +241 -0
  482. package/dist/ui/primitives/chart.mjs.map +1 -0
  483. package/dist/ui/primitives/collapsible.d.mts +8 -0
  484. package/dist/ui/primitives/collapsible.d.ts +8 -0
  485. package/dist/ui/primitives/collapsible.js +72 -0
  486. package/dist/ui/primitives/collapsible.js.map +1 -0
  487. package/dist/ui/primitives/collapsible.mjs +36 -0
  488. package/dist/ui/primitives/collapsible.mjs.map +1 -0
  489. package/dist/ui/primitives/context-menu.d.mts +29 -0
  490. package/dist/ui/primitives/context-menu.d.ts +29 -0
  491. package/dist/ui/primitives/context-menu.js +203 -0
  492. package/dist/ui/primitives/context-menu.js.map +1 -0
  493. package/dist/ui/primitives/context-menu.mjs +155 -0
  494. package/dist/ui/primitives/context-menu.mjs.map +1 -0
  495. package/dist/ui/primitives/dialog.d.mts +26 -0
  496. package/dist/ui/primitives/dialog.d.ts +26 -0
  497. package/dist/ui/primitives/dialog.js +192 -0
  498. package/dist/ui/primitives/dialog.js.map +1 -0
  499. package/dist/ui/primitives/dialog.mjs +148 -0
  500. package/dist/ui/primitives/dialog.mjs.map +1 -0
  501. package/dist/ui/primitives/drawer.d.mts +26 -0
  502. package/dist/ui/primitives/drawer.d.ts +26 -0
  503. package/dist/ui/primitives/drawer.js +146 -0
  504. package/dist/ui/primitives/drawer.js.map +1 -0
  505. package/dist/ui/primitives/drawer.mjs +103 -0
  506. package/dist/ui/primitives/drawer.mjs.map +1 -0
  507. package/dist/ui/primitives/input.d.mts +5 -0
  508. package/dist/ui/primitives/input.d.ts +5 -0
  509. package/dist/ui/primitives/input.js +46 -0
  510. package/dist/ui/primitives/input.js.map +1 -0
  511. package/dist/ui/primitives/input.mjs +22 -0
  512. package/dist/ui/primitives/input.mjs.map +1 -0
  513. package/dist/ui/primitives/item.d.mts +27 -0
  514. package/dist/ui/primitives/item.d.ts +27 -0
  515. package/dist/ui/primitives/item.js +221 -0
  516. package/dist/ui/primitives/item.js.map +1 -0
  517. package/dist/ui/primitives/item.mjs +188 -0
  518. package/dist/ui/primitives/item.mjs.map +1 -0
  519. package/dist/ui/primitives/kbd.d.mts +15 -0
  520. package/dist/ui/primitives/kbd.d.ts +15 -0
  521. package/dist/ui/primitives/kbd.js +45 -0
  522. package/dist/ui/primitives/kbd.js.map +1 -0
  523. package/dist/ui/primitives/kbd.mjs +21 -0
  524. package/dist/ui/primitives/kbd.mjs.map +1 -0
  525. package/dist/ui/primitives/label.d.mts +6 -0
  526. package/dist/ui/primitives/label.d.ts +6 -0
  527. package/dist/ui/primitives/label.js +55 -0
  528. package/dist/ui/primitives/label.js.map +1 -0
  529. package/dist/ui/primitives/label.mjs +21 -0
  530. package/dist/ui/primitives/label.mjs.map +1 -0
  531. package/dist/ui/primitives/resizable.d.mts +10 -0
  532. package/dist/ui/primitives/resizable.d.ts +10 -0
  533. package/dist/ui/primitives/resizable.js +68 -0
  534. package/dist/ui/primitives/resizable.js.map +1 -0
  535. package/dist/ui/primitives/resizable.mjs +42 -0
  536. package/dist/ui/primitives/resizable.mjs.map +1 -0
  537. package/dist/ui/primitives/save-status.d.mts +31 -0
  538. package/dist/ui/primitives/save-status.d.ts +31 -0
  539. package/dist/ui/primitives/save-status.js +150 -0
  540. package/dist/ui/primitives/save-status.js.map +1 -0
  541. package/dist/ui/primitives/save-status.mjs +126 -0
  542. package/dist/ui/primitives/save-status.mjs.map +1 -0
  543. package/dist/ui/primitives/separator.d.mts +6 -0
  544. package/dist/ui/primitives/separator.d.ts +6 -0
  545. package/dist/ui/primitives/separator.js +62 -0
  546. package/dist/ui/primitives/separator.js.map +1 -0
  547. package/dist/ui/primitives/separator.mjs +28 -0
  548. package/dist/ui/primitives/separator.mjs.map +1 -0
  549. package/dist/ui/primitives/sheet.d.mts +16 -0
  550. package/dist/ui/primitives/sheet.d.ts +16 -0
  551. package/dist/ui/primitives/sheet.js +170 -0
  552. package/dist/ui/primitives/sheet.js.map +1 -0
  553. package/dist/ui/primitives/sheet.mjs +129 -0
  554. package/dist/ui/primitives/sheet.mjs.map +1 -0
  555. package/dist/ui/primitives/sidebar.d.mts +74 -0
  556. package/dist/ui/primitives/sidebar.d.ts +74 -0
  557. package/dist/ui/primitives/sidebar.js +697 -0
  558. package/dist/ui/primitives/sidebar.js.map +1 -0
  559. package/dist/ui/primitives/sidebar.mjs +651 -0
  560. package/dist/ui/primitives/sidebar.mjs.map +1 -0
  561. package/dist/ui/primitives/skeleton.d.mts +5 -0
  562. package/dist/ui/primitives/skeleton.d.ts +5 -0
  563. package/dist/ui/primitives/skeleton.js +40 -0
  564. package/dist/ui/primitives/skeleton.js.map +1 -0
  565. package/dist/ui/primitives/skeleton.mjs +16 -0
  566. package/dist/ui/primitives/skeleton.mjs.map +1 -0
  567. package/dist/ui/primitives/slider.d.mts +20 -0
  568. package/dist/ui/primitives/slider.d.ts +20 -0
  569. package/dist/ui/primitives/slider.js +112 -0
  570. package/dist/ui/primitives/slider.js.map +1 -0
  571. package/dist/ui/primitives/slider.mjs +78 -0
  572. package/dist/ui/primitives/slider.mjs.map +1 -0
  573. package/dist/ui/primitives/sortable.d.mts +50 -0
  574. package/dist/ui/primitives/sortable.d.ts +50 -0
  575. package/dist/ui/primitives/sortable.js +456 -0
  576. package/dist/ui/primitives/sortable.js.map +1 -0
  577. package/dist/ui/primitives/sortable.mjs +435 -0
  578. package/dist/ui/primitives/sortable.mjs.map +1 -0
  579. package/dist/ui/primitives/switch.d.mts +6 -0
  580. package/dist/ui/primitives/switch.d.ts +6 -0
  581. package/dist/ui/primitives/switch.js +67 -0
  582. package/dist/ui/primitives/switch.js.map +1 -0
  583. package/dist/ui/primitives/switch.mjs +33 -0
  584. package/dist/ui/primitives/switch.mjs.map +1 -0
  585. package/dist/ui/primitives/table.d.mts +12 -0
  586. package/dist/ui/primitives/table.d.ts +12 -0
  587. package/dist/ui/primitives/table.js +130 -0
  588. package/dist/ui/primitives/table.js.map +1 -0
  589. package/dist/ui/primitives/table.mjs +89 -0
  590. package/dist/ui/primitives/table.mjs.map +1 -0
  591. package/dist/ui/primitives/tabs.d.mts +9 -0
  592. package/dist/ui/primitives/tabs.d.ts +9 -0
  593. package/dist/ui/primitives/tabs.js +86 -0
  594. package/dist/ui/primitives/tabs.js.map +1 -0
  595. package/dist/ui/primitives/tabs.mjs +49 -0
  596. package/dist/ui/primitives/tabs.mjs.map +1 -0
  597. package/dist/ui/primitives/textarea.d.mts +5 -0
  598. package/dist/ui/primitives/textarea.d.ts +5 -0
  599. package/dist/ui/primitives/textarea.js +43 -0
  600. package/dist/ui/primitives/textarea.js.map +1 -0
  601. package/dist/ui/primitives/textarea.mjs +19 -0
  602. package/dist/ui/primitives/textarea.mjs.map +1 -0
  603. package/dist/ui/primitives/tooltip.d.mts +9 -0
  604. package/dist/ui/primitives/tooltip.d.ts +9 -0
  605. package/dist/ui/primitives/tooltip.js +94 -0
  606. package/dist/ui/primitives/tooltip.js.map +1 -0
  607. package/dist/ui/primitives/tooltip.mjs +57 -0
  608. package/dist/ui/primitives/tooltip.mjs.map +1 -0
  609. package/docs/agents.md +72 -29
  610. package/docs/api/README.md +7 -3
  611. package/docs/api/appObjects.d.ts +3 -1
  612. package/docs/api/appObjects.md +2 -1
  613. package/docs/api/by-path.md +51 -0
  614. package/docs/api/dataPipelines.d.ts +149 -0
  615. package/docs/api/dataPipelines.md +232 -0
  616. package/docs/api/forms.d.ts +16 -0
  617. package/docs/api/forms.md +8 -0
  618. package/docs/api/objects.d.ts +705 -5
  619. package/docs/api/objects.md +1099 -14
  620. package/docs/api/ops.d.ts +1 -1
  621. package/docs/api/ops.md +1 -1
  622. package/docs/api/processLists.d.ts +247 -0
  623. package/docs/api/processLists.md +409 -0
  624. package/docs/api/quotes.d.ts +3 -1
  625. package/docs/api/quotes.md +7 -2
  626. package/docs/api/radar.d.ts +4 -0
  627. package/docs/api/radar.md +1 -0
  628. package/docs/api/reports.d.ts +476 -0
  629. package/docs/api/reports.md +539 -0
  630. package/docs/api/scheduleBuy.d.ts +12 -8
  631. package/docs/api/scheduleBuy.md +13 -10
  632. package/docs/api/seo.d.ts +406 -3
  633. package/docs/api/seo.md +505 -1
  634. package/docs/api/workspaceBackup.d.ts +324 -0
  635. package/docs/api/workspaceBackup.md +427 -0
  636. package/package.json +174 -5
  637. package/stacks/6sense.json +46 -0
  638. package/stacks/README.md +20 -0
  639. package/stacks/apollo.json +128 -0
  640. package/stacks/clay.json +59 -0
  641. package/stacks/gong.json +72 -0
  642. package/stacks/hubspot.json +162 -0
  643. package/stacks/intercom.json +53 -0
  644. package/stacks/mailchimp.json +71 -0
  645. package/stacks/outreach.json +86 -0
  646. package/stacks/salesforce.json +94 -0
  647. package/stacks/stack.schema.json +32 -0
  648. package/stacks/starter.json +22 -0
  649. package/styles/styles.css +2 -0
  650. package/styles/theme.css +181 -0
  651. package/styles/tokens.css +284 -0
  652. package/templates/next-app/README.md.tmpl +35 -0
  653. package/templates/next-app/_pages/redirect-page.tsx.tmpl +5 -0
  654. package/templates/next-app/_pages/route-page.tsx.tmpl +9 -0
  655. package/templates/next-app/app/globals.css.tmpl +8 -0
  656. package/templates/next-app/app/layout.tsx.tmpl +19 -0
  657. package/templates/next-app/components/app-shell.tsx.tmpl +34 -0
  658. package/templates/next-app/dot-env.local.example.tmpl +6 -0
  659. package/templates/next-app/dot-gitignore.tmpl +7 -0
  660. package/templates/next-app/lib/nav.ts.tmpl +2 -0
  661. package/templates/next-app/next.config.mjs.tmpl +4 -0
  662. package/templates/next-app/package.json.tmpl +25 -0
  663. package/templates/next-app/postcss.config.mjs.tmpl +4 -0
  664. package/templates/next-app/tsconfig.json.tmpl +21 -0
@@ -0,0 +1,127 @@
1
+ "use client";
2
+
3
+ /**
4
+ * WaterfallConfig: the saved enrichment pipelines of a list ("try provider A, then B, then C until one finds
5
+ * the value") and a form to create one: pick the field to fill, the providers and their order.
6
+ *
7
+ * SDK operations, in order:
8
+ * 1. listWaterfallConfigs GET /enrichment/waterfall/configs?list_id (read) pipelines runnable on the list
9
+ * 2. listEnrichmentProviders GET /enrichment/providers (read) graph8-funded vs own key, credits per action
10
+ * 3. createDefaultWaterfallConfig POST /enrichment/waterfall/configs { list_id, name, field, providers, skip_existing_values }
11
+ * (billable tier) goes through ConfirmSpendDialog first; idempotent by (list_id, name) - the same name reuses the pipeline.
12
+ * 4. deleteWaterfallConfig DELETE /enrichment/waterfall/configs/{column_id} (destructive, ConfirmSpendDialog)
13
+ *
14
+ * Providers on graph8's system key spend credits when the pipeline RUNS; providers on the org's own key (BYOK) do not.
15
+ * A BYOK provider without a key is listed under `missing_credentials` and is skipped at run time.
16
+ */
17
+
18
+ import { useState } from "react";
19
+ import { Button, Input, Label, Skeleton } from "@graph8/sdk/ui";
20
+ import { ApiError } from "@/g8/components/api-error";
21
+ import { ConfirmSpendDialog } from "@/g8/components/confirm-spend-dialog";
22
+ import { EmptyState } from "@/g8/components/empty-state";
23
+ import { useG8Mutation } from "@/g8/hooks/use-g8-mutation";
24
+ import { useG8Query } from "@/g8/hooks/use-g8-query";
25
+ import { g8Delete, g8Get, g8Post } from "@/g8/lib/g8-client";
26
+ import { useProviders } from "../hooks/use-providers";
27
+ import { TARGET_FIELDS } from "../lib/enrichment-types";
28
+ import type { TargetField, WaterfallConfigSummary } from "../lib/enrichment-types";
29
+
30
+ export interface WaterfallConfigProps {
31
+ listId: number;
32
+ /** Called with the pipeline's column_id after create or delete (for example to refresh a BulkEnrichPanel). */
33
+ onChanged?: () => void;
34
+ className?: string;
35
+ }
36
+
37
+ export function WaterfallConfig({ listId, onChanged, className }: WaterfallConfigProps) {
38
+ const [name, setName] = useState("");
39
+ const [field, setField] = useState<TargetField>("work_email");
40
+ const [order, setOrder] = useState<string[]>([]);
41
+ const [skipExisting, setSkipExisting] = useState(true);
42
+ const [confirmCreate, setConfirmCreate] = useState(false);
43
+ const [deleting, setDeleting] = useState<WaterfallConfigSummary | null>(null);
44
+ const catalog = useProviders();
45
+
46
+ const configs = useG8Query((signal) => g8Get<{ configs: WaterfallConfigSummary[] }>("/enrichment/waterfall/configs", { list_id: listId }, { signal }), [listId]);
47
+ const create = useG8Mutation(
48
+ () => g8Post<{ column_id: string; created: boolean }>("/enrichment/waterfall/configs", { list_id: listId, name: name.trim(), field, providers: order, skip_existing_values: skipExisting }),
49
+ { onSuccess: () => { setConfirmCreate(false); setName(""); setOrder([]); void configs.refetch(); onChanged?.(); } },
50
+ );
51
+ const remove = useG8Mutation((columnId: string) => g8Delete(`/enrichment/waterfall/configs/${columnId}`), {
52
+ onSuccess: () => { setDeleting(null); void configs.refetch(); onChanged?.(); },
53
+ });
54
+
55
+ const items = configs.data?.data.configs ?? [];
56
+ const byName = new Map(catalog.providers.map((p) => [p.provider, p]));
57
+ const systemUsed = order.filter((p) => byName.get(p)?.system_funded && !byName.get(p)?.byok_configured);
58
+ const move = (p: string, d: number) => {
59
+ const i = order.indexOf(p), j = i + d;
60
+ if (j < 0 || j >= order.length) return;
61
+ const next = [...order];
62
+ [next[i], next[j]] = [next[j], next[i]];
63
+ setOrder(next);
64
+ };
65
+
66
+ return (
67
+ <div className={`flex flex-col gap-5 ${className ?? ""}`}>
68
+ <section className="flex flex-col gap-2" aria-label="Saved pipelines">
69
+ <h3 className="text-sm font-medium">Saved pipelines</h3>
70
+ {configs.error ? <ApiError error={configs.error} title="Could not load pipelines" onRetry={() => void configs.refetch()} /> : null}
71
+ {remove.error ? <ApiError error={remove.error} title="Could not delete the pipeline" /> : null}
72
+ {configs.loading && !configs.data ? <Skeleton className="h-12 w-full" /> : null}
73
+ {!configs.loading && !configs.error && items.length === 0 ? <EmptyState title="No pipelines yet" description="Create one below, or let the first enrichment run create a default." /> : null}
74
+ <ul className="flex flex-col gap-2">
75
+ {items.map((c) => (
76
+ <li key={c.column_id} className="rounded-md border p-3" data-testid="pipeline">
77
+ <div className="flex items-center justify-between gap-2">
78
+ <p className="text-sm font-medium">{c.name}{c.is_global ? <span className="ml-2 text-xs text-muted-foreground">all lists</span> : null}</p>
79
+ <Button variant="ghost" size="sm" onClick={() => setDeleting(c)}>Delete</Button>
80
+ </div>
81
+ <p className="text-xs text-muted-foreground">{c.field_to_enrich ?? "field"}: {c.providers.join(" > ") || "no providers"} ({c.step_count} step{c.step_count === 1 ? "" : "s"})</p>
82
+ {c.missing_credentials.length ? <p role="alert" className="mt-1 text-xs text-amber-700">Skipped at run time, no key: {c.missing_credentials.join(", ")}</p> : null}
83
+ </li>
84
+ ))}
85
+ </ul>
86
+ </section>
87
+
88
+ <section className="flex flex-col gap-3" aria-label="New pipeline">
89
+ <h3 className="text-sm font-medium">New pipeline</h3>
90
+ <div className="flex flex-wrap items-end gap-3">
91
+ <div className="flex flex-col gap-1"><Label htmlFor="wf-name">Name</Label><Input id="wf-name" className="w-64" value={name} onChange={(e) => setName(e.target.value)} /></div>
92
+ <div className="flex flex-col gap-1"><Label htmlFor="wf-field">Fill</Label>
93
+ <select id="wf-field" className="h-9 rounded-md border bg-background px-2 text-sm" value={field} onChange={(e) => setField(e.target.value as TargetField)}>
94
+ {TARGET_FIELDS.map((f) => <option key={f.value} value={f.value}>{f.label}</option>)}
95
+ </select>
96
+ </div>
97
+ </div>
98
+ {catalog.error ? <ApiError error={catalog.error} title="Could not load providers" onRetry={() => void catalog.refetch()} /> : null}
99
+ <ol className="flex flex-col gap-1" aria-label="Provider order">
100
+ {order.map((p, i) => (
101
+ <li key={p} className="flex items-center gap-2 text-sm">
102
+ <span className="w-6 text-muted-foreground">{i + 1}.</span><span className="w-32 font-medium">{p}</span>
103
+ <span className="text-xs text-muted-foreground">{byName.get(p)?.byok_configured ? "your key, free" : byName.get(p)?.system_funded ? "graph8 credits" : "needs your key"}</span>
104
+ <Button variant="ghost" size="sm" aria-label={`Move ${p} up`} disabled={i === 0} onClick={() => move(p, -1)}>Up</Button>
105
+ <Button variant="ghost" size="sm" aria-label={`Move ${p} down`} disabled={i === order.length - 1} onClick={() => move(p, 1)}>Down</Button>
106
+ <Button variant="ghost" size="sm" aria-label={`Remove ${p}`} onClick={() => setOrder(order.filter((x) => x !== p))}>Remove</Button>
107
+ </li>
108
+ ))}
109
+ </ol>
110
+ <div className="flex flex-wrap gap-1">
111
+ {catalog.providers.filter((p) => !order.includes(p.provider)).map((p) => (
112
+ <Button key={p.provider} variant="outline" size="sm" onClick={() => setOrder([...order, p.provider])}>Add {p.provider}</Button>
113
+ ))}
114
+ </div>
115
+ <label className="flex items-center gap-2 text-sm"><input type="checkbox" checked={skipExisting} onChange={(e) => setSkipExisting(e.target.checked)} /> Skip contacts that already have a value</label>
116
+ {create.error ? <ApiError error={create.error} title="Could not create the pipeline" /> : null}
117
+ <div className="flex justify-end"><Button disabled={!name.trim() || order.length === 0} onClick={() => setConfirmCreate(true)}>Create pipeline</Button></div>
118
+ </section>
119
+
120
+ <ConfirmSpendDialog open={confirmCreate} tier="billable" title={`Create pipeline "${name.trim()}"`}
121
+ description={systemUsed.length ? `Running it uses graph8 credits for ${systemUsed.join(", ")}; providers on your own key cost nothing. Creating the pipeline itself does not run it.` : "All providers use your own keys, so running it costs no graph8 credits. Creating the pipeline does not run it."}
122
+ confirmLabel="Create" confirming={create.loading} onConfirm={() => void create.mutate(undefined)} onCancel={() => setConfirmCreate(false)} />
123
+ <ConfirmSpendDialog open={deleting != null} tier="destructive" title={`Delete pipeline "${deleting?.name ?? ""}"`} description="Values it already wrote stay on the contacts."
124
+ affected={1} confirming={remove.loading} onConfirm={() => deleting && void remove.mutate(deleting.column_id)} onCancel={() => setDeleting(null)} />
125
+ </div>
126
+ );
127
+ }
@@ -0,0 +1,18 @@
1
+ "use client";
2
+
3
+ import { useG8Query } from "@/g8/hooks/use-g8-query";
4
+ import { g8Get } from "@/g8/lib/g8-client";
5
+ import type { ProviderEntry } from "../lib/enrichment-types";
6
+
7
+ /**
8
+ * The enrichment provider catalog (`GET /enrichment/providers`): which providers graph8 funds with its own key
9
+ * (usable with no setup, spends credits) and which need the org's own key (BYOK), with the credits per action.
10
+ */
11
+ export function useProviders(enabled = true) {
12
+ const query = useG8Query(
13
+ async (signal) => (await g8Get<{ providers: ProviderEntry[]; count: number }>("/enrichment/providers", undefined, { signal })).data.providers ?? [],
14
+ [],
15
+ { enabled },
16
+ );
17
+ return { providers: query.data ?? [], loading: query.loading, error: query.error, refetch: query.refetch };
18
+ }
@@ -0,0 +1,104 @@
1
+ "use client";
2
+
3
+ /**
4
+ * Prices, vocabularies and shapes for the enrichment components.
5
+ *
6
+ * Prices are the ones the API charges today (developer_api/constants.py): a person or company lookup costs 2
7
+ * credits ONLY when it finds a match (a miss is free), an email verification costs 1, and a bulk enrichment is
8
+ * quoted at 2 credits per record before it runs. The API has no "get balance" call, so every number the UI shows
9
+ * is an ESTIMATE of what a run can cost, not a balance check. Prefer the API's own quote (`max_total_credits` from
10
+ * the preflight) whenever it is there.
11
+ */
12
+
13
+ export const CREDITS_PER_FOUND_LOOKUP = 2;
14
+ export const CREDITS_PER_EMAIL_VERIFICATION = 1;
15
+ export const CREDITS_PER_RECORD_ESTIMATE = 2;
16
+
17
+ /** What a bulk run can fill. `column` is the key in `fields_config`; `target` is the preflight's target_field. */
18
+ export const TARGET_FIELDS = [
19
+ { value: "work_email", label: "Work email", column: "work_email", target: "CONTACT_WORK_EMAIL" },
20
+ { value: "direct_phone", label: "Direct phone", column: "direct_phone", target: "CONTACT_DIRECT_PHONE" },
21
+ { value: "mobile_phone", label: "Mobile phone", column: "mobile_phone", target: "CONTACT_MOBILE_PHONE" },
22
+ ] as const;
23
+ export type TargetField = (typeof TARGET_FIELDS)[number]["value"];
24
+
25
+ export interface ProviderEntry {
26
+ provider: string;
27
+ system_funded: boolean;
28
+ byok_configured: boolean;
29
+ default_credential_source: "system" | "byok";
30
+ credits_per_row: Record<string, number>;
31
+ actions: string[];
32
+ }
33
+
34
+ export interface ProviderStep {
35
+ provider: string;
36
+ is_system_provider: boolean;
37
+ credential_source: "system" | "byok";
38
+ credential_ready: boolean;
39
+ }
40
+
41
+ export interface Preflight {
42
+ list_id: number;
43
+ list_name?: string | null;
44
+ mode: string;
45
+ contact_ids: number[];
46
+ contact_count: number;
47
+ duplicates_removed: number;
48
+ not_in_list: number[];
49
+ providers: string[];
50
+ uses_saved_pipeline: boolean;
51
+ providers_detail: ProviderStep[];
52
+ missing_credentials: string[];
53
+ warnings: string[];
54
+ pipeline_column_id?: string | null;
55
+ credits_per_record?: number | null;
56
+ priced_records?: number | null;
57
+ max_total_credits?: number | null;
58
+ }
59
+
60
+ export interface EnrichJob {
61
+ job_id: string;
62
+ status: string;
63
+ total?: number | null;
64
+ completed?: number | null;
65
+ successful_enrichments?: number | null;
66
+ failed_enrichments?: number | null;
67
+ total_credits_used?: number | null;
68
+ warnings?: string[] | null;
69
+ provider_errors?: Array<{ record_id?: number; provider?: string; error?: string }> | null;
70
+ }
71
+
72
+ export interface WaterfallConfigSummary {
73
+ column_id: string;
74
+ name: string;
75
+ field_to_enrich?: string | null;
76
+ is_global?: boolean;
77
+ is_active?: boolean;
78
+ list_id?: number | null;
79
+ step_count: number;
80
+ providers: string[];
81
+ providers_detail: ProviderStep[];
82
+ missing_credentials: string[];
83
+ }
84
+
85
+ const TERMINAL = new Set(["completed", "complete", "failed", "cancelled", "canceled", "completed_with_errors", "partial", "error"]);
86
+
87
+ /** A job in one of these states will not change any more: stop polling. */
88
+ export function isJobTerminal(status: string | undefined | null): boolean {
89
+ return TERMINAL.has(String(status ?? "").toLowerCase());
90
+ }
91
+
92
+ /**
93
+ * What to show as the cost of a run: the API's own quote when the preflight priced it, otherwise the flat
94
+ * per-record estimate times the contacts that are really on the list. Never a balance.
95
+ */
96
+ export function estimateCredits(preflight: Pick<Preflight, "max_total_credits" | "contact_count" | "not_in_list"> | undefined, fallbackCount: number): number {
97
+ if (preflight?.max_total_credits != null) return preflight.max_total_credits;
98
+ const count = preflight ? Math.max(0, preflight.contact_count - (preflight.not_in_list?.length ?? 0)) : fallbackCount;
99
+ return count * CREDITS_PER_RECORD_ESTIMATE;
100
+ }
101
+
102
+ export function isMaskedValue(value: unknown): boolean {
103
+ return typeof value === "string" && value.trim() === "***";
104
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @title Enrich many contacts of a list and wait for the job
3
+ * @when Filling work emails or phones for a list. Order: preflight (free: counts, missing provider keys and the
4
+ * credit quote) -> a human approves the quote -> start the job -> poll it (the API has no streams or
5
+ * webhook for completion) -> read provider errors if nothing was written. Contact ids must be on the list;
6
+ * ids not on it are skipped and not charged. Never enrich contacts you only have as masked search results:
7
+ * save them to a list first.
8
+ */
9
+ import { g8 } from "@graph8/sdk";
10
+
11
+ g8.init({ apiKey: process.env.G8_API_KEY! });
12
+
13
+ export async function quote(listId: number, contactIds: number[]) {
14
+ const res = await g8.api.enrichment.preflightEnrichment({
15
+ body: { list_id: listId, contact_ids: contactIds, mode: "waterfall", providers: ["prospeo", "dropcontact"], target_field: "CONTACT_WORK_EMAIL" },
16
+ });
17
+ return res.data; // contact_count, not_in_list, missing_credentials, warnings, credits_per_record, max_total_credits
18
+ }
19
+
20
+ /** Only after a person approved `max_total_credits`. */
21
+ export async function enrichAndWait(listId: number, contactIds: number[]) {
22
+ const started = await g8.api.enrichment.startEnrichment({
23
+ body: { list_id: listId, contact_ids: contactIds, fields_config: { work_email: ["prospeo", "dropcontact"] } },
24
+ });
25
+ const jobId = started.data.job_id;
26
+
27
+ let delay = 2000;
28
+ for (let i = 0; i < 100; i++) {
29
+ const job = await g8.api.enrichment.getEnrichmentJob({ path: { job_id: jobId } });
30
+ if (["completed", "failed", "cancelled"].includes(job.data.status)) {
31
+ if (!job.data.successful_enrichments) {
32
+ const why = await g8.api.enrichment.getEnrichmentJob({ path: { job_id: jobId }, query: { include_provider_errors: true } });
33
+ return { jobId, job: job.data, providerErrors: why.data.provider_errors };
34
+ }
35
+ return { jobId, job: job.data };
36
+ }
37
+ await new Promise((r) => setTimeout(r, delay));
38
+ delay = Math.min(15000, Math.round(delay * 1.5));
39
+ }
40
+ throw new Error(`job ${jobId} did not finish in time; keep polling later`);
41
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @title Look up a person or company and verify an email
3
+ * @when One-off enrichment of a single record. A lookup costs 2 credits ONLY when it finds a match (a miss is
4
+ * free); an email verification costs 1 credit. Both are billable: ask a human before looping over many records
5
+ * (use the bulk job for that). The lookup returns data, it does not update the CRM: write the fields you want
6
+ * with `g8.contacts.update` afterwards.
7
+ */
8
+ import { g8 } from "@graph8/sdk";
9
+
10
+ g8.init({ apiKey: process.env.G8_API_KEY! });
11
+
12
+ export async function enrichOnePerson(email: string) {
13
+ const person = await g8.enrich.person({ email });
14
+ if (!person.found) return { found: false as const }; // nothing was charged
15
+ return { found: true as const, confidence: person.confidence, data: person.data };
16
+ }
17
+
18
+ export async function enrichOneCompany(domain: string) {
19
+ return g8.enrich.company({ domain });
20
+ }
21
+
22
+ export async function isDeliverable(email: string) {
23
+ const v = await g8.enrich.verifyEmail(email);
24
+ return { valid: v.valid, deliverable: v.deliverable, catchAll: v.catch_all };
25
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @title Create a waterfall pipeline for a list and see which providers are ready
3
+ * @when Setting up "try provider A, then B" enrichment for a column once, then reusing it. Check the provider
4
+ * catalog first: graph8-funded providers spend credits when the pipeline runs, providers on your own key do not,
5
+ * and a provider without a key is skipped. Creating is idempotent by (list_id, name).
6
+ */
7
+ import { g8 } from "@graph8/sdk";
8
+
9
+ g8.init({ apiKey: process.env.G8_API_KEY! });
10
+
11
+ export async function readyProviders() {
12
+ const res = await g8.api.enrichment.listEnrichmentProviders();
13
+ return (res.data.providers ?? []).map((p) => ({ provider: p.provider, usable: p.system_funded || p.byok_configured, source: p.default_credential_source }));
14
+ }
15
+
16
+ export async function createPipeline(listId: number) {
17
+ const res = await g8.api.enrichment.createDefaultWaterfallConfig({
18
+ body: { list_id: listId, name: "Work email waterfall", field: "work_email", providers: ["prospeo", "dropcontact"], skip_existing_values: true },
19
+ });
20
+ return { columnId: res.data.column_id, created: res.data.created, missing: res.data.missing_credentials };
21
+ }
22
+
23
+ export async function pipelinesOf(listId: number) {
24
+ const res = await g8.api.enrichment.listWaterfallConfigs({ query: { list_id: listId } });
25
+ return res.data.configs;
26
+ }
@@ -0,0 +1,112 @@
1
+ # forms: capture, route and monitor website forms
2
+
3
+ graph8 does not host a form designer. It **captures the lead forms already on your site** through the tracking
4
+ snippet, lists them, and routes every submission to a list with a field mapping. This block is the screen set for
5
+ that: install the code (`FormEmbed`), set where leads go and how fields map (`FormBuilder`), see what arrived and
6
+ retry failures (`SubmissionsTable`), and find forms that are not captured (`SiteAuditPanel`).
7
+
8
+ ## Install
9
+
10
+ ```
11
+ npx @graph8/sdk add forms
12
+ ```
13
+
14
+ Installs `foundation` and `crm` first if missing. Everything lands under `g8/forms/`.
15
+
16
+ ## Prerequisites (the human must do these)
17
+
18
+ | Where | What | How to verify |
19
+ |---|---|---|
20
+ | Your site | Load the graph8 snippet (from `FormEmbed`) on every page that has a form. Forms appear only after a first captured submission. | Submit the form on the live site; `GET /api/v1/forms` lists it within a minute. |
21
+ | graph8 workspace | A list to receive leads. | `GET /api/v1/lists` returns one. |
22
+ | Your app | `allowedPrefixes` in `app/api/g8/[...path]/route.ts` must include `forms`, `snippet`, `contacts`, `lists`. | The route file lists them. |
23
+ | graph8 key | Submitted values (emails, names) are **redacted** for a key without the Signals write capability. | Identifying fields are not empty in `SubmissionsTable`. |
24
+
25
+ ## The flow, in order
26
+
27
+ 1. **Get the code**: `<FormEmbed />` calls `getOrgSnippet` (write key, `<script>` tag, React component) and `getFormTemplate`
28
+ (ready-made lead form HTML). With several sites the API answers `action_required` and lists streams; the component shows a picker
29
+ and re-reads with `stream_id`.
30
+ 2. **List captured forms**: `<FormBuilder />` calls `listForms`. Each item carries **`form_key` and `source_id`**; every later call
31
+ needs BOTH (a form key is only unique inside one source/site).
32
+ 3. **Open a form**: `getFormOverview(form_key, source_id)` gives health, counts and the current destination (`destination.list_id`,
33
+ `route.version`).
34
+ 4. **Map and route** (`FormMappingEditor`):
35
+ `getFormFields` (names the form really submits) + `getContactFormFields` (contact fields, grouped, `CONTACT_WORK_EMAIL` etc.)
36
+ + `listLists` (destination) -> optional `getFormRouteRecommendations` -> `previewFormMapping` (writes nothing)
37
+ -> `saveFormMapping` (a FULL replacement; sends `expected_route_version` so a colleague's save is a 409, not an overwrite)
38
+ -> `testFormRoute` (adds one synthetic contact to the list).
39
+ 5. **Watch it**: `SubmissionsTable` uses `searchFormSubmissions` (paged). `Trace` calls `getFormSubmissionTrace` (where did this lead go).
40
+ A failed row carries `delivery.receipt_id`; **Retry** calls `retryFormDelivery(receipt_id)` after a confirm.
41
+ 6. **Pause**: `pauseFormDelivery` keeps accepting submissions but queues them; `resumeFormDelivery` delivers again. Both open `ConfirmSpendDialog` (tier external).
42
+
43
+ ```tsx
44
+ // app/forms/page.tsx
45
+ "use client";
46
+ import { FormBuilder } from "@/g8/forms/components/form-builder";
47
+ export default function FormsPage() {
48
+ return <FormBuilder />;
49
+ }
50
+ // app/forms/install/page.tsx -> <FormEmbed />, app/forms/audit/page.tsx -> <SiteAuditPanel />
51
+ ```
52
+
53
+ ## Default decisions (do not ask the human unless marked)
54
+
55
+ | Decision | Default | Ask? |
56
+ |---|---|---|
57
+ | Hosted designer vs capturing existing forms | Capture existing forms; the generated lead form is only a starting point | no |
58
+ | Which list receives a form's leads | A new list named after the form | **yes** |
59
+ | Email field mapping | `CONTACT_WORK_EMAIL`; use "Suggest mapping" for the rest | no |
60
+ | Retrying failed deliveries | One lead at a time, after the person confirms | no |
61
+
62
+ ## Things that surprise people
63
+
64
+ - **Responses are passed through from the app and only partly typed.** The components read them defensively (`items`/`fields`/`receipts`).
65
+ If you build on the raw API, log the first response of each call before relying on a field.
66
+ - **Saving a mapping applies to every submission captured afterwards.** Always preview first (the editor's buttons are in that order).
67
+ - **`testFormRoute` writes.** It adds one synthetic contact (`forms-test-...@example.com`) to the destination list and needs an active route.
68
+ - **A scan is asynchronous.** `requestSiteAuditScan` is rate limited to one per minute per org (`already_queued`); `SiteAuditPanel` polls `getSiteAudit` with `useJobPoll`.
69
+ - Retrying many failures is a loop of single retries (see the recipe); replaying a whole time window (a backfill) is not exposed to the SDK block.
70
+
71
+ ## Recipes (server-side, `recipes/`)
72
+
73
+ - `install-snippet-and-form.ts`: fetch the snippet and the lead-form HTML for a site.
74
+ - `route-form-to-list.ts`: find a form, read its fields, create a list, preview, save, test.
75
+ - `retry-failed-deliveries.ts`: retry failed leads one by one, capped per run.
76
+
77
+ ## What is in the block
78
+
79
+ | Component | File | What it is |
80
+ |---|---|---|
81
+ | `FormBuilder` | `components/form-builder.tsx` | Forms workspace: list captured forms, rename, pause/resume delivery, set destination and mapping, view submissions. |
82
+ | `FormMappingEditor` | `components/form-mapping-editor.tsx` | Pick the destination list and map submitted fields to contact fields, with suggest, preview, save and test. |
83
+ | `FormEmbed` | `components/form-embed.tsx` | Copyable tracking snippet (script tag, React) and a ready-made lead-capture form with live preview. |
84
+ | `SubmissionsTable` | `components/submissions-table.tsx` | Paged submissions with delivery state, a per-lead trace and a confirmed retry for failed deliveries. |
85
+ | `SiteAuditPanel` | `components/site-audit-panel.tsx` | Forms on your site that are not captured, from the latest crawl; rescan and triage findings. |
86
+
87
+ ## Operations
88
+
89
+ Tiers: `read` and `write` need no confirmation; `external` (pause, resume, retry) opens `ConfirmSpendDialog` first.
90
+
91
+ | Operation | Method and path | Tier | Scope | Used by |
92
+ |---|---|---|---|---|
93
+ | `forms.listForms` | `GET /api/v1/forms` | read | `forms:read` | FormBuilder |
94
+ | `forms.getFormOverview` | `GET /api/v1/forms/{form_key}/overview` | read | `forms:read` | FormBuilder, FormMappingEditor |
95
+ | `forms.updateFormRegistry` | `PATCH /api/v1/forms/{form_key}` | write | `forms:write` | FormBuilder |
96
+ | `forms.pauseFormDelivery` | `POST /api/v1/forms/{form_key}/delivery/pause` | external | `forms:run` | FormBuilder |
97
+ | `forms.resumeFormDelivery` | `POST /api/v1/forms/{form_key}/delivery/resume` | external | `forms:run` | FormBuilder |
98
+ | `forms.getFormFields` | `GET /api/v1/forms/{form_key}/fields` | read | `forms:read` | FormMappingEditor |
99
+ | `contacts.getContactFormFields` | `GET /api/v1/contacts/form-fields` | read | `contacts:read` | FormMappingEditor |
100
+ | `lists.listLists` | `GET /api/v1/lists` | read | `lists:read` | FormMappingEditor |
101
+ | `forms.getFormRouteRecommendations` | `GET /api/v1/forms/{form_key}/route/recommendations` | read | `forms:read` | FormMappingEditor |
102
+ | `forms.previewFormMapping` | `POST /api/v1/forms/{form_key}/mapping/preview` | read | `forms:read` | FormMappingEditor |
103
+ | `forms.saveFormMapping` | `POST /api/v1/forms/{form_key}/mapping/save` | write | `forms:write` | FormMappingEditor |
104
+ | `forms.testFormRoute` | `POST /api/v1/forms/{form_key}/route/test` | write | `forms:write` | FormMappingEditor |
105
+ | `snippet.getOrgSnippet` | `GET /api/v1/snippet` | read | `integrations:read` | FormEmbed |
106
+ | `snippet.getFormTemplate` | `GET /api/v1/snippet/form` | read | `integrations:read` | FormEmbed |
107
+ | `forms.searchFormSubmissions` | `POST /api/v1/forms/{form_key}/submissions` | read | `forms:read` | SubmissionsTable |
108
+ | `forms.getFormSubmissionTrace` | `GET /api/v1/forms/{form_key}/submissions/{submission_id}/trace` | read | `forms:read` | SubmissionsTable |
109
+ | `forms.retryFormDelivery` | `POST /api/v1/forms/deliveries/{receipt_id}/retry` | external | `forms:run` | SubmissionsTable |
110
+ | `forms.getSiteAudit` | `GET /api/v1/forms/site-audit` | read | `forms:read` | SiteAuditPanel |
111
+ | `forms.requestSiteAuditScan` | `POST /api/v1/forms/site-audit/scan` | write | `forms:write` | SiteAuditPanel |
112
+ | `forms.updateSiteAuditFinding` | `PATCH /api/v1/forms/site-audit/findings/{finding_id}` | write | `forms:write` | SiteAuditPanel |