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,189 @@
1
+ /**
2
+ * Message Handler Service
3
+ *
4
+ * Handles message submission and chat operations with Supabase backend.
5
+ */
6
+
7
+ import { Alert } from 'react-native';
8
+
9
+ import { defaultCacheService } from '@/core/cache';
10
+ import type { AppMessage } from '@/features/chatbot/types';
11
+ import { translate } from '@/lib';
12
+
13
+ export type AppAttachment = {
14
+ storageId: string;
15
+ url?: string;
16
+ mimeType?: string;
17
+ type: 'image';
18
+ fileName?: string;
19
+ };
20
+
21
+ type MessageSubmissionOptions = {
22
+ currentInput: string;
23
+ conversationId: string;
24
+ attachmentsFromInputBar?: {
25
+ type: 'image';
26
+ storageId: string;
27
+ fileName?: string;
28
+ mimeType?: string;
29
+ url?: string;
30
+ }[];
31
+ storeUserMessageMutation: {
32
+ mutateAsync: (args: {
33
+ conversationId: string;
34
+ authorType: 'user' | 'bot';
35
+ text?: string;
36
+ attachments?: {
37
+ type: 'image';
38
+ storageId: string;
39
+ fileName?: string;
40
+ mimeType?: string;
41
+ }[];
42
+ }) => Promise<{ id: string } | null>;
43
+ };
44
+ };
45
+
46
+ type ClearChatOptions = {
47
+ conversationId: string;
48
+ clearConversationMutation: {
49
+ mutateAsync: (args: { conversationId: string }) => Promise<any>;
50
+ };
51
+ onCleared?: () => void;
52
+ };
53
+
54
+ /**
55
+ * Service for handling message submission and chat operations
56
+ */
57
+ export class MessageHandlerService {
58
+ /**
59
+ * Store a user message to the database before sending to AI
60
+ */
61
+ static async storeUserMessage(
62
+ options: MessageSubmissionOptions,
63
+ ): Promise<string | null> {
64
+ const {
65
+ currentInput,
66
+ conversationId,
67
+ attachmentsFromInputBar,
68
+ storeUserMessageMutation,
69
+ } = options;
70
+
71
+ try {
72
+ console.log('[MessageHandlerService] Storing user message to DB...');
73
+ const result = await storeUserMessageMutation.mutateAsync({
74
+ conversationId,
75
+ authorType: 'user',
76
+ text: currentInput.trim() || undefined,
77
+ attachments: attachmentsFromInputBar?.map((att) => ({
78
+ type: 'image',
79
+ storageId: att.storageId,
80
+ fileName: att.fileName,
81
+ mimeType: att.mimeType,
82
+ url: att.url,
83
+ })),
84
+ });
85
+ console.log('[MessageHandlerService] User message stored successfully.');
86
+ return result?.id ?? null;
87
+ } catch (dbError) {
88
+ console.error(
89
+ '[MessageHandlerService] Failed to store user message:',
90
+ dbError,
91
+ );
92
+ Alert.alert(translate('common.error'), translate('chatbot.send_failed'), [
93
+ {
94
+ text: translate('common.ok'),
95
+ onPress: () => {
96
+ // Reset the useChat hook by reloading the data
97
+ defaultCacheService.removeItem(`conversation_${conversationId}`);
98
+ },
99
+ },
100
+ ]);
101
+ return null;
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Handle clearing a chat conversation
107
+ */
108
+ static clearChat(options: ClearChatOptions): void {
109
+ const { conversationId, clearConversationMutation } = options;
110
+
111
+ Alert.alert(
112
+ 'Clear Chat',
113
+ 'Are you sure you want to clear all messages? This action cannot be undone.',
114
+ [
115
+ {
116
+ text: 'Cancel',
117
+ style: 'cancel',
118
+ },
119
+ {
120
+ text: 'Clear',
121
+ style: 'destructive',
122
+ onPress: async () => {
123
+ try {
124
+ console.log(
125
+ '[MessageHandlerService] Clearing conversation:',
126
+ conversationId,
127
+ );
128
+ await clearConversationMutation.mutateAsync({
129
+ conversationId,
130
+ });
131
+ console.log(
132
+ '[MessageHandlerService] Conversation cleared successfully',
133
+ );
134
+
135
+ // Reset the useChat hook by reloading the data
136
+ defaultCacheService.removeItem(`conversation_${conversationId}`);
137
+ options.onCleared?.();
138
+ } catch (error) {
139
+ console.error(
140
+ '[MessageHandlerService] Failed to clear conversation:',
141
+ error,
142
+ );
143
+ Alert.alert('Error', 'Failed to clear chat. Please try again.');
144
+ }
145
+ },
146
+ },
147
+ ],
148
+ );
149
+ }
150
+
151
+ /**
152
+ * Transform display messages with stable attachment mapping
153
+ */
154
+ static transformDisplayMessages(
155
+ liveMessages: AppMessage[],
156
+ persistedMessages: AppMessage[],
157
+ lastUserAttachments?: AppAttachment[],
158
+ attachmentCache?: Record<string, AppAttachment[]>,
159
+ ): AppMessage[] {
160
+ const persisted = new Map(persistedMessages.map((m) => [m.id, m]));
161
+ const lastUserIdx = [...liveMessages]
162
+ .map((m, i) => ({ m, i }))
163
+ .reverse()
164
+ .find((x) => x.m.role === 'user')?.i;
165
+
166
+ return liveMessages.map((m, i) => {
167
+ const fromDb = persisted.get(m.id);
168
+ const isMostRecentUser = m.role === 'user' && i === lastUserIdx;
169
+ // Attachment precedence:
170
+ // 1) Cached attachments for this live message ID (persist across renders)
171
+ // 2) Most recent user's optimistic attachments (for immediate display)
172
+ // 3) Attachments from persisted DB messages when IDs align
173
+ const fromCache = attachmentCache?.[m.id];
174
+ const attachments =
175
+ fromCache && fromCache.length
176
+ ? fromCache
177
+ : ((isMostRecentUser && lastUserAttachments?.length
178
+ ? lastUserAttachments
179
+ : fromDb?.attachments) ?? undefined);
180
+
181
+ return {
182
+ ...m,
183
+ attachments,
184
+ toolCalls: m.toolCalls ?? fromDb?.toolCalls,
185
+ metadata: m.metadata ?? fromDb?.metadata,
186
+ };
187
+ });
188
+ }
189
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Chatbot Types
3
+ *
4
+ * Types for the chatbot feature using Supabase backend.
5
+ */
6
+
7
+ export type LocalMessageContentPart =
8
+ | { type: 'text'; text: string }
9
+ | { type: 'image'; image: string | URL };
10
+
11
+ export type MessageAttachment = {
12
+ type: 'image';
13
+ storageId: string;
14
+ url?: string;
15
+ fileName?: string;
16
+ mimeType?: string;
17
+ };
18
+
19
+ export type ToolCallRecord = {
20
+ toolName: string;
21
+ args: unknown;
22
+ result?: unknown;
23
+ };
24
+
25
+ export type MessageMetadata = {
26
+ streamId?: string;
27
+ status?: string;
28
+ usage?: {
29
+ promptTokens?: number;
30
+ completionTokens?: number;
31
+ totalTokens?: number;
32
+ };
33
+ };
34
+
35
+ export type AgentStatus =
36
+ | {
37
+ type: 'thinking';
38
+ label?: string | null;
39
+ startedAt: number;
40
+ }
41
+ | {
42
+ type: 'tool';
43
+ toolName: string;
44
+ label?: string | null;
45
+ startedAt: number;
46
+ };
47
+
48
+ export type AppMessage = {
49
+ id: string;
50
+ role: 'user' | 'assistant' | 'data';
51
+ content: string | LocalMessageContentPart[];
52
+ createdAt?: Date;
53
+ parts?: unknown; // Optional hook into AI SDK shapes when present
54
+ attachments?: MessageAttachment[];
55
+ toolCalls?: ToolCallRecord[];
56
+ metadata?: MessageMetadata;
57
+ };
58
+
59
+ export type ConversationMessageFromDB = {
60
+ id: string;
61
+ created_at: string;
62
+ author_type: 'user' | 'bot';
63
+ text?: string | null;
64
+ attachments?: MessageAttachment[] | null;
65
+ tool_calls?: ToolCallRecord[] | null;
66
+ metadata?: MessageMetadata | null;
67
+ };
68
+
69
+ // Legacy type alias for backward compatibility
70
+ /** @deprecated Use MessageAttachment instead */
@@ -0,0 +1,91 @@
1
+ import type { TelemetryMode } from '@/core/config';
2
+ import { getChatTelemetryMode } from '@/core/config/telemetry';
3
+
4
+ const DEFAULT_SAMPLE_PROBABILITY = 0.1;
5
+
6
+ type TimelineEntry = {
7
+ label: string;
8
+ msFromStart: number;
9
+ data?: Record<string, unknown>;
10
+ };
11
+
12
+ export type ChatTelemetryTracker = {
13
+ readonly event: string;
14
+ mark: (label: string, data?: Record<string, unknown>) => void;
15
+ finalize: (status: 'ok' | 'error', extra?: Record<string, unknown>) => void;
16
+ };
17
+
18
+ function shouldTrack(mode: TelemetryMode, probability: number): boolean {
19
+ if (mode === 'off') {
20
+ return false;
21
+ }
22
+ if (mode === 'debug') {
23
+ return true;
24
+ }
25
+
26
+ const clampedProbability = Math.min(Math.max(probability, 0), 1);
27
+ return Math.random() < clampedProbability;
28
+ }
29
+
30
+ export function createChatTelemetryTracker(
31
+ event: string,
32
+ baseContext: Record<string, unknown>,
33
+ sampleProbability = DEFAULT_SAMPLE_PROBABILITY,
34
+ ): ChatTelemetryTracker | null {
35
+ const mode = getChatTelemetryMode();
36
+ if (!shouldTrack(mode, sampleProbability)) {
37
+ return null;
38
+ }
39
+
40
+ const start = Date.now();
41
+ const timeline: TimelineEntry[] = [{ label: 'start', msFromStart: 0 }];
42
+ let finalized = false;
43
+
44
+ return {
45
+ event,
46
+ mark(label, data) {
47
+ if (finalized) {
48
+ return;
49
+ }
50
+ const elapsed = Date.now() - start;
51
+ timeline.push({
52
+ label,
53
+ msFromStart: elapsed,
54
+ data,
55
+ });
56
+ },
57
+ finalize(status, extra) {
58
+ if (finalized) {
59
+ return;
60
+ }
61
+ finalized = true;
62
+ const totalMs = Date.now() - start;
63
+ console.log('[chat][telemetry]', {
64
+ event,
65
+ mode,
66
+ status,
67
+ totalMs,
68
+ ...baseContext,
69
+ ...(extra ?? {}),
70
+ timeline,
71
+ });
72
+ },
73
+ };
74
+ }
75
+
76
+ export function logChatTelemetryEvent(
77
+ event: string,
78
+ payload: Record<string, unknown>,
79
+ sampleProbability = DEFAULT_SAMPLE_PROBABILITY,
80
+ ) {
81
+ const mode = getChatTelemetryMode();
82
+ if (!shouldTrack(mode, sampleProbability)) {
83
+ return;
84
+ }
85
+
86
+ console.log('[chat][telemetry]', {
87
+ event,
88
+ mode,
89
+ ...payload,
90
+ });
91
+ }
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Conversations Service
3
+ *
4
+ * Handles conversation operations including getOrCreateDefault, create, list, and delete.
5
+ *
6
+ * Requirements: 4.1, 4.2
7
+ */
8
+
9
+ import type { SupabaseClientType } from '../lib/supabase';
10
+ import type { Conversation } from '../types';
11
+
12
+ const DEFAULT_CONVERSATION_NAME = 'Default Chat';
13
+
14
+ export interface GetConversationResult {
15
+ success: boolean;
16
+ conversation?: Conversation;
17
+ error?: string;
18
+ }
19
+
20
+ export interface ListConversationsResult {
21
+ success: boolean;
22
+ conversations?: Conversation[];
23
+ error?: string;
24
+ }
25
+
26
+ export interface DeleteConversationResult {
27
+ success: boolean;
28
+ error?: string;
29
+ }
30
+
31
+ /**
32
+ * Get or create the default conversation for the current user
33
+ *
34
+ * This function returns an existing conversation named "Default Chat" or creates
35
+ * a new one if it doesn't exist. This ensures idempotency - calling multiple times
36
+ * always returns the same conversation.
37
+ *
38
+ * @param supabase - Supabase client (authenticated)
39
+ * @returns The default conversation
40
+ *
41
+ * Requirements: 4.1
42
+ */
43
+ export async function getOrCreateDefault(
44
+ supabase: SupabaseClientType
45
+ ): Promise<GetConversationResult> {
46
+ // Get the current auth user
47
+ const { data: authData, error: authError } = await supabase.auth.getUser();
48
+
49
+ if (authError || !authData.user) {
50
+ return { success: false, error: 'Not authenticated' };
51
+ }
52
+
53
+ const userId = authData.user.id;
54
+
55
+ // Try to find existing default conversation (use limit 1 to handle duplicates)
56
+ const { data: existingList, error: findError } = await supabase
57
+ .from('conversations')
58
+ .select('*')
59
+ .eq('user_id', userId)
60
+ .eq('name', DEFAULT_CONVERSATION_NAME)
61
+ .order('created_at', { ascending: true })
62
+ .limit(1);
63
+
64
+ if (findError) {
65
+ return { success: false, error: `Failed to find conversation: ${findError.message}` };
66
+ }
67
+
68
+ // Return existing if found
69
+ if (existingList && existingList.length > 0) {
70
+ return { success: true, conversation: existingList[0] };
71
+ }
72
+
73
+ // Create new default conversation
74
+ const { data: created, error: createError } = await supabase
75
+ .from('conversations')
76
+ .insert({
77
+ user_id: userId,
78
+ name: DEFAULT_CONVERSATION_NAME,
79
+ })
80
+ .select()
81
+ .single();
82
+
83
+ if (createError) {
84
+ return { success: false, error: `Failed to create conversation: ${createError.message}` };
85
+ }
86
+
87
+ return { success: true, conversation: created };
88
+ }
89
+
90
+
91
+ /**
92
+ * Create a new conversation
93
+ *
94
+ * @param supabase - Supabase client (authenticated)
95
+ * @param name - Optional name for the conversation
96
+ * @returns The created conversation
97
+ *
98
+ * Requirements: 4.2
99
+ */
100
+ export async function create(
101
+ supabase: SupabaseClientType,
102
+ name?: string
103
+ ): Promise<GetConversationResult> {
104
+ // Get the current auth user
105
+ const { data: authData, error: authError } = await supabase.auth.getUser();
106
+
107
+ if (authError || !authData.user) {
108
+ return { success: false, error: 'Not authenticated' };
109
+ }
110
+
111
+ const { data: conversation, error: createError } = await supabase
112
+ .from('conversations')
113
+ .insert({
114
+ user_id: authData.user.id,
115
+ name: name || null,
116
+ })
117
+ .select()
118
+ .single();
119
+
120
+ if (createError) {
121
+ return { success: false, error: `Failed to create conversation: ${createError.message}` };
122
+ }
123
+
124
+ return { success: true, conversation };
125
+ }
126
+
127
+ /**
128
+ * List all conversations for the current user
129
+ *
130
+ * @param supabase - Supabase client (authenticated)
131
+ * @returns List of conversations ordered by creation time (newest first)
132
+ *
133
+ * Requirements: 4.2
134
+ */
135
+ export async function list(
136
+ supabase: SupabaseClientType
137
+ ): Promise<ListConversationsResult> {
138
+ // Get the current auth user
139
+ const { data: authData, error: authError } = await supabase.auth.getUser();
140
+
141
+ if (authError || !authData.user) {
142
+ return { success: false, error: 'Not authenticated' };
143
+ }
144
+
145
+ const { data: conversations, error: listError } = await supabase
146
+ .from('conversations')
147
+ .select('*')
148
+ .eq('user_id', authData.user.id)
149
+ .order('created_at', { ascending: false });
150
+
151
+ if (listError) {
152
+ return { success: false, error: `Failed to list conversations: ${listError.message}` };
153
+ }
154
+
155
+ return { success: true, conversations: conversations || [] };
156
+ }
157
+
158
+ /**
159
+ * Delete a conversation
160
+ *
161
+ * This will also delete all messages in the conversation due to CASCADE.
162
+ *
163
+ * @param supabase - Supabase client (authenticated)
164
+ * @param conversationId - The ID of the conversation to delete
165
+ * @returns Success or error
166
+ *
167
+ * Requirements: 4.2
168
+ */
169
+ export async function deleteConversation(
170
+ supabase: SupabaseClientType,
171
+ conversationId: string
172
+ ): Promise<DeleteConversationResult> {
173
+ // Get the current auth user
174
+ const { data: authData, error: authError } = await supabase.auth.getUser();
175
+
176
+ if (authError || !authData.user) {
177
+ return { success: false, error: 'Not authenticated' };
178
+ }
179
+
180
+ if (!conversationId) {
181
+ return { success: false, error: 'Conversation ID is required' };
182
+ }
183
+
184
+ // Delete the conversation (RLS ensures user can only delete their own)
185
+ const { error: deleteError } = await supabase
186
+ .from('conversations')
187
+ .delete()
188
+ .eq('id', conversationId)
189
+ .eq('user_id', authData.user.id);
190
+
191
+ if (deleteError) {
192
+ return { success: false, error: `Failed to delete conversation: ${deleteError.message}` };
193
+ }
194
+
195
+ return { success: true };
196
+ }
197
+
198
+ /**
199
+ * Get a conversation by ID
200
+ *
201
+ * @param supabase - Supabase client (authenticated)
202
+ * @param conversationId - The ID of the conversation
203
+ * @returns The conversation or error
204
+ */
205
+ export async function getById(
206
+ supabase: SupabaseClientType,
207
+ conversationId: string
208
+ ): Promise<GetConversationResult> {
209
+ // Get the current auth user
210
+ const { data: authData, error: authError } = await supabase.auth.getUser();
211
+
212
+ if (authError || !authData.user) {
213
+ return { success: false, error: 'Not authenticated' };
214
+ }
215
+
216
+ if (!conversationId) {
217
+ return { success: false, error: 'Conversation ID is required' };
218
+ }
219
+
220
+ const { data: conversation, error: getError } = await supabase
221
+ .from('conversations')
222
+ .select('*')
223
+ .eq('id', conversationId)
224
+ .eq('user_id', authData.user.id)
225
+ .single();
226
+
227
+ if (getError) {
228
+ if (getError.code === 'PGRST116') {
229
+ return { success: false, error: 'Conversation not found' };
230
+ }
231
+ return { success: false, error: `Failed to get conversation: ${getError.message}` };
232
+ }
233
+
234
+ return { success: true, conversation };
235
+ }
236
+
237
+ export const conversationsService = {
238
+ getOrCreateDefault,
239
+ create,
240
+ list,
241
+ delete: deleteConversation,
242
+ getById,
243
+ };