@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,157 @@
1
+ "use client";
2
+
3
+ /**
4
+ * VisitorFeed: who is on your site. Companies by default (identified from the visit), people when the
5
+ * visitor is a known contact. It is a polled feed: the API has no stream, so it reloads on a timer.
6
+ *
7
+ * SDK operations, in order:
8
+ * 1. listCompanyVisitorEvents GET /visitors/companies/events (read; show_mode=grouped)
9
+ * 2. listContactVisitorEvents GET /visitors/contacts/events (read; People tab, needs contacts:read too)
10
+ *
11
+ * Tiers: read only; no confirmation. Bots and internal traffic are excluded unless you pass
12
+ * `includeBots` / `includeInternal`. Poll interval: `pollSeconds` (default 30, 0 turns it off).
13
+ */
14
+
15
+ import { useEffect, useState } from "react";
16
+ import { Button, Skeleton } from "@graph8/sdk/ui";
17
+ import { g8Get } from "@/g8/lib/g8-client";
18
+ import { useG8Query } from "@/g8/hooks/use-g8-query";
19
+ import { ApiError } from "@/g8/components/api-error";
20
+ import { EmptyState } from "@/g8/components/empty-state";
21
+ import { VisitorCompanyCard } from "./visitor-company-card";
22
+ import { pageOf, personLabel, pageLabel, timeAgo } from "../lib/visitors-utils";
23
+ import type { VisitorGroup } from "../lib/visitors-utils";
24
+
25
+ export interface VisitorFeedProps {
26
+ pageSize?: number;
27
+ pollSeconds?: number;
28
+ includeBots?: boolean;
29
+ includeInternal?: boolean;
30
+ /** Which tab to open on. Default "companies". */
31
+ initialView?: "companies" | "people";
32
+ onSelectPerson?: (visit: VisitorGroup) => void;
33
+ className?: string;
34
+ }
35
+
36
+ type View = "companies" | "people";
37
+
38
+ export function VisitorFeed({
39
+ pageSize = 25,
40
+ pollSeconds = 30,
41
+ includeBots = false,
42
+ includeInternal = false,
43
+ initialView = "companies",
44
+ onSelectPerson,
45
+ className,
46
+ }: VisitorFeedProps) {
47
+ const [view, setView] = useState<View>(initialView);
48
+ // The page belongs to one set of inputs: a different tab, page size or bot/internal filter starts at page 1.
49
+ const scope = `${view}|${pageSize}|${includeBots}|${includeInternal}`;
50
+ const [pageState, setPageState] = useState({ scope, n: 1 });
51
+ const page = pageState.scope === scope ? pageState.n : 1;
52
+ const setPage = (update: number | ((p: number) => number)) =>
53
+ setPageState({ scope, n: typeof update === "function" ? update(page) : update });
54
+ const rawFeed = useG8Query(
55
+ async (signal) => ({
56
+ view,
57
+ res: await g8Get(
58
+ view === "companies" ? "/visitors/companies/events" : "/visitors/contacts/events",
59
+ { show_mode: "grouped", page, limit: pageSize, include_bots: includeBots, include_internal: includeInternal },
60
+ { signal },
61
+ ),
62
+ }),
63
+ [view, page, pageSize, includeBots, includeInternal],
64
+ );
65
+ // Rows fetched for the other tab must never render under this one (companies would show as "Unknown visitor").
66
+ const feed = { ...rawFeed, data: rawFeed.data?.view === view ? rawFeed.data.res : undefined };
67
+
68
+ useEffect(() => {
69
+ if (!pollSeconds) return;
70
+ const timer = setInterval(() => void feed.refetch(), pollSeconds * 1000);
71
+ return () => clearInterval(timer);
72
+ }, [pollSeconds, feed.refetch]);
73
+
74
+ const { events, total } = pageOf(feed.data);
75
+ const switchTo = (next: View) => {
76
+ setView(next);
77
+ setPage(1);
78
+ };
79
+
80
+ return (
81
+ <div className={`space-y-3 ${className ?? ""}`}>
82
+ <div className="flex items-center justify-between">
83
+ <div className="inline-flex gap-1" role="group" aria-label="Visitor type">
84
+ <Button
85
+ size="sm"
86
+ variant={view === "companies" ? "default" : "outline"}
87
+ aria-pressed={view === "companies"}
88
+ onClick={() => switchTo("companies")}
89
+ >
90
+ Companies
91
+ </Button>
92
+ <Button
93
+ size="sm"
94
+ variant={view === "people" ? "default" : "outline"}
95
+ aria-pressed={view === "people"}
96
+ onClick={() => switchTo("people")}
97
+ >
98
+ People
99
+ </Button>
100
+ </div>
101
+ <Button size="sm" variant="outline" disabled={feed.loading} onClick={() => void feed.refetch()}>
102
+ Refresh
103
+ </Button>
104
+ </div>
105
+
106
+ {feed.error ? (
107
+ <ApiError error={feed.error} onRetry={() => void feed.refetch()} />
108
+ ) : feed.loading && !feed.data ? (
109
+ <div className="space-y-2">
110
+ <Skeleton className="h-20 w-full" />
111
+ <Skeleton className="h-20 w-full" />
112
+ </div>
113
+ ) : events.length === 0 ? (
114
+ <EmptyState
115
+ title={view === "companies" ? "No company visits yet" : "No identified people yet"}
116
+ description="Visits appear once the graph8 snippet is on your site. Check the install in SnippetInstall."
117
+ />
118
+ ) : view === "companies" ? (
119
+ <div className="space-y-3">
120
+ {events.map((visit, i) => (
121
+ <VisitorCompanyCard key={`${visit.COMPANY_ID}-${visit.received_at}-${i}`} visit={visit} />
122
+ ))}
123
+ </div>
124
+ ) : (
125
+ <ul className="divide-y rounded border border-gray-200">
126
+ {events.map((visit, i) => (
127
+ <li key={`${visit.CONTACT_ID}-${visit.received_at}-${i}`}>
128
+ <button
129
+ type="button"
130
+ className="flex w-full items-center justify-between px-3 py-2 text-left text-sm hover:bg-gray-50"
131
+ onClick={() => onSelectPerson?.(visit)}
132
+ >
133
+ <span>
134
+ <span className="font-medium">{personLabel(visit)}</span>
135
+ <span className="ml-2 text-xs text-gray-500">{visit.children?.[0] ? pageLabel(visit.children[0]) : ""}</span>
136
+ </span>
137
+ <span className="text-xs text-gray-500">{timeAgo(visit.received_at)}</span>
138
+ </button>
139
+ </li>
140
+ ))}
141
+ </ul>
142
+ )}
143
+
144
+ <div className="flex items-center justify-between text-sm text-gray-600">
145
+ <span>{total.toLocaleString()} visits</span>
146
+ <div className="flex gap-2">
147
+ <Button size="sm" variant="outline" disabled={page <= 1 || feed.loading} onClick={() => setPage((p) => p - 1)}>
148
+ Previous
149
+ </Button>
150
+ <Button size="sm" variant="outline" disabled={feed.loading || page * pageSize >= total} onClick={() => setPage((p) => p + 1)}>
151
+ Next
152
+ </Button>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ );
157
+ }
@@ -0,0 +1,78 @@
1
+ "use client";
2
+
3
+ /**
4
+ * Types and helpers shared by the visitors components. Visitor payloads are open-shaped: the tracker adds
5
+ * fields over time and each feed carries a different set, so every field here is optional and the readers
6
+ * accept the upper-case names the grouped feeds use as well as lower-case ones.
7
+ */
8
+
9
+ /** One page view inside a visit. */
10
+ export interface FlowEvent {
11
+ message_id?: string;
12
+ received_at?: string;
13
+ page_title?: string | null;
14
+ page_path?: string | null;
15
+ page_host?: string | null;
16
+ page_referrer?: string | null;
17
+ sequence_name?: string | null;
18
+ }
19
+
20
+ /** A grouped company visit (`show_mode=grouped`) or a grouped person visit. */
21
+ export interface VisitorGroup {
22
+ COMPANY_ID?: number;
23
+ COMPANY_NAME?: string | null;
24
+ COMPANY_DOMAIN?: string | null;
25
+ CONTACT_ID?: number;
26
+ CONTACT_FIRST_NAME?: string | null;
27
+ CONTACT_LAST_NAME?: string | null;
28
+ received_at?: string;
29
+ children?: FlowEvent[];
30
+ }
31
+
32
+ export interface EventPage {
33
+ events: VisitorGroup[];
34
+ total: number;
35
+ }
36
+
37
+ /** `{ data: { events, total } }` -> the page, tolerating a missing body. */
38
+ export function pageOf(envelope: unknown): EventPage {
39
+ const data = (envelope as { data?: { events?: VisitorGroup[]; total?: number } } | null)?.data;
40
+ const events = data?.events ?? [];
41
+ return { events, total: data?.total ?? events.length };
42
+ }
43
+
44
+ export function companyLabel(g: VisitorGroup): string {
45
+ return g.COMPANY_NAME || g.COMPANY_DOMAIN || (g.COMPANY_ID != null ? `Company ${g.COMPANY_ID}` : "Unknown company");
46
+ }
47
+
48
+ export function personLabel(g: VisitorGroup): string {
49
+ const name = [g.CONTACT_FIRST_NAME, g.CONTACT_LAST_NAME].filter(Boolean).join(" ").trim();
50
+ return name || (g.CONTACT_ID != null ? `Contact ${g.CONTACT_ID}` : "Unknown visitor");
51
+ }
52
+
53
+ /** "3 min ago", "2 h ago", or a date for older visits. */
54
+ export function timeAgo(value: string | null | undefined, now = Date.now()): string {
55
+ if (!value) return "-";
56
+ const then = new Date(value).getTime();
57
+ if (Number.isNaN(then)) return value;
58
+ const minutes = Math.max(0, Math.round((now - then) / 60000));
59
+ if (minutes < 1) return "just now";
60
+ if (minutes < 60) return `${minutes} min ago`;
61
+ if (minutes < 60 * 24) return `${Math.round(minutes / 60)} h ago`;
62
+ return new Date(then).toLocaleDateString();
63
+ }
64
+
65
+ export function pageLabel(e: FlowEvent): string {
66
+ return e.page_title || e.page_path || e.page_host || "page";
67
+ }
68
+
69
+ /** Rows out of an analytics response (`data` array, `data.rows`/`items`, or a bare array). */
70
+ export function seriesOf<T>(envelope: unknown): T[] {
71
+ const data = (envelope as { data?: unknown } | null)?.data ?? envelope;
72
+ if (Array.isArray(data)) return data as T[];
73
+ const obj = data as Record<string, unknown> | null | undefined;
74
+ for (const key of ["rows", "items", "trend", "pages", "data"]) {
75
+ if (Array.isArray(obj?.[key])) return obj![key] as T[];
76
+ }
77
+ return [];
78
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @title Fetch the tracking snippet and confirm events are arriving
3
+ * @when Onboarding a website. The snippet's write key is PUBLIC (safe in page source). Installation is
4
+ * proven by events arriving, not by the page containing the tag, so poll `checkTrackingInstallation` after
5
+ * a human has loaded a page that has the snippet. Read tier, free.
6
+ */
7
+ import { g8 } from "@graph8/sdk";
8
+
9
+ g8.init({ apiKey: process.env.G8_API_KEY! });
10
+
11
+ export async function getSnippetAndWait(streamId?: string, attempts = 12) {
12
+ const snippet = await g8.api.snippet.getOrgSnippet({ query: { stream_id: streamId } });
13
+ const writeKey = snippet.data?.write_key;
14
+ if (!writeKey) throw new Error("No tracking stream: create a website stream in graph8 first");
15
+ console.log("Paste this into the site:\n", snippet.data?.script_tag);
16
+
17
+ for (let i = 0; i < attempts; i++) {
18
+ const check = await g8.api.visitors.checkTrackingInstallation({ query: { write_key: writeKey } });
19
+ const status = (check.data as { status?: string } | undefined)?.status;
20
+ if (status === "receiving") return { installed: true as const, writeKey };
21
+ await new Promise((resolve) => setTimeout(resolve, Math.min(15000, 3000 * 1.5 ** i)));
22
+ }
23
+ return { installed: false as const, writeKey };
24
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @title List the companies that visited your site recently
3
+ * @when Building a "who is on our site" view or a daily digest. `show_mode: "grouped"` returns one row per
4
+ * company with its page views under `children`. Bots and internal traffic are excluded by default. Read tier.
5
+ */
6
+ import { g8 } from "@graph8/sdk";
7
+
8
+ g8.init({ apiKey: process.env.G8_API_KEY! });
9
+
10
+ interface CompanyVisit {
11
+ COMPANY_ID?: number;
12
+ COMPANY_NAME?: string | null;
13
+ COMPANY_DOMAIN?: string | null;
14
+ received_at?: string;
15
+ children?: Array<{ page_path?: string | null }>;
16
+ }
17
+
18
+ export async function recentCompanyVisits(limit = 25) {
19
+ const res = await g8.api.visitors.listCompanyVisitorEvents({ query: { show_mode: "grouped", limit, page: 1 } });
20
+ const events = ((res.data as { events?: CompanyVisit[] } | undefined)?.events ?? []).map((v) => ({
21
+ companyId: v.COMPANY_ID,
22
+ name: v.COMPANY_NAME ?? v.COMPANY_DOMAIN,
23
+ lastSeen: v.received_at,
24
+ pages: (v.children ?? []).map((c) => c.page_path),
25
+ }));
26
+ return events;
27
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @title Summarise site traffic for the last N days
3
+ * @when A weekly report or a dashboard header. Three reads (no spend): the daily trend, the top pages and
4
+ * who is on the site right now. Pass a stream's write key to scope to one website.
5
+ */
6
+ import { g8 } from "@graph8/sdk";
7
+
8
+ g8.init({ apiKey: process.env.G8_API_KEY! });
9
+
10
+ export async function trafficSummary(days = 7, writeKey?: string) {
11
+ const scope = { days, write_key: writeKey };
12
+ const [trend, pages, live] = await Promise.all([
13
+ g8.api.webAnalytics.getAudienceTrend({ query: scope }),
14
+ g8.api.webAnalytics.getTopPages({ query: { ...scope, limit: 10 } }),
15
+ g8.api.webAnalytics.getRealtime({ query: { write_key: writeKey } }),
16
+ ]);
17
+ const rows = (trend.data as Array<{ date: string; users?: number; page_views?: number }> | undefined) ?? [];
18
+ return {
19
+ visitors: rows.reduce((sum, r) => sum + (r.users ?? 0), 0),
20
+ pageViews: rows.reduce((sum, r) => sum + (r.page_views ?? 0), 0),
21
+ topPages: pages.data,
22
+ liveNow: live.data,
23
+ };
24
+ }
@@ -0,0 +1,87 @@
1
+ # webchat
2
+
3
+ Configure the AI chat widget on your website and see who used it. `ChatWidgetConfig` manages chat bots, the widget's
4
+ look, starter questions and the embed code; `ConversationList` shows the widget's visitors and the engagement funnel.
5
+ Message threads and replies live in the `inbox` block.
6
+
7
+ ## Install
8
+
9
+ ```
10
+ npx @graph8/sdk add webchat
11
+ ```
12
+
13
+ Installs `foundation` and `crm` first if missing. Everything lands under `g8/webchat/`.
14
+
15
+ ## Prerequisites (the human must do these)
16
+
17
+ | Where | What | How to verify |
18
+ |---|---|---|
19
+ | Your site | Load the graph8 tracking snippet on the pages that should show the chat; the widget ships through it (`ChatWidgetConfig` displays the code). | The launcher appears on a page with the snippet. |
20
+ | graph8 workspace | An **answering agent** mapped to the bot. A bot with none answers nothing. | `GET /api/v1/webchat/agents?chat_bot_id=` lists an active agent. |
21
+ | Your app | `allowedPrefixes` must include `webchat` and `snippet`. | The route file lists both. |
22
+
23
+ ## The flow, in order (IDs passed between steps)
24
+
25
+ 1. `listChatBots` -> **`bot.id`**. This is the `chat_bot_id` of nearly every other call. `createChatBot({ name })` makes one.
26
+ 2. `getWebchatSettings(chat_bot_id, surface)` -> the current theme. A `404` means the bot has none yet: `createWebchatSettings` (POST, one row per bot and surface, `409` if it exists). Otherwise `updateWebchatSettings` (PATCH, partial).
27
+ **Saves are live**: the next visitor sees them, there is no publish step. Colours must be hex, sizes CSS lengths; an illegible text/background pair is a 422.
28
+ 3. `listWebchatQuestions(chat_bot_id)`, `createWebchatQuestion`, `deleteWebchatQuestion` (confirmed; pass `expected_revision` when you have it).
29
+ 4. `getOrgSnippet` -> `script_tag` to paste on your pages.
30
+ 5. `ConversationList`: `listWebchatVisitors` (paged, `identified_only`, `search`) and `getWebchatVisitorFunnel`.
31
+
32
+ ```tsx
33
+ // app/chat/page.tsx
34
+ "use client";
35
+ import { ChatWidgetConfig } from "@/g8/webchat/components/chat-widget-config";
36
+ import { ConversationList } from "@/g8/webchat/components/conversation-list";
37
+
38
+ export default function Page() {
39
+ return (<><ChatWidgetConfig /><ConversationList /></>);
40
+ }
41
+ ```
42
+
43
+ ## Default decisions (do not ask the human unless marked)
44
+
45
+ | Decision | Default | Ask? |
46
+ |---|---|---|
47
+ | Surface to style | `external` (public website) | no |
48
+ | First bot shown | The default bot, else the first | no |
49
+ | Colours | Leave unset unless the brand colours are known | **yes** |
50
+ | Saving | Live immediately; style a new bot before production pages load the snippet | no |
51
+
52
+ ## Things that surprise people
53
+
54
+ - **No conversations endpoint here.** Webchat has visitors and a funnel; the actual messages are inbox threads.
55
+ - **Responses are passed through and only partly typed.** The visitor columns (name, email, company, last seen) are read from whichever of several keys is present.
56
+ - **`abandonment_window_minutes` on the funnel is not applied by the API yet**, and `answer_feedback` / `conversation_abandoned` stages are absent rather than zero. Do not build on them.
57
+ - **Deleting settings** (`deleteWebchatSettings`) reverts to defaults, which every visitor sees at once. The block does not expose it.
58
+
59
+ ## Recipes (server-side, `recipes/`)
60
+
61
+ - `create-bot-and-style-widget.ts`: bot, theme, starter questions.
62
+ - `list-chat-visitors.ts`: identified visitors and the funnel.
63
+
64
+ ## What is in the block
65
+
66
+ | Component | File | What it is |
67
+ |---|---|---|
68
+ | `ChatWidgetConfig` | `components/chat-widget-config.tsx` | Pick or create a chat bot, style its widget, manage starter questions and copy the embed code. |
69
+ | `ConversationList` | `components/conversation-list.tsx` | People who used the widget, identified where possible, with the engagement funnel counts. |
70
+
71
+ ## Operations
72
+
73
+ Tiers: `read` and `write` need no confirmation; `destructive` always opens `ConfirmSpendDialog` first.
74
+
75
+ | Operation | Method and path | Tier | Scope | Used by |
76
+ |---|---|---|---|---|
77
+ | `webChat.listChatBots` | `GET /api/v1/webchat/chat-bots` | read | `inbox:read` | ChatWidgetConfig |
78
+ | `webChat.createChatBot` | `POST /api/v1/webchat/chat-bots` | write | `inbox:write` | ChatWidgetConfig |
79
+ | `webChat.getWebchatSettings` | `GET /api/v1/webchat/settings` | read | `inbox:read` | ChatWidgetConfig |
80
+ | `webChat.createWebchatSettings` | `POST /api/v1/webchat/settings` | write | `inbox:write` | ChatWidgetConfig |
81
+ | `webChat.updateWebchatSettings` | `PATCH /api/v1/webchat/settings` | write | `inbox:write` | ChatWidgetConfig |
82
+ | `webChat.listWebchatQuestions` | `GET /api/v1/webchat/questions` | read | `inbox:read` | ChatWidgetConfig |
83
+ | `webChat.createWebchatQuestion` | `POST /api/v1/webchat/questions` | write | `inbox:write` | ChatWidgetConfig |
84
+ | `webChat.deleteWebchatQuestion` | `DELETE /api/v1/webchat/questions/{question_id}` | destructive | `inbox:delete` | ChatWidgetConfig |
85
+ | `snippet.getOrgSnippet` | `GET /api/v1/snippet` | read | `integrations:read` | ChatWidgetConfig |
86
+ | `webChat.listWebchatVisitors` | `GET /api/v1/webchat/visitors` | read | `inbox:read` | ConversationList |
87
+ | `webChat.getWebchatVisitorFunnel` | `GET /api/v1/webchat/visitors/funnel` | read | `inbox:read` | ConversationList |
@@ -0,0 +1,134 @@
1
+ {
2
+ "$schema": "../block.schema.json",
3
+ "id": "webchat",
4
+ "title": "Web chat",
5
+ "summary": "Configure the website chat widget (bots, styling, starter questions, embed code) and see who used it.",
6
+ "features": [
7
+ "chat bots with a default",
8
+ "live widget styling with validation",
9
+ "starter questions",
10
+ "embed code from the tracking snippet",
11
+ "chat visitors list and engagement funnel"
12
+ ],
13
+ "dependsOn": [
14
+ "crm"
15
+ ],
16
+ "operations": [
17
+ "list_chat_bots_webchat_chat_bots_get",
18
+ "create_chat_bot_webchat_chat_bots_post",
19
+ "get_webchat_settings_webchat_settings_get",
20
+ "create_webchat_settings_webchat_settings_post",
21
+ "update_webchat_settings_webchat_settings_patch",
22
+ "list_webchat_questions_webchat_questions_get",
23
+ "create_webchat_question_webchat_questions_post",
24
+ "delete_webchat_question_webchat_questions__question_id__delete",
25
+ "get_org_snippet_snippet_get",
26
+ "list_webchat_visitors_webchat_visitors_get",
27
+ "get_webchat_visitor_funnel_webchat_visitors_funnel_get"
28
+ ],
29
+ "components": [
30
+ {
31
+ "name": "ChatWidgetConfig",
32
+ "file": "components/chat-widget-config.tsx",
33
+ "purpose": "Pick or create a chat bot, style its widget, manage starter questions and copy the embed code.",
34
+ "operations": [
35
+ "list_chat_bots_webchat_chat_bots_get",
36
+ "create_chat_bot_webchat_chat_bots_post",
37
+ "get_webchat_settings_webchat_settings_get",
38
+ "create_webchat_settings_webchat_settings_post",
39
+ "update_webchat_settings_webchat_settings_patch",
40
+ "list_webchat_questions_webchat_questions_get",
41
+ "create_webchat_question_webchat_questions_post",
42
+ "delete_webchat_question_webchat_questions__question_id__delete",
43
+ "get_org_snippet_snippet_get"
44
+ ],
45
+ "tiers": [
46
+ "read",
47
+ "write",
48
+ "destructive"
49
+ ]
50
+ },
51
+ {
52
+ "name": "ConversationList",
53
+ "file": "components/conversation-list.tsx",
54
+ "purpose": "People who used the widget, identified where possible, with the engagement funnel counts.",
55
+ "operations": [
56
+ "list_webchat_visitors_webchat_visitors_get",
57
+ "get_webchat_visitor_funnel_webchat_visitors_funnel_get"
58
+ ],
59
+ "tiers": [
60
+ "read"
61
+ ]
62
+ }
63
+ ],
64
+ "hooks": [],
65
+ "lib": [
66
+ {
67
+ "file": "lib/webchat-types.ts",
68
+ "purpose": "Bot, settings, question and visitor types with tolerant readers and colour/length validators."
69
+ }
70
+ ],
71
+ "recipes": [
72
+ {
73
+ "file": "recipes/create-bot-and-style-widget.ts",
74
+ "title": "Create a chat bot, style its widget, add starter questions",
75
+ "when": "First-time chat setup."
76
+ },
77
+ {
78
+ "file": "recipes/list-chat-visitors.ts",
79
+ "title": "List identified chat visitors and the funnel",
80
+ "when": "A daily pull of people who chatted, to route hot ones to sales."
81
+ }
82
+ ],
83
+ "prerequisites": [
84
+ {
85
+ "id": "snippet-on-site",
86
+ "description": "The graph8 tracking snippet must load on the pages that should show the chat; the widget ships through it. ChatWidgetConfig shows the code, a human or the agent pastes it into the site.",
87
+ "where": "app",
88
+ "verify": "The widget launcher appears on a page that loads the snippet."
89
+ },
90
+ {
91
+ "id": "answering-agent",
92
+ "description": "A chat bot answers nothing until an answering agent is mapped to it (POST /webchat/agents, or in the graph8 app). Build or pick the agent with the agents block or the app.",
93
+ "where": "api",
94
+ "verify": "GET /api/v1/webchat/agents?chat_bot_id= lists an active agent."
95
+ },
96
+ {
97
+ "id": "proxy-allowlist",
98
+ "description": "Add \"webchat\" and \"snippet\" to allowedPrefixes in app/api/g8/[...path]/route.ts.",
99
+ "where": "app",
100
+ "verify": "The route file's allowedPrefixes contains both."
101
+ }
102
+ ],
103
+ "scopes": [
104
+ "inbox:delete",
105
+ "inbox:read",
106
+ "inbox:write",
107
+ "integrations:read"
108
+ ],
109
+ "defaults": [
110
+ {
111
+ "decision": "Which surface to style",
112
+ "default": "external (the public website widget)",
113
+ "askHuman": false
114
+ },
115
+ {
116
+ "decision": "Which bot to open first",
117
+ "default": "The default bot, else the first",
118
+ "askHuman": false
119
+ },
120
+ {
121
+ "decision": "Widget colours",
122
+ "default": "Leave unset (graph8 defaults) unless the brand colours are known",
123
+ "askHuman": true
124
+ },
125
+ {
126
+ "decision": "Saving widget settings",
127
+ "default": "Saves are live immediately; style a new bot before production pages load the snippet",
128
+ "askHuman": false
129
+ }
130
+ ],
131
+ "peerDependencies": {
132
+ "react": ">=18"
133
+ }
134
+ }