@funnelsgrove/cli 0.1.15 → 0.1.18

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 (293) hide show
  1. package/contracts/step-contract-v2.json +733 -0
  2. package/dist/analyticsOutput.d.ts +30 -15
  3. package/dist/analyticsOutput.js +45 -28
  4. package/dist/apiClient.d.ts +85 -0
  5. package/dist/apiClient.js +225 -8
  6. package/dist/cli.d.ts +149 -1
  7. package/dist/cli.js +1232 -71
  8. package/dist/diagnosticOutput.d.ts +42 -0
  9. package/dist/diagnosticOutput.js +83 -0
  10. package/dist/docsOutput.d.ts +19 -0
  11. package/dist/docsOutput.js +73 -0
  12. package/dist/docsTransaction.d.ts +81 -0
  13. package/dist/docsTransaction.js +1755 -0
  14. package/dist/funnelValidation.d.ts +14 -0
  15. package/dist/funnelValidation.js +297 -0
  16. package/dist/localSync.d.ts +79 -0
  17. package/dist/localSync.js +400 -29
  18. package/dist/projectValidator.d.ts +27 -0
  19. package/dist/projectValidator.js +208 -0
  20. package/dist/reskin.js +27 -1
  21. package/dist/stepContractMigration.d.ts +71 -0
  22. package/dist/stepContractMigration.js +1323 -0
  23. package/dist/templateDocs.js +8 -25
  24. package/docs-release-history.json +66 -0
  25. package/legacy-docs-catalog.json +1012 -0
  26. package/package.json +13 -4
  27. package/template_docs/.funnelsgrove-docs.json +144 -0
  28. package/template_docs/AGENTS.md +30 -58
  29. package/template_docs/CLAUDE.md +0 -2
  30. package/template_docs/docs/funnelsgrove/START-HERE.md +73 -0
  31. package/template_docs/docs/funnelsgrove/contracts/analytics-events.md +59 -0
  32. package/template_docs/docs/funnelsgrove/contracts/content-answers.md +44 -0
  33. package/template_docs/docs/funnelsgrove/contracts/flow-routing.md +41 -0
  34. package/template_docs/docs/funnelsgrove/contracts/payments.md +42 -0
  35. package/template_docs/docs/funnelsgrove/contracts/step-metadata.md +57 -0
  36. package/template_docs/docs/funnelsgrove/migrations/step-contract-v3.md +39 -0
  37. package/template_docs/docs/funnelsgrove/qa/analytics.md +43 -0
  38. package/template_docs/docs/funnelsgrove/qa/local.md +42 -0
  39. package/template_docs/docs/funnelsgrove/qa/paywall-checkout.md +55 -0
  40. package/template_docs/docs/funnelsgrove/qa/publish.md +32 -0
  41. package/template_docs/docs/funnelsgrove/recipes/add-experiment.md +34 -0
  42. package/template_docs/docs/funnelsgrove/recipes/add-step.md +33 -0
  43. package/template_docs/docs/funnelsgrove/recipes/edit-step.md +31 -0
  44. package/template_docs/docs/funnelsgrove/steps/INDEX.md +26 -0
  45. package/template_docs/docs/funnelsgrove/steps/cancellation_offer.md +112 -0
  46. package/template_docs/docs/funnelsgrove/steps/checkout.md +120 -0
  47. package/template_docs/docs/funnelsgrove/steps/form_input.md +115 -0
  48. package/template_docs/docs/funnelsgrove/steps/intro_hero.md +110 -0
  49. package/template_docs/docs/funnelsgrove/steps/multi_select_choice.md +123 -0
  50. package/template_docs/docs/funnelsgrove/steps/paywall_offer.md +115 -0
  51. package/template_docs/docs/funnelsgrove/steps/progress_interstitial.md +111 -0
  52. package/template_docs/docs/funnelsgrove/steps/purchase_completed.md +117 -0
  53. package/template_docs/docs/funnelsgrove/steps/single_step_choice.md +122 -0
  54. package/template_docs/docs/funnelsgrove/steps/single_step_choice_emoji.md +122 -0
  55. package/template_docs/docs/funnelsgrove/steps/social_proof.md +110 -0
  56. package/template_docs/docs/funnelsgrove/steps/subscription_handoff.md +113 -0
  57. package/template_docs/docs/funnelsgrove/steps/subscription_management.md +112 -0
  58. package/template_docs/docs/funnelsgrove/steps/summary_confirmation.md +110 -0
  59. package/template_docs/docs/funnelsgrove/steps/upsell_offer.md +112 -0
  60. package/template_docs/docs/funnelsgrove/steps/value_prop_story.md +110 -0
  61. package/template_docs/funnel-docs.config.json +43 -0
  62. package/template_scaffold/.env.example +41 -0
  63. package/template_scaffold/.funnelsgrove-contract-tools.json +19 -0
  64. package/template_scaffold/.funnelsgrove-docs.json +144 -0
  65. package/template_scaffold/.funnelsgrove-scaffold.json +1078 -0
  66. package/template_scaffold/AGENTS.md +42 -0
  67. package/template_scaffold/CLAUDE.md +1 -0
  68. package/template_scaffold/PLAN.md +81 -0
  69. package/template_scaffold/PRODUCT_SENSE.md +28 -0
  70. package/template_scaffold/context/build-context.md +34 -0
  71. package/template_scaffold/docs/AGENT_FUNNEL_IMPLEMENTATION_SPEC.md +5 -0
  72. package/template_scaffold/docs/ARCHITECTURE.md +5 -0
  73. package/template_scaffold/docs/FLOW_CONFIG_AND_ROUTING.md +5 -0
  74. package/template_scaffold/docs/PAYWALL_AND_PAYMENTS.md +5 -0
  75. package/template_scaffold/docs/README.md +5 -0
  76. package/template_scaffold/docs/funnelsgrove/START-HERE.md +73 -0
  77. package/template_scaffold/docs/funnelsgrove/contracts/analytics-events.md +59 -0
  78. package/template_scaffold/docs/funnelsgrove/contracts/content-answers.md +44 -0
  79. package/template_scaffold/docs/funnelsgrove/contracts/flow-routing.md +41 -0
  80. package/template_scaffold/docs/funnelsgrove/contracts/payments.md +42 -0
  81. package/template_scaffold/docs/funnelsgrove/contracts/step-metadata.md +57 -0
  82. package/template_scaffold/docs/funnelsgrove/migrations/step-contract-v3.md +39 -0
  83. package/template_scaffold/docs/funnelsgrove/qa/analytics.md +43 -0
  84. package/template_scaffold/docs/funnelsgrove/qa/local.md +42 -0
  85. package/template_scaffold/docs/funnelsgrove/qa/paywall-checkout.md +55 -0
  86. package/template_scaffold/docs/funnelsgrove/qa/publish.md +32 -0
  87. package/template_scaffold/docs/funnelsgrove/recipes/add-experiment.md +34 -0
  88. package/template_scaffold/docs/funnelsgrove/recipes/add-step.md +33 -0
  89. package/template_scaffold/docs/funnelsgrove/recipes/edit-step.md +31 -0
  90. package/template_scaffold/docs/funnelsgrove/steps/INDEX.md +26 -0
  91. package/template_scaffold/docs/funnelsgrove/steps/cancellation_offer.md +112 -0
  92. package/template_scaffold/docs/funnelsgrove/steps/checkout.md +120 -0
  93. package/template_scaffold/docs/funnelsgrove/steps/form_input.md +115 -0
  94. package/template_scaffold/docs/funnelsgrove/steps/intro_hero.md +110 -0
  95. package/template_scaffold/docs/funnelsgrove/steps/multi_select_choice.md +123 -0
  96. package/template_scaffold/docs/funnelsgrove/steps/paywall_offer.md +115 -0
  97. package/template_scaffold/docs/funnelsgrove/steps/progress_interstitial.md +111 -0
  98. package/template_scaffold/docs/funnelsgrove/steps/purchase_completed.md +117 -0
  99. package/template_scaffold/docs/funnelsgrove/steps/single_step_choice.md +122 -0
  100. package/template_scaffold/docs/funnelsgrove/steps/single_step_choice_emoji.md +122 -0
  101. package/template_scaffold/docs/funnelsgrove/steps/social_proof.md +110 -0
  102. package/template_scaffold/docs/funnelsgrove/steps/subscription_handoff.md +113 -0
  103. package/template_scaffold/docs/funnelsgrove/steps/subscription_management.md +112 -0
  104. package/template_scaffold/docs/funnelsgrove/steps/summary_confirmation.md +110 -0
  105. package/template_scaffold/docs/funnelsgrove/steps/upsell_offer.md +112 -0
  106. package/template_scaffold/docs/funnelsgrove/steps/value_prop_story.md +110 -0
  107. package/template_scaffold/docs/references/funnel-sdk-user-answers.md +5 -0
  108. package/template_scaffold/eslint.config.mjs +16 -0
  109. package/template_scaffold/funnel-agent-docs.test.ts +699 -0
  110. package/template_scaffold/funnel-docs.config.json +43 -0
  111. package/template_scaffold/funnel.config.json +5 -0
  112. package/template_scaffold/gitignore.template +5 -0
  113. package/template_scaffold/next-env.d.ts +6 -0
  114. package/template_scaffold/next.config.ts +53 -0
  115. package/template_scaffold/package-lock.json +7737 -0
  116. package/template_scaffold/package.json +37 -0
  117. package/template_scaffold/package.test.ts +23 -0
  118. package/template_scaffold/public/claimbee/bee.png +0 -0
  119. package/template_scaffold/public/claimbee/device-iphone.png +0 -0
  120. package/template_scaffold/public/claimbee/device-macbook.png +0 -0
  121. package/template_scaffold/public/claimbee/device-none.png +0 -0
  122. package/template_scaffold/public/claimbee/device-watch.png +0 -0
  123. package/template_scaffold/public/claimbee/glow.svg +3 -0
  124. package/template_scaffold/public/claimbee/steps-sprite-alt.png +0 -0
  125. package/template_scaffold/public/claimbee/steps-sprite-default.png +0 -0
  126. package/template_scaffold/public/claimbee/testimonial-avatar.png +0 -0
  127. package/template_scaffold/public/claimbee/testimonial-star.svg +3 -0
  128. package/template_scaffold/public/paywall/ai-claim-assistant.png +0 -0
  129. package/template_scaffold/public/paywall/claim-history.png +0 -0
  130. package/template_scaffold/public/paywall/clear-progress.png +0 -0
  131. package/template_scaffold/public/paywall/hero.png +0 -0
  132. package/template_scaffold/public/paywall/money-alerts.png +0 -0
  133. package/template_scaffold/public/paywall/money-back-badge.png +0 -0
  134. package/template_scaffold/public/paywall/paywall-image.png +0 -0
  135. package/template_scaffold/public/paywall/r1.png +0 -0
  136. package/template_scaffold/public/paywall/r2.png +0 -0
  137. package/template_scaffold/public/paywall/r3.png +0 -0
  138. package/template_scaffold/public/paywall/r4.png +0 -0
  139. package/template_scaffold/public/paywall/r5.png +0 -0
  140. package/template_scaffold/public/paywall/r6.png +0 -0
  141. package/template_scaffold/public/paywall/special-offer-gift.png +0 -0
  142. package/template_scaffold/public/please/bee.png +0 -0
  143. package/template_scaffold/public/please/device-iphone.png +0 -0
  144. package/template_scaffold/public/please/device-macbook.png +0 -0
  145. package/template_scaffold/public/please/device-none.png +0 -0
  146. package/template_scaffold/public/please/device-watch.png +0 -0
  147. package/template_scaffold/public/please/glow.svg +3 -0
  148. package/template_scaffold/public/please/steps-sprite-alt.png +0 -0
  149. package/template_scaffold/public/please/steps-sprite-default.png +0 -0
  150. package/template_scaffold/public/please/testimonial-avatar.png +0 -0
  151. package/template_scaffold/public/please/testimonial-star.svg +3 -0
  152. package/template_scaffold/public/upsell/upgrade-hero.png +0 -0
  153. package/template_scaffold/src/app/[stepId]/page.test.tsx +59 -0
  154. package/template_scaffold/src/app/[stepId]/page.tsx +62 -0
  155. package/template_scaffold/src/app/globals.css +49 -0
  156. package/template_scaffold/src/app/layout.test.ts +26 -0
  157. package/template_scaffold/src/app/layout.tsx +61 -0
  158. package/template_scaffold/src/app/page.tsx +8 -0
  159. package/template_scaffold/src/app/sdk/page.tsx +673 -0
  160. package/template_scaffold/src/app/subscription-dashboard/page.tsx +274 -0
  161. package/template_scaffold/src/assets/claimbee/bee.png +0 -0
  162. package/template_scaffold/src/assets/claimbee/device-iphone.png +0 -0
  163. package/template_scaffold/src/assets/claimbee/device-macbook.png +0 -0
  164. package/template_scaffold/src/assets/claimbee/device-none.png +0 -0
  165. package/template_scaffold/src/assets/claimbee/device-watch.png +0 -0
  166. package/template_scaffold/src/assets/claimbee/glow.svg +3 -0
  167. package/template_scaffold/src/assets/claimbee/steps-sprite-alt.png +0 -0
  168. package/template_scaffold/src/assets/claimbee/steps-sprite-default.png +0 -0
  169. package/template_scaffold/src/assets/claimbee/testimonial-avatar.png +0 -0
  170. package/template_scaffold/src/assets/claimbee/testimonial-star.svg +3 -0
  171. package/template_scaffold/src/components/FunnelEditorPanel.tsx +194 -0
  172. package/template_scaffold/src/components/FunnelFlow.test.tsx +17 -0
  173. package/template_scaffold/src/components/FunnelFlow.tsx +114 -0
  174. package/template_scaffold/src/components/FunnelStepImage.test.ts +15 -0
  175. package/template_scaffold/src/components/FunnelStepImage.tsx +28 -0
  176. package/template_scaffold/src/components/step/FunnelStepHeader.tsx +35 -0
  177. package/template_scaffold/src/config/billing.plans.test.ts +143 -0
  178. package/template_scaffold/src/config/billing.plans.ts +69 -0
  179. package/template_scaffold/src/config/billing.test.plans.ts +32 -0
  180. package/template_scaffold/src/config/experiments.generated.ts +4 -0
  181. package/template_scaffold/src/config/experiments.test.ts +12 -0
  182. package/template_scaffold/src/config/experiments.ts +9 -0
  183. package/template_scaffold/src/config/funnel.config.ts +12 -0
  184. package/template_scaffold/src/config/funnel.manifest.test.ts +166 -0
  185. package/template_scaffold/src/config/funnel.manifest.ts +139 -0
  186. package/template_scaffold/src/config/offer-sets.generated.ts +4 -0
  187. package/template_scaffold/src/contract/funnel-project.validation.test.ts +80 -0
  188. package/template_scaffold/src/contract/funnel-project.validation.ts +44 -0
  189. package/template_scaffold/src/contract/funnel-validator.vite.config.ts +11 -0
  190. package/template_scaffold/src/contract/golden/cancellation_offer.fixture.ts +29 -0
  191. package/template_scaffold/src/contract/golden/checkout.fixture.ts +37 -0
  192. package/template_scaffold/src/contract/golden/form_input.fixture.ts +28 -0
  193. package/template_scaffold/src/contract/golden/golden-fixtures.test.ts +190 -0
  194. package/template_scaffold/src/contract/golden/intro_hero.fixture.ts +27 -0
  195. package/template_scaffold/src/contract/golden/multi_select_choice.fixture.ts +37 -0
  196. package/template_scaffold/src/contract/golden/paywall_offer.fixture.ts +30 -0
  197. package/template_scaffold/src/contract/golden/progress_interstitial.fixture.ts +28 -0
  198. package/template_scaffold/src/contract/golden/purchase_completed.fixture.ts +33 -0
  199. package/template_scaffold/src/contract/golden/single_step_choice.fixture.ts +36 -0
  200. package/template_scaffold/src/contract/golden/single_step_choice_emoji.fixture.ts +36 -0
  201. package/template_scaffold/src/contract/golden/social_proof.fixture.ts +27 -0
  202. package/template_scaffold/src/contract/golden/subscription_handoff.fixture.ts +30 -0
  203. package/template_scaffold/src/contract/golden/subscription_management.fixture.ts +29 -0
  204. package/template_scaffold/src/contract/golden/summary_confirmation.fixture.ts +27 -0
  205. package/template_scaffold/src/contract/golden/upsell_offer.fixture.ts +29 -0
  206. package/template_scaffold/src/contract/golden/value_prop_story.fixture.ts +27 -0
  207. package/template_scaffold/src/contract/validate-funnel.cli.test.ts +180 -0
  208. package/template_scaffold/src/contract/validate-funnel.cli.ts +199 -0
  209. package/template_scaffold/src/runtime/checkout-runtime-config.test.ts +60 -0
  210. package/template_scaffold/src/runtime/checkout-runtime-config.ts +26 -0
  211. package/template_scaffold/src/runtime/funnel-runtime.test.ts +25 -0
  212. package/template_scaffold/src/runtime/funnel-runtime.ts +118 -0
  213. package/template_scaffold/src/runtime/step-content-context.test.ts +38 -0
  214. package/template_scaffold/src/runtime/step-content-context.ts +65 -0
  215. package/template_scaffold/src/runtime/step-registry.ts +66 -0
  216. package/template_scaffold/src/runtime/step-variable-values.ts +31 -0
  217. package/template_scaffold/src/runtime/use-funnel-flow-controller.integration.test.ts +203 -0
  218. package/template_scaffold/src/runtime/use-funnel-flow-controller.test.ts +76 -0
  219. package/template_scaffold/src/runtime/use-funnel-flow-controller.ts +53 -0
  220. package/template_scaffold/src/steps/content/email-capture.content.ts +29 -0
  221. package/template_scaffold/src/steps/content/manage-subscription.content.ts +62 -0
  222. package/template_scaffold/src/steps/content/paywall.content.ts +191 -0
  223. package/template_scaffold/src/steps/content/step-01.content.ts +23 -0
  224. package/template_scaffold/src/steps/content/step-02.content.ts +77 -0
  225. package/template_scaffold/src/steps/content/step-03.content.ts +40 -0
  226. package/template_scaffold/src/steps/content/step-04.content.ts +49 -0
  227. package/template_scaffold/src/steps/content/step-32-paywall.content.ts +352 -0
  228. package/template_scaffold/src/steps/content/subscription-started.content.ts +68 -0
  229. package/template_scaffold/src/steps/editor/email-capture.editor.ts +58 -0
  230. package/template_scaffold/src/steps/editor/manage-subscription.editor.ts +179 -0
  231. package/template_scaffold/src/steps/editor/paywall.editor.ts +232 -0
  232. package/template_scaffold/src/steps/editor/step-01.editor.ts +22 -0
  233. package/template_scaffold/src/steps/editor/step-02.editor.ts +41 -0
  234. package/template_scaffold/src/steps/editor/step-03.editor.ts +58 -0
  235. package/template_scaffold/src/steps/editor/step-04.editor.ts +98 -0
  236. package/template_scaffold/src/steps/editor/step-32-paywall.editor.ts +478 -0
  237. package/template_scaffold/src/steps/editor/subscription-started.editor.ts +131 -0
  238. package/template_scaffold/src/steps/index.ts +25 -0
  239. package/template_scaffold/src/steps/paywall-checkout-options.test.ts +104 -0
  240. package/template_scaffold/src/steps/paywall-checkout-options.ts +130 -0
  241. package/template_scaffold/src/steps/pricing/paywall-b.pricing.ts +12 -0
  242. package/template_scaffold/src/steps/pricing/paywall.pricing.ts +12 -0
  243. package/template_scaffold/src/steps/pricing/shared-plan-order.ts +17 -0
  244. package/template_scaffold/src/steps/pricing/upsell-form.pricing.ts +16 -0
  245. package/template_scaffold/src/steps/shared-header-contract.test.ts +27 -0
  246. package/template_scaffold/src/steps/step-01.test.ts +38 -0
  247. package/template_scaffold/src/steps/step-01.tsx +108 -0
  248. package/template_scaffold/src/steps/step-02.test.ts +43 -0
  249. package/template_scaffold/src/steps/step-02.tsx +140 -0
  250. package/template_scaffold/src/steps/step-03.test.ts +15 -0
  251. package/template_scaffold/src/steps/step-03.tsx +262 -0
  252. package/template_scaffold/src/steps/step-04.test.ts +32 -0
  253. package/template_scaffold/src/steps/step-04.tsx +673 -0
  254. package/template_scaffold/src/steps/step-31-email-capture.test.ts +22 -0
  255. package/template_scaffold/src/steps/step-31-email-capture.tsx +195 -0
  256. package/template_scaffold/src/steps/step-32-paywall.test.ts +770 -0
  257. package/template_scaffold/src/steps/step-32-paywall.tsx +2253 -0
  258. package/template_scaffold/src/steps/step-32b-paywall-b.tsx +35 -0
  259. package/template_scaffold/src/steps/step-33-subscription-started.test.ts +26 -0
  260. package/template_scaffold/src/steps/step-33-subscription-started.tsx +86 -0
  261. package/template_scaffold/src/steps/step-34-upsell-form.test.ts +27 -0
  262. package/template_scaffold/src/steps/step-35-manage-subscription.tsx +46 -0
  263. package/template_scaffold/src/steps/step-content.registry.ts +45 -0
  264. package/template_scaffold/src/steps/step-image-migration.test.ts +20 -0
  265. package/template_scaffold/src/steps/styles/index.css +2 -0
  266. package/template_scaffold/src/steps/styles/shared/final-flow-shared.css +55 -0
  267. package/template_scaffold/src/steps/styles/shared/funnel-base.css +543 -0
  268. package/template_scaffold/src/steps/styles/shared/info-shared.css +139 -0
  269. package/template_scaffold/src/steps/styles/shared/progress-shared.css +117 -0
  270. package/template_scaffold/src/steps/styles/shared/question-shared.css +76 -0
  271. package/template_scaffold/src/steps/styles/shared/responsive-container.css +176 -0
  272. package/template_scaffold/src/steps/types.ts +7 -0
  273. package/template_scaffold/src/steps/use-claimbee-step-content.ts +15 -0
  274. package/template_scaffold/src/theme/theme.ts +81 -0
  275. package/template_scaffold/tsconfig.json +38 -0
  276. package/template_scaffold/vitest.config.ts +32 -0
  277. package/template_validation/.funnelsgrove-contract-tools.json +19 -0
  278. package/template_validation/src/contract/funnel-project.validation.ts +44 -0
  279. package/template_validation/src/contract/funnel-validator.vite.config.ts +11 -0
  280. package/template_validation/src/contract/validate-funnel.cli.ts +199 -0
  281. package/template_docs/docs/ab-experiments.md +0 -111
  282. package/template_docs/docs/analytics.md +0 -65
  283. package/template_docs/docs/editing-flow.md +0 -136
  284. package/template_docs/docs/editing-step.md +0 -125
  285. package/template_docs/docs/editor-and-content.md +0 -58
  286. package/template_docs/docs/funnel-runtime-architecture.md +0 -125
  287. package/template_docs/docs/meta-pixel-conversions-api.md +0 -50
  288. package/template_docs/docs/payment-plans-and-discounts.md +0 -106
  289. package/template_docs/docs/publishing-and-versioning.md +0 -117
  290. package/template_docs/docs/qa-checklist.md +0 -80
  291. package/template_docs/docs/sdk-api-endpoints.md +0 -78
  292. package/template_docs/docs/step-ui-guidelines.md +0 -110
  293. package/template_docs/docs/theme.md +0 -35
@@ -0,0 +1,673 @@
1
+ import type { Metadata } from 'next';
2
+
3
+ export const metadata: Metadata = {
4
+ title: 'Funnel SDK Docs',
5
+ description: 'User answers object, useFunnel runtime reference, and analytics SDK usage for this project.',
6
+ };
7
+
8
+ const userObjectExample = `{
9
+ "selectedDevices": ["iphone", "laptop"],
10
+ "stepChoices": {
11
+ "step-1": "yes",
12
+ "step-3": "no"
13
+ },
14
+ "upsellAccepted": true,
15
+ "upsellEmail": "user@example.com",
16
+ "upsellSelectedPlanId": "price_yearly_123",
17
+ "selectedPaywallPlanId": "price_yearly_123",
18
+ "manageSubscriptionHasActive": true,
19
+ "manageSubscriptionReason": "cost",
20
+ "manageSubscriptionCancelled": false,
21
+ "manageSubscriptionCancelledId": ""
22
+ }`;
23
+
24
+ type MethodDoc = {
25
+ id: string;
26
+ name: string;
27
+ signature: string;
28
+ description: string;
29
+ example: string;
30
+ };
31
+
32
+ const methodDocs: MethodDoc[] = [
33
+ {
34
+ id: 'active-step-id',
35
+ name: 'activeStepId',
36
+ signature: 'activeStepId: FunnelStepId',
37
+ description: 'Current rendered step id in the runtime shell.',
38
+ example: `const { activeStepId } = useFunnel();
39
+
40
+ if (activeStepId === 'step-4') {
41
+ // Step-specific behavior
42
+ }`,
43
+ },
44
+ {
45
+ id: 'answers',
46
+ name: 'answers',
47
+ signature: 'answers: FunnelUserAnswers',
48
+ description: 'Typed answers object persisted across steps.',
49
+ example: `const { answers } = useFunnel();
50
+ const selectedDevices = answers.selectedDevices || [];`,
51
+ },
52
+ {
53
+ id: 'set-answer',
54
+ name: 'setAnswer',
55
+ signature:
56
+ "setAnswer<K extends keyof FunnelUserAnswers>(key: K, value: FunnelUserAnswers[K]): void",
57
+ description: 'Typed way to write answer values.',
58
+ example: `const { setAnswer } = useFunnel();
59
+
60
+ setAnswer('selectedDevices', ['iphone', 'watch']);
61
+ setAnswer('upsellAccepted', true);`,
62
+ },
63
+ {
64
+ id: 'get-answer',
65
+ name: 'getAnswer',
66
+ signature:
67
+ 'getAnswer<K extends keyof FunnelUserAnswers>(key: K): FunnelUserAnswers[K] | undefined',
68
+ description: 'Typed getter for a single answer key.',
69
+ example: `const { getAnswer } = useFunnel();
70
+ const reason = getAnswer('manageSubscriptionReason');`,
71
+ },
72
+ {
73
+ id: 'go-next',
74
+ name: 'goNext',
75
+ signature: 'goNext(): void',
76
+ description: 'Navigate to configured next step based on routing and current answers.',
77
+ example: `const { goNext } = useFunnel();
78
+
79
+ <button type='button' onClick={goNext}>
80
+ Continue
81
+ </button>`,
82
+ },
83
+ {
84
+ id: 'go-to-step',
85
+ name: 'goToStep',
86
+ signature: 'goToStep(stepId: string, outcome: FunnelNavigationOutcome): void',
87
+ description: 'Imperative navigation to a specific step id.',
88
+ example: `const { goToStep } = useFunnel();
89
+ goToStep('paywall', { type: 'complete' });`,
90
+ },
91
+ {
92
+ id: 'get-choice-targets',
93
+ name: 'getChoiceTargets',
94
+ signature: 'getChoiceTargets(stepId?: string): { yes: FunnelStepId; no: FunnelStepId } | null',
95
+ description: 'Read yes/no branch targets from routing config.',
96
+ example: `const { getChoiceTargets } = useFunnel();
97
+ const choiceTargets = getChoiceTargets();`,
98
+ },
99
+ {
100
+ id: 'go-choice',
101
+ name: 'goChoice',
102
+ signature: "goChoice(choice: 'yes' | 'no', stepId?: string): void",
103
+ description:
104
+ 'Record a binary choice and route using configured choice targets with fallback logic.',
105
+ example: `const { goChoice } = useFunnel();
106
+
107
+ <button type='button' onClick={() => goChoice('yes')}>
108
+ Yes
109
+ </button>`,
110
+ },
111
+ {
112
+ id: 'user',
113
+ name: 'user',
114
+ signature: 'user: FunnelUser',
115
+ description: 'Current SDK user profile and historical completed steps.',
116
+ example: `const { user } = useFunnel();
117
+ const userEmail = user.email;`,
118
+ },
119
+ {
120
+ id: 'set-user',
121
+ name: 'setUser',
122
+ signature: 'setUser(user: FunnelUser): void',
123
+ description: 'Replace user object (advanced/rare use only).',
124
+ example: `const { user, setUser } = useFunnel();
125
+ setUser({ ...user, email: 'new-email@example.com' });`,
126
+ },
127
+ {
128
+ id: 'complete-step',
129
+ name: 'completeStep',
130
+ signature: 'completeStep(stepId: string, choices?: Record<string, unknown>): void',
131
+ description: 'Manually emit and persist a step completion record.',
132
+ example: `const { completeStep } = useFunnel();
133
+
134
+ completeStep('step-2', {
135
+ selectedDevices: ['iphone', 'laptop'],
136
+ });`,
137
+ },
138
+ {
139
+ id: 'complete-funnel',
140
+ name: 'completeFunnel',
141
+ signature: 'completeFunnel(stepId: string): void',
142
+ description: 'Complete the active terminal step and emit the canonical funnel conversion once.',
143
+ example: `const { completeFunnel } = useFunnel();
144
+
145
+ completeFunnel('subscription-started');`,
146
+ },
147
+ {
148
+ id: 'legacy-attributes',
149
+ name: 'attributes / setAttribute',
150
+ signature:
151
+ 'attributes: FunnelUserAnswers, setAttribute(key: string, value: unknown): void (compat)',
152
+ description: 'Compatibility aliases for older step implementations.',
153
+ example: `const { attributes, setAttribute } = useFunnel();
154
+
155
+ setAttribute('legacyCustomKey', true);
156
+ const value = attributes.legacyCustomKey;`,
157
+ },
158
+ ];
159
+
160
+ const quickStartExample = `import { useFunnel } from '@funnelsgrove/runtime';
161
+
162
+ export function ExampleStep() {
163
+ const { answers, setAnswer, goNext } = useFunnel();
164
+
165
+ return (
166
+ <button
167
+ type='button'
168
+ onClick={() => {
169
+ setAnswer('selectedDevices', ['iphone']);
170
+ goNext();
171
+ }}
172
+ >
173
+ Continue
174
+ </button>
175
+ );
176
+ }`;
177
+
178
+ type AnalyticsMethodDoc = {
179
+ id: string;
180
+ name: string;
181
+ signature: string;
182
+ description: string;
183
+ example: string;
184
+ };
185
+
186
+ type AnalyticsUseCaseDoc = {
187
+ id: string;
188
+ title: string;
189
+ description: string;
190
+ example: string;
191
+ };
192
+
193
+ const analyticsQuickStartExample = `import {
194
+ bootstrapPublicAnalyticsUser,
195
+ publicAnalyticsSdk,
196
+ } from '@funnelsgrove/analytics';
197
+
198
+ export async function initializeAnalytics() {
199
+ await bootstrapPublicAnalyticsUser({
200
+ email: 'user@example.com',
201
+ metadata: { source: 'landing' },
202
+ });
203
+
204
+ publicAnalyticsSdk.track({
205
+ eventType: 'funnel_opened',
206
+ stepId: 'step-1',
207
+ stepName: 'Welcome',
208
+ });
209
+ }`;
210
+
211
+ const analyticsUseCases: AnalyticsUseCaseDoc[] = [
212
+ {
213
+ id: 'analytics-use-case-cta',
214
+ title: 'Track CTA clicks and plan picks',
215
+ description: 'Capture conversion intent (button clicks, plan id, variant id) without blocking UI.',
216
+ example: `publicAnalyticsSdk.track({
217
+ eventType: 'cta_click',
218
+ stepId: 'paywall',
219
+ stepName: 'Paywall',
220
+ payload: {
221
+ cta: 'start_trial',
222
+ planId: selectedPlanId,
223
+ experimentVariant: 'v2',
224
+ },
225
+ });`,
226
+ },
227
+ {
228
+ id: 'analytics-use-case-step-override',
229
+ title: 'Complete custom interactions through FunnelFlow',
230
+ description: 'FunnelFlow owns step timing and lifecycle events, including long-running custom interactions.',
231
+ example: `const { goToStep } = useFunnel();
232
+
233
+ // ...custom async flow...
234
+
235
+ goToStep('step-7', {
236
+ type: 'complete',
237
+ selected: { uploadCount: files.length },
238
+ });`,
239
+ },
240
+ {
241
+ id: 'analytics-use-case-flush',
242
+ title: 'Force flush before sensitive transitions',
243
+ description: 'Flush before redirecting to external checkout/store links when you need best-effort delivery.',
244
+ example: `await publicAnalyticsSdk.track({
245
+ eventType: 'checkout_redirect_clicked',
246
+ stepId: 'paywall',
247
+ metadata: { destination: 'stripe_checkout' },
248
+ });
249
+ await publicAnalyticsSdk.flush();
250
+ window.location.href = checkoutUrl;`,
251
+ },
252
+ ];
253
+
254
+ const analyticsMethodDocs: AnalyticsMethodDoc[] = [
255
+ {
256
+ id: 'analytics-bootstrap-public-user',
257
+ name: 'bootstrapPublicAnalyticsUser',
258
+ signature:
259
+ 'bootstrapPublicAnalyticsUser(input?: PublicSdkIdentifyInput, client?: BootstrapPublicAnalyticsUserClient): Promise<string>',
260
+ description:
261
+ 'Thin bootstrap helper that identifies the visitor, persists the funnel-scoped user_id, and returns the resolved id.',
262
+ example: `const userId = await bootstrapPublicAnalyticsUser({
263
+ email: 'user@example.com',
264
+ metadata: { source: 'landing' },
265
+ });`,
266
+ },
267
+ {
268
+ id: 'analytics-identify',
269
+ name: 'identify',
270
+ signature: 'identify(input?: PublicSdkIdentifyInput): Promise<string>',
271
+ description:
272
+ 'Bootstraps or resolves the funnel-scoped user_id through /sdk/public/users/bootstrap and persists it locally.',
273
+ example: `const userId = await publicAnalyticsSdk.identify({
274
+ user_id: existingIdFromCookie,
275
+ email: userEmail,
276
+ fullName: userName,
277
+ });`,
278
+ },
279
+ {
280
+ id: 'analytics-track',
281
+ name: 'track',
282
+ signature: 'track(event: PublicSdkTrackEventInput): string | null',
283
+ description:
284
+ 'Queues custom events only. Returns null for empty or contract-reserved event names; use their owning FunnelFlow or named helper path.',
285
+ example: `const eventId = publicAnalyticsSdk.track({
286
+ eventType: 'upsell_offer_seen',
287
+ stepId: 'step-7',
288
+ payload: { offerVersion: 'B' },
289
+ });`,
290
+ },
291
+ {
292
+ id: 'analytics-track-step-started',
293
+ name: 'trackStepStarted',
294
+ signature: 'trackStepStarted(input: PublicSdkStepStartInput): string | null',
295
+ description: 'FunnelFlow-owned adapter method for canonical step_start events; step components must not call it.',
296
+ example: `const { goNext } = useFunnel();
297
+ goNext(); // FunnelFlow records the current completion and starts the next visit.`,
298
+ },
299
+ {
300
+ id: 'analytics-track-step-completed',
301
+ name: 'trackStepCompleted',
302
+ signature: 'trackStepCompleted(input: PublicSdkStepEndInput): string | null',
303
+ description: 'FunnelFlow-owned adapter method for canonical step_end events; step components must not call it.',
304
+ example: `const { goToStep } = useFunnel();
305
+ goToStep('step-3', {
306
+ type: 'complete',
307
+ selected: { painScore: 7 },
308
+ });`,
309
+ },
310
+ {
311
+ id: 'analytics-flush',
312
+ name: 'flush',
313
+ signature: 'flush(): Promise<number>',
314
+ description: 'Attempts to deliver queued events immediately. Returns number of events sent in this flush run.',
315
+ example: `const sentCount = await publicAnalyticsSdk.flush();
316
+ console.log('analytics events sent', sentCount);`,
317
+ },
318
+ {
319
+ id: 'analytics-get-current-user-id',
320
+ name: 'getCurrentUserId',
321
+ signature: 'getCurrentUserId(): string',
322
+ description: 'Returns the active funnel-scoped user_id used for analytics envelopes.',
323
+ example: `const userId = publicAnalyticsSdk.getCurrentUserId();`,
324
+ },
325
+ ];
326
+
327
+ export default function SdkDocsPage() {
328
+ return (
329
+ <main className='sdk-docs'>
330
+ <div className='sdk-docs__backdrop' aria-hidden />
331
+
332
+ <header className='sdk-docs__hero'>
333
+ <p className='sdk-docs__eyebrow'>Funnel SDK</p>
334
+ <h1 className='sdk-docs__title'>Runtime + Analytics SDK Reference</h1>
335
+ <p className='sdk-docs__subtitle'>
336
+ Typed `useFunnel()` runtime reference plus analytics SDK event patterns and practical implementation examples.
337
+ </p>
338
+ </header>
339
+
340
+ <div className='sdk-docs__layout'>
341
+ <aside className='sdk-docs__sidebar'>
342
+ <nav className='sdk-docs__nav'>
343
+ <a href='#user-object'>User Object</a>
344
+ <a href='#quick-start'>Quick Start</a>
345
+ <a href='#analytics-sdk'>Analytics SDK</a>
346
+ <a href='#analytics-quick-start'>Analytics Quick Start</a>
347
+ <a href='#analytics-use-cases'>Analytics Use Cases</a>
348
+ <a href='#analytics-methods'>Analytics Methods</a>
349
+ <a href='#methods'>All SDK Methods</a>
350
+ {analyticsMethodDocs.map((methodDoc) => (
351
+ <a key={methodDoc.id} href={`#${methodDoc.id}`}>
352
+ analytics.{methodDoc.name}
353
+ </a>
354
+ ))}
355
+ {methodDocs.map((methodDoc) => (
356
+ <a key={methodDoc.id} href={`#${methodDoc.id}`}>
357
+ {methodDoc.name}
358
+ </a>
359
+ ))}
360
+ </nav>
361
+ </aside>
362
+
363
+ <article className='sdk-docs__content'>
364
+ <section id='user-object' className='sdk-docs__section'>
365
+ <h2>User Object (Start Here)</h2>
366
+ <p>
367
+ This is the canonical runtime answer payload available as `useFunnel().answers`.
368
+ Keep this aligned with `@funnelsgrove/runtime` and `docs/references/funnel-sdk-user-answers.md`.
369
+ </p>
370
+ <pre>
371
+ <code>{userObjectExample}</code>
372
+ </pre>
373
+ </section>
374
+
375
+ <section id='quick-start' className='sdk-docs__section'>
376
+ <h2>Quick Start</h2>
377
+ <p>Import `useFunnel()` in any step and write typed answer keys before moving forward.</p>
378
+ <pre>
379
+ <code>{quickStartExample}</code>
380
+ </pre>
381
+ </section>
382
+
383
+ <section id='analytics-sdk' className='sdk-docs__section'>
384
+ <h2>Analytics SDK</h2>
385
+ <p>
386
+ Use `publicAnalyticsSdk` from `@funnelsgrove/analytics` for custom analytics events.
387
+ It batches events and delivers them directly to PostHog through `navigator.sendBeacon` with
388
+ `fetch(keepalive)` fallback.
389
+ </p>
390
+ <p>
391
+ Standard step start/complete events are already emitted by `FunnelFlow`. Add custom events only for
392
+ business-specific moments (CTA clicks, upload completed, checkout redirect, variant exposure).
393
+ </p>
394
+ </section>
395
+
396
+ <section id='analytics-quick-start' className='sdk-docs__section'>
397
+ <h2>Analytics Quick Start</h2>
398
+ <p>Bootstrap the visitor once, then emit custom events from steps/components as needed.</p>
399
+ <pre>
400
+ <code>{analyticsQuickStartExample}</code>
401
+ </pre>
402
+ </section>
403
+
404
+ <section id='analytics-use-cases' className='sdk-docs__section'>
405
+ <h2>Analytics Use Cases</h2>
406
+ <p>Reference implementations for the most common customization patterns.</p>
407
+ </section>
408
+
409
+ {analyticsUseCases.map((useCase) => (
410
+ <section key={useCase.id} id={useCase.id} className='sdk-docs__section sdk-docs__method'>
411
+ <h3>{useCase.title}</h3>
412
+ <p>{useCase.description}</p>
413
+ <pre>
414
+ <code>{useCase.example}</code>
415
+ </pre>
416
+ </section>
417
+ ))}
418
+
419
+ <section id='analytics-methods' className='sdk-docs__section'>
420
+ <h2>Analytics Methods</h2>
421
+ <p>Public method reference for `bootstrapPublicAnalyticsUser` and `publicAnalyticsSdk`.</p>
422
+ </section>
423
+
424
+ {analyticsMethodDocs.map((methodDoc) => (
425
+ <section key={methodDoc.id} id={methodDoc.id} className='sdk-docs__section sdk-docs__method'>
426
+ <h3>analytics.{methodDoc.name}</h3>
427
+ <p className='sdk-docs__signature'>{methodDoc.signature}</p>
428
+ <p>{methodDoc.description}</p>
429
+ <pre>
430
+ <code>{methodDoc.example}</code>
431
+ </pre>
432
+ </section>
433
+ ))}
434
+
435
+ <section id='methods' className='sdk-docs__section'>
436
+ <h2>All SDK Methods</h2>
437
+ <p>Reference for every field/function currently exposed by `@funnelsgrove/runtime`.</p>
438
+ </section>
439
+
440
+ {methodDocs.map((methodDoc) => (
441
+ <section key={methodDoc.id} id={methodDoc.id} className='sdk-docs__section sdk-docs__method'>
442
+ <h3>{methodDoc.name}</h3>
443
+ <p className='sdk-docs__signature'>{methodDoc.signature}</p>
444
+ <p>{methodDoc.description}</p>
445
+ <pre>
446
+ <code>{methodDoc.example}</code>
447
+ </pre>
448
+ </section>
449
+ ))}
450
+ </article>
451
+ </div>
452
+
453
+ {sdkDocsStyles ? <style>{sdkDocsStyles}</style> : null}
454
+ </main>
455
+ );
456
+ }
457
+
458
+ const sdkDocsStyles = `
459
+ .sdk-docs {
460
+ position: relative;
461
+ min-height: 100svh;
462
+ padding: 36px 24px 48px;
463
+ background: linear-gradient(180deg, #f5f8ff 0%, #edf3ff 55%, #e6eefb 100%);
464
+ color: #1f2740;
465
+ font-family: var(--font-family-base);
466
+ }
467
+
468
+ .sdk-docs__backdrop {
469
+ position: fixed;
470
+ inset: 0;
471
+ pointer-events: none;
472
+ background:
473
+ radial-gradient(circle at 10% 8%, rgba(63, 81, 181, 0.17), transparent 46%),
474
+ radial-gradient(circle at 90% 14%, rgba(77, 181, 63, 0.15), transparent 44%);
475
+ z-index: 0;
476
+ }
477
+
478
+ .sdk-docs__hero,
479
+ .sdk-docs__layout {
480
+ position: relative;
481
+ z-index: 1;
482
+ width: min(1180px, 100%);
483
+ margin: 0 auto;
484
+ }
485
+
486
+ .sdk-docs__hero {
487
+ border: 1px solid rgba(95, 114, 205, 0.26);
488
+ border-radius: 22px;
489
+ padding: 26px;
490
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.93), rgba(240, 246, 255, 0.92));
491
+ box-shadow: 0 16px 38px rgba(31, 39, 64, 0.09);
492
+ }
493
+
494
+ .sdk-docs__eyebrow {
495
+ margin: 0;
496
+ color: var(--color-primary);
497
+ font-size: 12px;
498
+ font-weight: 700;
499
+ letter-spacing: 0.08em;
500
+ text-transform: uppercase;
501
+ }
502
+
503
+ .sdk-docs__title {
504
+ margin: 10px 0 0;
505
+ color: #1f2740;
506
+ font-size: 40px;
507
+ line-height: 1.08;
508
+ font-weight: 800;
509
+ }
510
+
511
+ .sdk-docs__subtitle {
512
+ margin: 14px 0 0;
513
+ color: #475179;
514
+ max-width: 760px;
515
+ font-size: 17px;
516
+ line-height: 1.45;
517
+ }
518
+
519
+ .sdk-docs__layout {
520
+ margin-top: 20px;
521
+ display: grid;
522
+ grid-template-columns: 270px minmax(0, 1fr);
523
+ gap: 20px;
524
+ align-items: start;
525
+ }
526
+
527
+ .sdk-docs__sidebar {
528
+ position: sticky;
529
+ top: 20px;
530
+ }
531
+
532
+ .sdk-docs__nav {
533
+ display: flex;
534
+ flex-direction: column;
535
+ gap: 6px;
536
+ border: 1px solid rgba(95, 114, 205, 0.2);
537
+ border-radius: 18px;
538
+ background: rgba(255, 255, 255, 0.85);
539
+ padding: 12px;
540
+ box-shadow: 0 10px 24px rgba(31, 39, 64, 0.07);
541
+ }
542
+
543
+ .sdk-docs__nav a {
544
+ border-radius: 10px;
545
+ padding: 8px 10px;
546
+ text-decoration: none;
547
+ color: #3a4366;
548
+ font-size: 13px;
549
+ font-weight: 600;
550
+ line-height: 1.25;
551
+ }
552
+
553
+ .sdk-docs__nav a:hover {
554
+ background: rgba(63, 81, 181, 0.12);
555
+ color: #25337f;
556
+ }
557
+
558
+ .sdk-docs__content {
559
+ display: flex;
560
+ flex-direction: column;
561
+ gap: 16px;
562
+ }
563
+
564
+ .sdk-docs__section {
565
+ border: 1px solid rgba(95, 114, 205, 0.2);
566
+ border-radius: 18px;
567
+ background: rgba(255, 255, 255, 0.88);
568
+ padding: 20px;
569
+ box-shadow: 0 10px 24px rgba(31, 39, 64, 0.07);
570
+ }
571
+
572
+ .sdk-docs__section h2,
573
+ .sdk-docs__section h3 {
574
+ margin: 0;
575
+ color: #222f77;
576
+ font-family: var(--font-family-display);
577
+ }
578
+
579
+ .sdk-docs__section h2 {
580
+ font-size: 28px;
581
+ line-height: 1.2;
582
+ }
583
+
584
+ .sdk-docs__section h3 {
585
+ font-size: 24px;
586
+ line-height: 1.2;
587
+ }
588
+
589
+ .sdk-docs__section p {
590
+ margin: 10px 0 0;
591
+ color: #495175;
592
+ font-size: 15px;
593
+ line-height: 1.48;
594
+ }
595
+
596
+ .sdk-docs__signature {
597
+ margin-top: 8px;
598
+ border: 1px dashed rgba(63, 81, 181, 0.35);
599
+ border-radius: 10px;
600
+ background: rgba(238, 243, 255, 0.9);
601
+ padding: 10px 12px;
602
+ color: #27316d;
603
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace;
604
+ font-size: 12px;
605
+ line-height: 1.45;
606
+ overflow-x: auto;
607
+ }
608
+
609
+ .sdk-docs pre {
610
+ margin: 14px 0 0;
611
+ border: 1px solid #d6defe;
612
+ border-radius: 14px;
613
+ background: #151a2e;
614
+ color: #eaf0ff;
615
+ padding: 14px;
616
+ overflow-x: auto;
617
+ }
618
+
619
+ .sdk-docs code {
620
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace;
621
+ font-size: 12px;
622
+ line-height: 1.6;
623
+ }
624
+
625
+ .sdk-docs__method {
626
+ scroll-margin-top: 20px;
627
+ }
628
+
629
+ @media (max-width: 1020px) {
630
+ .sdk-docs__layout {
631
+ grid-template-columns: 1fr;
632
+ }
633
+
634
+ .sdk-docs__sidebar {
635
+ position: static;
636
+ }
637
+
638
+ .sdk-docs__nav {
639
+ max-height: 260px;
640
+ overflow-y: auto;
641
+ }
642
+ }
643
+
644
+ @media (max-width: 640px) {
645
+ .sdk-docs {
646
+ padding: 20px 14px 30px;
647
+ }
648
+
649
+ .sdk-docs__hero {
650
+ padding: 18px;
651
+ }
652
+
653
+ .sdk-docs__title {
654
+ font-size: 30px;
655
+ }
656
+
657
+ .sdk-docs__subtitle {
658
+ font-size: 15px;
659
+ }
660
+
661
+ .sdk-docs__section {
662
+ padding: 16px;
663
+ }
664
+
665
+ .sdk-docs__section h2 {
666
+ font-size: 24px;
667
+ }
668
+
669
+ .sdk-docs__section h3 {
670
+ font-size: 20px;
671
+ }
672
+ }
673
+ `;