vibefast-cli 1.1.3 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +63 -169
  3. package/dist/__tests__/recipes.test.js +25 -3
  4. package/dist/__tests__/recipes.test.js.map +1 -1
  5. package/dist/commands/add.d.ts +1 -1
  6. package/dist/commands/add.d.ts.map +1 -1
  7. package/dist/commands/add.js +547 -543
  8. package/dist/commands/add.js.map +1 -1
  9. package/dist/commands/checklist.d.ts +1 -1
  10. package/dist/commands/checklist.d.ts.map +1 -1
  11. package/dist/commands/checklist.js +40 -39
  12. package/dist/commands/checklist.js.map +1 -1
  13. package/dist/commands/doctor.d.ts +1 -1
  14. package/dist/commands/doctor.js +22 -22
  15. package/dist/commands/doctor.js.map +1 -1
  16. package/dist/commands/env.d.ts +1 -1
  17. package/dist/commands/env.d.ts.map +1 -1
  18. package/dist/commands/env.js +58 -53
  19. package/dist/commands/env.js.map +1 -1
  20. package/dist/commands/health.d.ts +1 -1
  21. package/dist/commands/health.d.ts.map +1 -1
  22. package/dist/commands/health.js +101 -93
  23. package/dist/commands/health.js.map +1 -1
  24. package/dist/commands/init.d.ts +1 -1
  25. package/dist/commands/init.d.ts.map +1 -1
  26. package/dist/commands/init.js +416 -296
  27. package/dist/commands/init.js.map +1 -1
  28. package/dist/commands/remove.d.ts +1 -1
  29. package/dist/commands/remove.d.ts.map +1 -1
  30. package/dist/commands/remove.js +77 -64
  31. package/dist/commands/remove.js.map +1 -1
  32. package/dist/commands/status.d.ts +1 -1
  33. package/dist/commands/status.d.ts.map +1 -1
  34. package/dist/commands/status.js +15 -14
  35. package/dist/commands/status.js.map +1 -1
  36. package/dist/core/__tests__/detect.test.js +68 -34
  37. package/dist/core/__tests__/detect.test.js.map +1 -1
  38. package/dist/core/ast.d.ts +14 -0
  39. package/dist/core/ast.d.ts.map +1 -0
  40. package/dist/core/ast.js +239 -0
  41. package/dist/core/ast.js.map +1 -0
  42. package/dist/core/codemod.d.ts.map +1 -1
  43. package/dist/core/codemod.js +62 -44
  44. package/dist/core/codemod.js.map +1 -1
  45. package/dist/core/config.d.ts +10 -0
  46. package/dist/core/config.d.ts.map +1 -0
  47. package/dist/core/config.js +51 -0
  48. package/dist/core/config.js.map +1 -0
  49. package/dist/core/detect.d.ts +8 -2
  50. package/dist/core/detect.d.ts.map +1 -1
  51. package/dist/core/detect.js +52 -21
  52. package/dist/core/detect.js.map +1 -1
  53. package/dist/core/errors.d.ts.map +1 -1
  54. package/dist/core/errors.js +9 -8
  55. package/dist/core/errors.js.map +1 -1
  56. package/dist/core/exec.d.ts +16 -0
  57. package/dist/core/exec.d.ts.map +1 -0
  58. package/dist/core/exec.js +48 -0
  59. package/dist/core/exec.js.map +1 -0
  60. package/dist/core/manualSteps.d.ts +7 -0
  61. package/dist/core/manualSteps.d.ts.map +1 -0
  62. package/dist/core/manualSteps.js +59 -0
  63. package/dist/core/manualSteps.js.map +1 -0
  64. package/dist/core/paths.d.ts +3 -1
  65. package/dist/core/paths.d.ts.map +1 -1
  66. package/dist/core/paths.js +14 -10
  67. package/dist/core/paths.js.map +1 -1
  68. package/dist/core/spinner.d.ts +1 -1
  69. package/dist/core/spinner.d.ts.map +1 -1
  70. package/dist/core/spinner.js +38 -8
  71. package/dist/core/spinner.js.map +1 -1
  72. package/dist/core/vosk.d.ts.map +1 -1
  73. package/dist/core/vosk.js +50 -39
  74. package/dist/core/vosk.js.map +1 -1
  75. package/docs/manual-testing.md +91 -0
  76. package/package.json +6 -3
  77. package/recipes/audio-recorder/apps/native/src/app/audio-recorder/index.tsx +5 -0
  78. package/recipes/audio-recorder/recipe.json +3 -3
  79. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-player.tsx +301 -0
  80. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +373 -0
  81. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-waveform.tsx +270 -0
  82. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/index.ts +4 -0
  83. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/recording-list.tsx +89 -0
  84. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-player-demo.tsx +66 -0
  85. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-recorder-cloud.tsx +68 -0
  86. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-recorder-interview.tsx +102 -0
  87. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/basic.tsx +27 -0
  88. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/index.ts +5 -0
  89. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +82 -0
  90. package/recipes/audio-recorder-supabase/packages/backend/src/services/recordings.ts +369 -0
  91. package/recipes/audio-recorder-supabase/packages/backend/supabase/migrations/recordings.sql +70 -0
  92. package/recipes/audio-recorder-supabase/recipe.json +35 -0
  93. package/recipes/audio-recorder-supabase@latest.zip +0 -0
  94. package/recipes/audio-recorder@latest.zip +0 -0
  95. package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +3 -3
  96. package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +2 -2
  97. package/recipes/charts/apps/native/src/features/charts/components/chart-card.tsx +5 -5
  98. package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +3 -3
  99. package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +20 -4
  100. package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +7 -6
  101. package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +6 -4
  102. package/recipes/charts/apps/native/src/features/charts/components/radial-bar-chart.tsx +1 -1
  103. package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +5 -4
  104. package/recipes/charts/recipe.json +4 -13
  105. package/recipes/charts@latest.zip +0 -0
  106. package/recipes/chatbot/apps/native/src/app/chatbot/index.tsx +1 -0
  107. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +86 -86
  108. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +86 -53
  109. package/recipes/chatbot/recipe.json +26 -92
  110. package/recipes/chatbot-supabase/apps/native/src/api-client/supabase/chatbot.ts +515 -0
  111. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/app/index.tsx +257 -0
  112. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-header-buttons.tsx +59 -0
  113. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-input-bar.tsx +485 -0
  114. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-markdown.tsx +575 -0
  115. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-message-bubble.tsx +223 -0
  116. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-settings-modal.tsx +161 -0
  117. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/image-preview-list.tsx +116 -0
  118. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/code-block.tsx +165 -0
  119. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/index.ts +10 -0
  120. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/table-renderer.tsx +129 -0
  121. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/message-error-boundary.tsx +78 -0
  122. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/message-list.tsx +170 -0
  123. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/model-selector.tsx +283 -0
  124. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/report-content-modal.tsx +188 -0
  125. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/suggested-messages.tsx +67 -0
  126. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/constants/models.ts +20 -0
  127. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/constants/report-reasons.ts +9 -0
  128. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-attachment-cache.ts +142 -0
  129. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chat-config.ts +458 -0
  130. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chat-handlers.ts +429 -0
  131. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chatbot-settings.ts +89 -0
  132. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-conversation.ts +90 -0
  133. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-image-picker.ts +122 -0
  134. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-keyboard-coordinator.ts +161 -0
  135. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-smart-scroll-manager.ts +213 -0
  136. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/index.ts +86 -0
  137. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/models.ts +162 -0
  138. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/providers.ts +62 -0
  139. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/types.ts +40 -0
  140. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/services/file-uploader.ts +287 -0
  141. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/services/message-handler-service.ts +189 -0
  142. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/types/index.ts +70 -0
  143. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/utils/chat-telemetry.ts +91 -0
  144. package/recipes/chatbot-supabase/packages/backend/src/services/conversations.ts +243 -0
  145. package/recipes/chatbot-supabase/packages/backend/src/services/messages.ts +327 -0
  146. package/recipes/chatbot-supabase/packages/backend/supabase/functions/chat-stream/index.ts +347 -0
  147. package/recipes/chatbot-supabase/packages/backend/supabase/migrations/chatbot.sql +104 -0
  148. package/recipes/chatbot-supabase/recipe.json +79 -0
  149. package/recipes/chatbot-supabase@latest.zip +0 -0
  150. package/recipes/chatbot.zip +0 -0
  151. package/recipes/chatbot@latest.zip +0 -0
  152. package/recipes/image-analysis/packages/backend/convex/imageAnalysis/index.ts +2 -2
  153. package/recipes/image-analysis/packages/backend/convex/{imageAnalysisFunctions.ts → imageAnalysis.ts} +5 -5
  154. package/recipes/image-analysis/recipe.json +15 -55
  155. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/analysis-options-screen.tsx +304 -0
  156. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/camera.tsx +221 -0
  157. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/image-capture-screen.tsx +333 -0
  158. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/loading-screen.tsx +214 -0
  159. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/loading.tsx +191 -0
  160. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/results.tsx +137 -0
  161. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/trait-details.tsx +172 -0
  162. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/use-analysis-data.ts +160 -0
  163. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/use-results-screen.ts +151 -0
  164. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-badge.tsx +77 -0
  165. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-card.tsx +75 -0
  166. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-unlocked-modal.tsx +162 -0
  167. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievements-section.tsx +44 -0
  168. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/advice-list.tsx +42 -0
  169. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/circular-progress.tsx +233 -0
  170. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/content-card.tsx +38 -0
  171. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/error-state.tsx +42 -0
  172. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/index.ts +9 -0
  173. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/loading-state.tsx +26 -0
  174. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/profile-image.tsx +60 -0
  175. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/results-header.tsx +62 -0
  176. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/score-display.tsx +54 -0
  177. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/share-options-modal.tsx +110 -0
  178. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/traits-grid.tsx +74 -0
  179. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/config/analysis-config.ts +80 -0
  180. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/config/master-analysis-config.ts +157 -0
  181. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/index.ts +1 -0
  182. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/use-analysis.ts +38 -0
  183. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/use-image-analysis.ts +208 -0
  184. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/analysis-service.ts +262 -0
  185. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/share-service.ts +176 -0
  186. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/trait-details-service.ts +289 -0
  187. package/recipes/image-analysis-supabase/packages/backend/src/services/image-analyses.ts +132 -0
  188. package/recipes/image-analysis-supabase/packages/backend/supabase/functions/analyze-image/index.ts +312 -0
  189. package/recipes/image-analysis-supabase/packages/backend/supabase/migrations/image_analysis.sql +42 -0
  190. package/recipes/image-analysis-supabase/recipe.json +57 -0
  191. package/recipes/image-analysis-supabase@latest.zip +0 -0
  192. package/recipes/image-analysis@latest.zip +0 -0
  193. package/recipes/image-generator/apps/native/src/features/image-generator/app/index.tsx +16 -2
  194. package/recipes/image-generator/apps/native/src/features/image-generator/components/image-model-selector.tsx +11 -5
  195. package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator.ts +11 -5
  196. package/recipes/image-generator/packages/backend/convex/imageGeneration/index.ts +2 -2
  197. package/recipes/image-generator/recipe.json +16 -39
  198. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/_layout.tsx +26 -0
  199. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/gallery.tsx +217 -0
  200. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/index.tsx +251 -0
  201. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/gallery-image.tsx +25 -0
  202. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-detail-modal.tsx +215 -0
  203. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-model-selector.tsx +216 -0
  204. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-placeholder.tsx +26 -0
  205. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-gallery.ts +71 -0
  206. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-generator-settings.ts +152 -0
  207. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-generator.ts +103 -0
  208. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/models/models.ts +66 -0
  209. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/services/image-gallery-service.ts +96 -0
  210. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/services/image-save-service.ts +120 -0
  211. package/recipes/image-generator-supabase/packages/backend/supabase/functions/generate-image/index.ts +291 -0
  212. package/recipes/image-generator-supabase/packages/backend/supabase/migrations/image_generator.sql +71 -0
  213. package/recipes/image-generator-supabase/recipe.json +59 -0
  214. package/recipes/image-generator-supabase@latest.zip +0 -0
  215. package/recipes/image-generator@latest.zip +0 -0
  216. package/recipes/ios-widget/recipe.json +15 -24
  217. package/recipes/ios-widget@latest.zip +0 -0
  218. package/recipes/onboarding/apps/native/src/features/onboarding/analytics/index.ts +9 -0
  219. package/recipes/onboarding/apps/native/src/features/onboarding/components/onboarding-with-analytics.tsx +141 -0
  220. package/recipes/onboarding/apps/native/src/features/onboarding/components/onboarding.tsx +173 -0
  221. package/recipes/onboarding/apps/native/src/features/onboarding/config/onboarding-flow-config.ts +189 -0
  222. package/recipes/onboarding/apps/native/src/features/onboarding/demo-one/app/index.tsx +42 -0
  223. package/recipes/onboarding/apps/native/src/features/onboarding/demo-one/data.ts +32 -0
  224. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/app/index.tsx +43 -0
  225. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/interactive-onboarding.tsx +222 -0
  226. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/ai-tone-step.tsx +133 -0
  227. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/currency-step.tsx +165 -0
  228. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-ai-step.tsx +199 -0
  229. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-chatbot-step.tsx +154 -0
  230. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-manual-step.tsx +156 -0
  231. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-scan-step.tsx +158 -0
  232. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/main-reason-step.tsx +139 -0
  233. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/notification-step.tsx +129 -0
  234. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/overspend-step.tsx +138 -0
  235. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/personalizing-step.tsx +190 -0
  236. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/rating-step.tsx +98 -0
  237. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/reminder-step.tsx +181 -0
  238. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/safety-step.tsx +110 -0
  239. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/struggle-step.tsx +139 -0
  240. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/welcome-step.tsx +217 -0
  241. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/ui/onboarding-header.tsx +58 -0
  242. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/constants.ts +179 -0
  243. package/recipes/onboarding/apps/native/src/features/onboarding/hooks/use-onboarding-analytics.ts +323 -0
  244. package/recipes/onboarding/apps/native/src/features/onboarding/services/onboarding-analytics.ts +432 -0
  245. package/recipes/onboarding/recipe.json +15 -0
  246. package/recipes/onboarding@latest.zip +0 -0
  247. package/recipes/payments/recipe.json +28 -61
  248. package/recipes/payments-supabase/apps/native/src/features/payments/README.md +200 -0
  249. package/recipes/payments-supabase/apps/native/src/features/payments/app/local-paywall.tsx +194 -0
  250. package/recipes/payments-supabase/apps/native/src/features/payments/app/remote-paywall.tsx +79 -0
  251. package/recipes/payments-supabase/apps/native/src/features/payments/components/payment-initializer.tsx +95 -0
  252. package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-error-state.tsx +60 -0
  253. package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-local-mode.tsx +116 -0
  254. package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-product-card.tsx +133 -0
  255. package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-remote-mode.tsx +146 -0
  256. package/recipes/payments-supabase/apps/native/src/features/payments/hooks/use-entitlement.ts +63 -0
  257. package/recipes/payments-supabase/apps/native/src/features/payments/index.ts +8 -0
  258. package/recipes/payments-supabase/apps/native/src/features/payments/services/revenuecat-adapter.ts +407 -0
  259. package/recipes/payments-supabase/packages/backend/src/services/payments.ts +201 -0
  260. package/recipes/payments-supabase/packages/backend/supabase/migrations/payments.sql +35 -0
  261. package/recipes/payments-supabase/recipe.json +51 -0
  262. package/recipes/payments-supabase@latest.zip +0 -0
  263. package/recipes/payments@latest.zip +0 -0
  264. package/recipes/quiz/apps/native/src/features/quiz/index.tsx +1 -2
  265. package/recipes/quiz/recipe.json +6 -9
  266. package/recipes/quiz@latest.zip +0 -0
  267. package/recipes/tracker-app/apps/native/src/features/tracker-app/app/index.tsx +1 -2
  268. package/recipes/tracker-app/recipe.json +7 -10
  269. package/recipes/tracker-app@latest.zip +0 -0
  270. package/recipes/voice-bot/recipe.json +8 -68
  271. package/recipes/voice-bot.zip +0 -0
  272. package/recipes/voice-bot@latest.zip +0 -0
  273. package/recipes/wake-word/recipe.json +10 -9
  274. package/recipes/wake-word.zip +0 -0
  275. package/recipes/wake-word@latest.zip +0 -0
  276. package/recipes/charts/apps/native/src/app/(root)/(protected)/charts/index.tsx +0 -3
  277. package/recipes/chatbot/packages/backend/convex/lib/rateLimit.ts +0 -100
  278. package/recipes/chatbot/packages/backend/convex/lib/telemetry.ts +0 -29
  279. package/recipes/chatbot/packages/backend/convex/ragKnowledge.ts +0 -0
  280. package/recipes/image-analysis/apps/native/assets/features/image-analyzer/front.jpg +0 -0
  281. package/recipes/image-analysis/apps/native/assets/features/image-analyzer/side.jpg +0 -0
  282. package/recipes/image-analysis/apps/native/assets/features/image-analyzer/threeQuarter.jpg +0 -0
  283. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/_layout.tsx +0 -5
  284. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/analysis-options.tsx +0 -50
  285. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/camera.tsx +0 -2
  286. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/index.tsx +0 -50
  287. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/loading.tsx +0 -50
  288. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/results.tsx +0 -2
  289. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/trait-details.tsx +0 -3
  290. package/recipes/image-analysis/packages/backend/convex/lib/ai/imageAnalysisAdapter.ts +0 -200
  291. package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/index.tsx +0 -74
  292. package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/local.tsx +0 -25
  293. package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/remote.tsx +0 -23
  294. package/recipes/quiz/apps/native/src/app/(root)/(protected)/quiz/index.tsx +0 -47
  295. package/recipes/tracker-app/apps/native/src/app/(root)/(protected)/tracker-app/index.tsx +0 -1
  296. package/recipes/voice-bot/apps/native/src/app/(root)/(protected)/voice-bot/index.tsx +0 -27
  297. package/recipes/voice-bot/packages/backend/convex/router.ts +0 -81
  298. /package/recipes/{chatbot/apps/native/src/app/(root)/(protected) → chatbot-supabase/apps/native/src/app}/chatbot/index.tsx +0 -0
  299. /package/recipes/{image-generator/apps/native/src/app/(root)/(protected) → image-generator-supabase/apps/native/src/app}/image-generator/gallery.tsx +0 -0
  300. /package/recipes/{image-generator/apps/native/src/app/(root)/(protected) → image-generator-supabase/apps/native/src/app}/image-generator/index.tsx +0 -0
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+ import { MaterialCommunityIcons } from '@expo/vector-icons';
4
+ import Animated, {
5
+ useAnimatedStyle,
6
+ useSharedValue,
7
+ withTiming,
8
+ } from 'react-native-reanimated';
9
+ import { useThemeConfig } from '@/lib/use-theme-config';
10
+ import { Pressable } from '@/components/ui';
11
+
12
+ interface OnboardingHeaderProps {
13
+ onBack: () => void;
14
+ canGoBack: boolean;
15
+ progress?: number;
16
+ }
17
+
18
+ export function OnboardingHeader({
19
+ onBack,
20
+ canGoBack,
21
+ progress = 0,
22
+ }: OnboardingHeaderProps) {
23
+ const theme = useThemeConfig();
24
+ const progressValue = useSharedValue(0);
25
+
26
+ React.useEffect(() => {
27
+ progressValue.value = withTiming(progress, { duration: 500 });
28
+ }, [progress]);
29
+
30
+ const animatedProgressStyle = useAnimatedStyle(() => ({
31
+ width: `${progressValue.value * 100}%`,
32
+ }));
33
+
34
+ if (!canGoBack) return <View className="h-12" />;
35
+
36
+ return (
37
+ <View className="h-12 px-6 flex-row items-center">
38
+ <Pressable
39
+ onPress={onBack}
40
+ className="w-10 h-10 items-center justify-center -ml-2 rounded-full active:bg-muted/20 mr-4"
41
+ >
42
+ <MaterialCommunityIcons
43
+ name="chevron-left"
44
+ size={32}
45
+ color={theme.colors.foreground}
46
+ />
47
+ </Pressable>
48
+
49
+ {/* Progress Bar */}
50
+ <View className="flex-1 h-1 bg-muted rounded-full overflow-hidden">
51
+ <Animated.View
52
+ className="h-full bg-primary rounded-full"
53
+ style={animatedProgressStyle}
54
+ />
55
+ </View>
56
+ </View>
57
+ );
58
+ }
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Demo Expense Tracker Onboarding - Currency Constants
3
+ *
4
+ * Contains currency data for the onboarding demo.
5
+ * This is a self-contained copy to avoid external dependencies.
6
+ */
7
+
8
+ export const SUPPORTED_CURRENCIES = [
9
+ // Major Global Currencies
10
+ { code: 'USD', symbol: '$', name: 'US Dollar' },
11
+ { code: 'EUR', symbol: 'EUR', name: 'Euro' },
12
+ { code: 'GBP', symbol: 'GBP', name: 'British Pound' },
13
+ { code: 'JPY', symbol: 'JPY', name: 'Japanese Yen' },
14
+ { code: 'CHF', symbol: 'CHF', name: 'Swiss Franc' },
15
+ { code: 'CNY', symbol: 'CNY', name: 'Chinese Yuan' },
16
+ { code: 'CAD', symbol: 'CAD', name: 'Canadian Dollar' },
17
+ { code: 'AUD', symbol: 'AUD', name: 'Australian Dollar' },
18
+ { code: 'NZD', symbol: 'NZD', name: 'New Zealand Dollar' },
19
+ { code: 'SGD', symbol: 'SGD', name: 'Singapore Dollar' },
20
+ { code: 'HKD', symbol: 'HKD', name: 'Hong Kong Dollar' },
21
+
22
+ // Asian Currencies
23
+ { code: 'INR', symbol: 'INR', name: 'Indian Rupee' },
24
+ { code: 'PKR', symbol: 'PKR', name: 'Pakistani Rupee' },
25
+ { code: 'BDT', symbol: 'BDT', name: 'Bangladeshi Taka' },
26
+ { code: 'LKR', symbol: 'LKR', name: 'Sri Lankan Rupee' },
27
+ { code: 'THB', symbol: 'THB', name: 'Thai Baht' },
28
+ { code: 'MYR', symbol: 'MYR', name: 'Malaysian Ringgit' },
29
+ { code: 'IDR', symbol: 'IDR', name: 'Indonesian Rupiah' },
30
+ { code: 'PHP', symbol: 'PHP', name: 'Philippine Peso' },
31
+ { code: 'VND', symbol: 'VND', name: 'Vietnamese Dong' },
32
+ { code: 'KRW', symbol: 'KRW', name: 'South Korean Won' },
33
+ { code: 'TWD', symbol: 'TWD', name: 'Taiwan Dollar' },
34
+
35
+ // Middle Eastern Currencies
36
+ { code: 'AED', symbol: 'AED', name: 'UAE Dirham' },
37
+ { code: 'SAR', symbol: 'SAR', name: 'Saudi Riyal' },
38
+ { code: 'QAR', symbol: 'QAR', name: 'Qatari Riyal' },
39
+ { code: 'KWD', symbol: 'KWD', name: 'Kuwaiti Dinar' },
40
+ { code: 'BHD', symbol: 'BHD', name: 'Bahraini Dinar' },
41
+ { code: 'OMR', symbol: 'OMR', name: 'Omani Rial' },
42
+ { code: 'JOD', symbol: 'JOD', name: 'Jordanian Dinar' },
43
+ { code: 'LBP', symbol: 'LBP', name: 'Lebanese Pound' },
44
+ { code: 'EGP', symbol: 'EGP', name: 'Egyptian Pound' },
45
+ { code: 'ILS', symbol: 'ILS', name: 'Israeli Shekel' },
46
+ { code: 'TRY', symbol: 'TRY', name: 'Turkish Lira' },
47
+ { code: 'IRR', symbol: 'IRR', name: 'Iranian Rial' },
48
+
49
+ // European Currencies
50
+ { code: 'SEK', symbol: 'SEK', name: 'Swedish Krona' },
51
+ { code: 'NOK', symbol: 'NOK', name: 'Norwegian Krone' },
52
+ { code: 'DKK', symbol: 'DKK', name: 'Danish Krone' },
53
+ { code: 'PLN', symbol: 'PLN', name: 'Polish Zloty' },
54
+ { code: 'CZK', symbol: 'CZK', name: 'Czech Koruna' },
55
+ { code: 'HUF', symbol: 'HUF', name: 'Hungarian Forint' },
56
+ { code: 'RON', symbol: 'RON', name: 'Romanian Leu' },
57
+ { code: 'BGN', symbol: 'BGN', name: 'Bulgarian Lev' },
58
+ { code: 'HRK', symbol: 'HRK', name: 'Croatian Kuna' },
59
+ { code: 'RUB', symbol: 'RUB', name: 'Russian Ruble' },
60
+ { code: 'UAH', symbol: 'UAH', name: 'Ukrainian Hryvnia' },
61
+ { code: 'BYN', symbol: 'BYN', name: 'Belarusian Ruble' },
62
+
63
+ // Americas Currencies
64
+ { code: 'MXN', symbol: 'MXN', name: 'Mexican Peso' },
65
+ { code: 'BRL', symbol: 'BRL', name: 'Brazilian Real' },
66
+ { code: 'ARS', symbol: 'ARS', name: 'Argentine Peso' },
67
+ { code: 'CLP', symbol: 'CLP', name: 'Chilean Peso' },
68
+ { code: 'COP', symbol: 'COP', name: 'Colombian Peso' },
69
+ { code: 'PEN', symbol: 'PEN', name: 'Peruvian Sol' },
70
+ { code: 'UYU', symbol: 'UYU', name: 'Uruguayan Peso' },
71
+ { code: 'VEF', symbol: 'VEF', name: 'Venezuelan Bolivar' },
72
+
73
+ // African Currencies
74
+ { code: 'ZAR', symbol: 'ZAR', name: 'South African Rand' },
75
+ { code: 'NGN', symbol: 'NGN', name: 'Nigerian Naira' },
76
+ { code: 'GHS', symbol: 'GHS', name: 'Ghanaian Cedi' },
77
+ { code: 'KES', symbol: 'KES', name: 'Kenyan Shilling' },
78
+ { code: 'UGX', symbol: 'UGX', name: 'Ugandan Shilling' },
79
+ { code: 'ETB', symbol: 'ETB', name: 'Ethiopian Birr' },
80
+ { code: 'MAD', symbol: 'MAD', name: 'Moroccan Dirham' },
81
+ { code: 'TND', symbol: 'TND', name: 'Tunisian Dinar' },
82
+ { code: 'ZWL', symbol: 'ZWL', name: 'Zimbabwean Dollar' },
83
+
84
+ // Oceania & Pacific
85
+ { code: 'FJD', symbol: 'FJD', name: 'Fijian Dollar' },
86
+ { code: 'PGK', symbol: 'PGK', name: 'Papua New Guinean Kina' },
87
+ ] as const;
88
+
89
+ /**
90
+ * Currency flag emojis for visual display
91
+ */
92
+ export const CURRENCY_FLAGS: Record<string, string> = {
93
+ USD: '🇺🇸',
94
+ EUR: '🇪🇺',
95
+ GBP: '🇬🇧',
96
+ JPY: '🇯🇵',
97
+ CHF: '🇨🇭',
98
+ CNY: '🇨🇳',
99
+ CAD: '🇨🇦',
100
+ AUD: '🇦🇺',
101
+ NZD: '🇳🇿',
102
+ SGD: '🇸🇬',
103
+ HKD: '🇭🇰',
104
+ INR: '🇮🇳',
105
+ PKR: '🇵🇰',
106
+ BDT: '🇧🇩',
107
+ LKR: '🇱🇰',
108
+ THB: '🇹🇭',
109
+ MYR: '🇲🇾',
110
+ IDR: '🇮🇩',
111
+ PHP: '🇵🇭',
112
+ VND: '🇻🇳',
113
+ KRW: '🇰🇷',
114
+ TWD: '🇹🇼',
115
+ AED: '🇦🇪',
116
+ SAR: '🇸🇦',
117
+ QAR: '🇶🇦',
118
+ KWD: '🇰🇼',
119
+ BHD: '🇧🇭',
120
+ OMR: '🇴🇲',
121
+ JOD: '🇯🇴',
122
+ LBP: '🇱🇧',
123
+ EGP: '🇪🇬',
124
+ ILS: '🇮🇱',
125
+ TRY: '🇹🇷',
126
+ IRR: '🇮🇷',
127
+ SEK: '🇸🇪',
128
+ NOK: '🇳🇴',
129
+ DKK: '🇩🇰',
130
+ PLN: '🇵🇱',
131
+ CZK: '🇨🇿',
132
+ HUF: '🇭🇺',
133
+ RON: '🇷🇴',
134
+ BGN: '🇧🇬',
135
+ HRK: '🇭🇷',
136
+ RUB: '🇷🇺',
137
+ UAH: '🇺🇦',
138
+ BYN: '🇧🇾',
139
+ MXN: '🇲🇽',
140
+ BRL: '🇧🇷',
141
+ ARS: '🇦🇷',
142
+ CLP: '🇨🇱',
143
+ COP: '🇨🇴',
144
+ PEN: '🇵🇪',
145
+ UYU: '🇺🇾',
146
+ VEF: '🇻🇪',
147
+ ZAR: '🇿🇦',
148
+ NGN: '🇳🇬',
149
+ GHS: '🇬🇭',
150
+ KES: '🇰🇪',
151
+ UGX: '🇺🇬',
152
+ ETB: '🇪🇹',
153
+ MAD: '🇲🇦',
154
+ TND: '🇹🇳',
155
+ ZWL: '🇿🇼',
156
+ FJD: '🇫🇯',
157
+ PGK: '🇵🇬',
158
+ };
159
+
160
+ export function getCurrencyFlag(code: string): string {
161
+ return CURRENCY_FLAGS[code] || code;
162
+ }
163
+
164
+ export type SupportedCurrency = (typeof SUPPORTED_CURRENCIES)[number];
165
+ export type CurrencyCode = SupportedCurrency['code'];
166
+
167
+ /**
168
+ * Currency symbols (derived from SUPPORTED_CURRENCIES)
169
+ */
170
+ export const CURRENCY_SYMBOLS: Record<string, string> = Object.fromEntries(
171
+ SUPPORTED_CURRENCIES.map((c) => [c.code, c.symbol]),
172
+ );
173
+
174
+ /**
175
+ * Get currency symbol for a currency code
176
+ */
177
+ export function getCurrencySymbol(currency: string): string {
178
+ return CURRENCY_SYMBOLS[currency] || currency;
179
+ }
@@ -0,0 +1,323 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+
3
+ import { usePostHogAnalyticsAdapter } from '@/core/analytics';
4
+
5
+ import type {
6
+ OnboardingFlowConfig,
7
+ OnboardingSession,
8
+ } from '../services/onboarding-analytics';
9
+ import { OnboardingAnalyticsService } from '../services/onboarding-analytics';
10
+
11
+ /**
12
+ * Configuration for the onboarding analytics hook
13
+ */
14
+ export type UseOnboardingAnalyticsConfig = {
15
+ flowConfig: OnboardingFlowConfig;
16
+ userType?: 'new' | 'returning' | 'migrated';
17
+ autoStart?: boolean; // Whether to automatically start tracking when hook is called
18
+ };
19
+
20
+ /**
21
+ * Return type for the onboarding analytics hook
22
+ */
23
+ export type OnboardingAnalyticsActions = {
24
+ // Flow control
25
+ startFlow: () => Promise<string>;
26
+ completeFlow: () => Promise<void>;
27
+ abandonFlow: (reason?: string) => Promise<void>;
28
+
29
+ // Step tracking
30
+ trackStepViewed: (
31
+ stepId: string,
32
+ properties?: Record<string, any>,
33
+ ) => Promise<void>;
34
+ trackStepCompleted: (
35
+ stepId: string,
36
+ properties?: Record<string, any>,
37
+ ) => Promise<void>;
38
+ trackStepSkipped: (
39
+ stepId: string,
40
+ reason?: string,
41
+ properties?: Record<string, any>,
42
+ ) => Promise<void>;
43
+ trackStepRetried: (
44
+ stepId: string,
45
+ attempt: number,
46
+ properties?: Record<string, any>,
47
+ ) => Promise<void>;
48
+ trackStepHelp: (
49
+ stepId: string,
50
+ helpType?: string,
51
+ properties?: Record<string, any>,
52
+ ) => Promise<void>;
53
+
54
+ // Navigation tracking
55
+ trackNavigation: (
56
+ direction: 'back' | 'forward',
57
+ fromStepId: string,
58
+ toStepId: string,
59
+ ) => Promise<void>;
60
+
61
+ // State access
62
+ getCurrentSession: () => OnboardingSession | null;
63
+ getProgress: () => {
64
+ totalSteps: number;
65
+ currentStep: number;
66
+ completedSteps: number;
67
+ skippedSteps: number;
68
+ completionRate: number;
69
+ } | null;
70
+
71
+ // Utilities
72
+ isStepCompleted: (stepId: string) => boolean;
73
+ isStepSkipped: (stepId: string) => boolean;
74
+ getNextStep: (currentStepId: string) => string | null;
75
+ getPreviousStep: (currentStepId: string) => string | null;
76
+ };
77
+
78
+ /**
79
+ * Hook for tracking onboarding analytics with automatic step discovery.
80
+ * Provides a clean, React-friendly interface for onboarding event tracking.
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * const analytics = useOnboardingAnalytics({
85
+ * flowConfig: {
86
+ * flowId: 'main_onboarding',
87
+ * flowName: 'Main App Onboarding',
88
+ * steps: [
89
+ * { id: 'welcome', name: 'Welcome Screen', index: 0 },
90
+ * { id: 'permissions', name: 'Permissions Setup', index: 1 },
91
+ * { id: 'profile', name: 'Profile Creation', index: 2, isOptional: true },
92
+ * ]
93
+ * },
94
+ * userType: 'new',
95
+ * autoStart: true
96
+ * });
97
+ *
98
+ * // In your component
99
+ * const handleStepComplete = () => {
100
+ * analytics.trackStepCompleted('welcome', { interaction_method: 'button' });
101
+ * };
102
+ * ```
103
+ */
104
+ export function useOnboardingAnalytics(
105
+ config: UseOnboardingAnalyticsConfig,
106
+ ): OnboardingAnalyticsActions {
107
+ const postHogAdapter = usePostHogAnalyticsAdapter();
108
+ const analyticsServiceRef = useRef<OnboardingAnalyticsService | null>(null);
109
+
110
+ // Initialize analytics service
111
+ useEffect(() => {
112
+ let isActive = true;
113
+ const service = new OnboardingAnalyticsService(postHogAdapter);
114
+ analyticsServiceRef.current = service;
115
+
116
+ const bootstrap = async () => {
117
+ try {
118
+ await postHogAdapter.initialize();
119
+ if (config.autoStart && isActive) {
120
+ await service.startFlow(config.flowConfig, config.userType);
121
+ }
122
+ } catch (error) {
123
+ console.warn(
124
+ '[useOnboardingAnalytics] Failed to initialize analytics service',
125
+ error,
126
+ );
127
+ }
128
+ };
129
+
130
+ void bootstrap();
131
+
132
+ // Cleanup on unmount - track abandonment if session is active
133
+ return () => {
134
+ isActive = false;
135
+ if (analyticsServiceRef.current?.getCurrentSession()) {
136
+ analyticsServiceRef.current.trackFlowAbandoned('component_unmount');
137
+ }
138
+ };
139
+ }, [postHogAdapter, config.autoStart, config.userType, config.flowConfig]);
140
+
141
+ // Flow control functions
142
+ const startFlow = useCallback(async (): Promise<string> => {
143
+ if (!analyticsServiceRef.current) {
144
+ throw new Error('Analytics service not initialized');
145
+ }
146
+ return analyticsServiceRef.current.startFlow(
147
+ config.flowConfig,
148
+ config.userType,
149
+ );
150
+ }, [config.flowConfig, config.userType]);
151
+
152
+ const completeFlow = useCallback(async (): Promise<void> => {
153
+ if (!analyticsServiceRef.current) return;
154
+ await analyticsServiceRef.current.trackFlowCompleted();
155
+ }, []);
156
+
157
+ const abandonFlow = useCallback(async (reason?: string): Promise<void> => {
158
+ if (!analyticsServiceRef.current) return;
159
+ await analyticsServiceRef.current.trackFlowAbandoned(reason);
160
+ }, []);
161
+
162
+ // Step tracking functions
163
+ const trackStepViewed = useCallback(
164
+ async (stepId: string, properties?: Record<string, any>): Promise<void> => {
165
+ if (!analyticsServiceRef.current) return;
166
+ await analyticsServiceRef.current.trackStepViewed(stepId, properties);
167
+ },
168
+ [],
169
+ );
170
+
171
+ const trackStepCompleted = useCallback(
172
+ async (stepId: string, properties?: Record<string, any>): Promise<void> => {
173
+ if (!analyticsServiceRef.current) return;
174
+ await analyticsServiceRef.current.trackStepCompleted(stepId, properties);
175
+ },
176
+ [],
177
+ );
178
+
179
+ const trackStepSkipped = useCallback(
180
+ async (
181
+ stepId: string,
182
+ reason?: string,
183
+ properties?: Record<string, any>,
184
+ ): Promise<void> => {
185
+ if (!analyticsServiceRef.current) return;
186
+ await analyticsServiceRef.current.trackStepSkipped(
187
+ stepId,
188
+ reason,
189
+ properties,
190
+ );
191
+ },
192
+ [],
193
+ );
194
+
195
+ const trackStepRetried = useCallback(
196
+ async (
197
+ stepId: string,
198
+ attempt: number,
199
+ properties?: Record<string, any>,
200
+ ): Promise<void> => {
201
+ if (!analyticsServiceRef.current) return;
202
+ await analyticsServiceRef.current.trackStepRetried(
203
+ stepId,
204
+ attempt,
205
+ properties,
206
+ );
207
+ },
208
+ [],
209
+ );
210
+
211
+ const trackStepHelp = useCallback(
212
+ async (
213
+ stepId: string,
214
+ helpType?: string,
215
+ properties?: Record<string, any>,
216
+ ): Promise<void> => {
217
+ if (!analyticsServiceRef.current) return;
218
+ await analyticsServiceRef.current.trackStepHelpAccessed(
219
+ stepId,
220
+ helpType,
221
+ properties,
222
+ );
223
+ },
224
+ [],
225
+ );
226
+
227
+ // Navigation tracking
228
+ const trackNavigation = useCallback(
229
+ async (
230
+ direction: 'back' | 'forward',
231
+ fromStepId: string,
232
+ toStepId: string,
233
+ ): Promise<void> => {
234
+ if (!analyticsServiceRef.current) return;
235
+ await analyticsServiceRef.current.trackNavigation(
236
+ direction,
237
+ fromStepId,
238
+ toStepId,
239
+ );
240
+ },
241
+ [],
242
+ );
243
+
244
+ // State access functions
245
+ const getCurrentSession = useCallback((): OnboardingSession | null => {
246
+ return analyticsServiceRef.current?.getCurrentSession() || null;
247
+ }, []);
248
+
249
+ const getProgress = useCallback(() => {
250
+ return analyticsServiceRef.current?.getFlowProgress() || null;
251
+ }, []);
252
+
253
+ // Utility functions
254
+ const isStepCompleted = useCallback(
255
+ (stepId: string): boolean => {
256
+ const session = getCurrentSession();
257
+ return session?.completedSteps.includes(stepId) || false;
258
+ },
259
+ [getCurrentSession],
260
+ );
261
+
262
+ const isStepSkipped = useCallback(
263
+ (stepId: string): boolean => {
264
+ const session = getCurrentSession();
265
+ return session?.skippedSteps.includes(stepId) || false;
266
+ },
267
+ [getCurrentSession],
268
+ );
269
+
270
+ const getNextStep = useCallback(
271
+ (currentStepId: string): string | null => {
272
+ const step = config.flowConfig.steps.find((s) => s.id === currentStepId);
273
+ if (!step || step.index >= config.flowConfig.steps.length - 1)
274
+ return null;
275
+
276
+ const nextStep = config.flowConfig.steps.find(
277
+ (s) => s.index === step.index + 1,
278
+ );
279
+ return nextStep?.id || null;
280
+ },
281
+ [config.flowConfig.steps],
282
+ );
283
+
284
+ const getPreviousStep = useCallback(
285
+ (currentStepId: string): string | null => {
286
+ const step = config.flowConfig.steps.find((s) => s.id === currentStepId);
287
+ if (!step || step.index <= 0) return null;
288
+
289
+ const prevStep = config.flowConfig.steps.find(
290
+ (s) => s.index === step.index - 1,
291
+ );
292
+ return prevStep?.id || null;
293
+ },
294
+ [config.flowConfig.steps],
295
+ );
296
+
297
+ return {
298
+ // Flow control
299
+ startFlow,
300
+ completeFlow,
301
+ abandonFlow,
302
+
303
+ // Step tracking
304
+ trackStepViewed,
305
+ trackStepCompleted,
306
+ trackStepSkipped,
307
+ trackStepRetried,
308
+ trackStepHelp,
309
+
310
+ // Navigation
311
+ trackNavigation,
312
+
313
+ // State access
314
+ getCurrentSession,
315
+ getProgress,
316
+
317
+ // Utilities
318
+ isStepCompleted,
319
+ isStepSkipped,
320
+ getNextStep,
321
+ getPreviousStep,
322
+ };
323
+ }