vibefast-cli 1.1.5 → 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 (299) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +63 -169
  3. package/dist/commands/add.d.ts +1 -1
  4. package/dist/commands/add.d.ts.map +1 -1
  5. package/dist/commands/add.js +547 -589
  6. package/dist/commands/add.js.map +1 -1
  7. package/dist/commands/checklist.d.ts +1 -1
  8. package/dist/commands/checklist.d.ts.map +1 -1
  9. package/dist/commands/checklist.js +40 -39
  10. package/dist/commands/checklist.js.map +1 -1
  11. package/dist/commands/doctor.d.ts +1 -1
  12. package/dist/commands/doctor.js +22 -22
  13. package/dist/commands/doctor.js.map +1 -1
  14. package/dist/commands/env.d.ts +1 -1
  15. package/dist/commands/env.d.ts.map +1 -1
  16. package/dist/commands/env.js +58 -53
  17. package/dist/commands/env.js.map +1 -1
  18. package/dist/commands/health.d.ts +1 -1
  19. package/dist/commands/health.d.ts.map +1 -1
  20. package/dist/commands/health.js +101 -93
  21. package/dist/commands/health.js.map +1 -1
  22. package/dist/commands/init.d.ts +1 -1
  23. package/dist/commands/init.d.ts.map +1 -1
  24. package/dist/commands/init.js +416 -296
  25. package/dist/commands/init.js.map +1 -1
  26. package/dist/commands/remove.d.ts +1 -1
  27. package/dist/commands/remove.d.ts.map +1 -1
  28. package/dist/commands/remove.js +77 -64
  29. package/dist/commands/remove.js.map +1 -1
  30. package/dist/commands/status.d.ts +1 -1
  31. package/dist/commands/status.d.ts.map +1 -1
  32. package/dist/commands/status.js +15 -14
  33. package/dist/commands/status.js.map +1 -1
  34. package/dist/core/__tests__/detect.test.js +68 -34
  35. package/dist/core/__tests__/detect.test.js.map +1 -1
  36. package/dist/core/ast.d.ts +14 -0
  37. package/dist/core/ast.d.ts.map +1 -0
  38. package/dist/core/ast.js +239 -0
  39. package/dist/core/ast.js.map +1 -0
  40. package/dist/core/codemod.d.ts.map +1 -1
  41. package/dist/core/codemod.js +62 -44
  42. package/dist/core/codemod.js.map +1 -1
  43. package/dist/core/config.d.ts +10 -0
  44. package/dist/core/config.d.ts.map +1 -0
  45. package/dist/core/config.js +51 -0
  46. package/dist/core/config.js.map +1 -0
  47. package/dist/core/detect.d.ts +8 -2
  48. package/dist/core/detect.d.ts.map +1 -1
  49. package/dist/core/detect.js +52 -21
  50. package/dist/core/detect.js.map +1 -1
  51. package/dist/core/errors.d.ts.map +1 -1
  52. package/dist/core/errors.js +9 -8
  53. package/dist/core/errors.js.map +1 -1
  54. package/dist/core/exec.d.ts +16 -0
  55. package/dist/core/exec.d.ts.map +1 -0
  56. package/dist/core/exec.js +48 -0
  57. package/dist/core/exec.js.map +1 -0
  58. package/dist/core/manualSteps.d.ts +7 -0
  59. package/dist/core/manualSteps.d.ts.map +1 -0
  60. package/dist/core/manualSteps.js +59 -0
  61. package/dist/core/manualSteps.js.map +1 -0
  62. package/dist/core/paths.d.ts +3 -1
  63. package/dist/core/paths.d.ts.map +1 -1
  64. package/dist/core/paths.js +14 -10
  65. package/dist/core/paths.js.map +1 -1
  66. package/dist/core/spinner.d.ts +1 -1
  67. package/dist/core/spinner.d.ts.map +1 -1
  68. package/dist/core/spinner.js +38 -8
  69. package/dist/core/spinner.js.map +1 -1
  70. package/dist/core/vosk.d.ts.map +1 -1
  71. package/dist/core/vosk.js +50 -39
  72. package/dist/core/vosk.js.map +1 -1
  73. package/docs/manual-testing.md +91 -0
  74. package/package.json +6 -3
  75. package/recipes/audio-recorder/apps/native/src/app/audio-recorder/index.tsx +5 -0
  76. package/recipes/audio-recorder/recipe.json +3 -3
  77. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-player.tsx +301 -0
  78. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +373 -0
  79. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-waveform.tsx +270 -0
  80. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/index.ts +4 -0
  81. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/recording-list.tsx +89 -0
  82. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-player-demo.tsx +66 -0
  83. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-recorder-cloud.tsx +68 -0
  84. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-recorder-interview.tsx +102 -0
  85. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/basic.tsx +27 -0
  86. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/index.ts +5 -0
  87. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +82 -0
  88. package/recipes/audio-recorder-supabase/packages/backend/src/services/recordings.ts +369 -0
  89. package/recipes/audio-recorder-supabase/packages/backend/supabase/migrations/recordings.sql +70 -0
  90. package/recipes/audio-recorder-supabase/recipe.json +35 -0
  91. package/recipes/audio-recorder-supabase@latest.zip +0 -0
  92. package/recipes/audio-recorder@latest.zip +0 -0
  93. package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +3 -3
  94. package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +2 -2
  95. package/recipes/charts/apps/native/src/features/charts/components/chart-card.tsx +5 -5
  96. package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +3 -3
  97. package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +20 -4
  98. package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +7 -6
  99. package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +6 -4
  100. package/recipes/charts/apps/native/src/features/charts/components/radial-bar-chart.tsx +1 -1
  101. package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +5 -4
  102. package/recipes/charts/recipe.json +4 -13
  103. package/recipes/charts@latest.zip +0 -0
  104. package/recipes/chatbot/apps/native/src/app/chatbot/index.tsx +1 -0
  105. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +86 -86
  106. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +86 -53
  107. package/recipes/chatbot/recipe.json +26 -92
  108. package/recipes/chatbot-supabase/apps/native/src/api-client/supabase/chatbot.ts +515 -0
  109. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/app/index.tsx +257 -0
  110. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-header-buttons.tsx +59 -0
  111. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-input-bar.tsx +485 -0
  112. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-markdown.tsx +575 -0
  113. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-message-bubble.tsx +223 -0
  114. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-settings-modal.tsx +161 -0
  115. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/image-preview-list.tsx +116 -0
  116. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/code-block.tsx +165 -0
  117. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/index.ts +10 -0
  118. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/table-renderer.tsx +129 -0
  119. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/message-error-boundary.tsx +78 -0
  120. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/message-list.tsx +170 -0
  121. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/model-selector.tsx +283 -0
  122. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/report-content-modal.tsx +188 -0
  123. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/suggested-messages.tsx +67 -0
  124. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/constants/models.ts +20 -0
  125. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/constants/report-reasons.ts +9 -0
  126. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-attachment-cache.ts +142 -0
  127. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chat-config.ts +458 -0
  128. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chat-handlers.ts +429 -0
  129. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chatbot-settings.ts +89 -0
  130. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-conversation.ts +90 -0
  131. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-image-picker.ts +122 -0
  132. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-keyboard-coordinator.ts +161 -0
  133. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-smart-scroll-manager.ts +213 -0
  134. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/index.ts +86 -0
  135. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/models.ts +162 -0
  136. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/providers.ts +62 -0
  137. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/types.ts +40 -0
  138. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/services/file-uploader.ts +287 -0
  139. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/services/message-handler-service.ts +189 -0
  140. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/types/index.ts +70 -0
  141. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/utils/chat-telemetry.ts +91 -0
  142. package/recipes/chatbot-supabase/packages/backend/src/services/conversations.ts +243 -0
  143. package/recipes/chatbot-supabase/packages/backend/src/services/messages.ts +327 -0
  144. package/recipes/chatbot-supabase/packages/backend/supabase/functions/chat-stream/index.ts +347 -0
  145. package/recipes/chatbot-supabase/packages/backend/supabase/migrations/chatbot.sql +104 -0
  146. package/recipes/chatbot-supabase/recipe.json +79 -0
  147. package/recipes/chatbot-supabase@latest.zip +0 -0
  148. package/recipes/chatbot.zip +0 -0
  149. package/recipes/chatbot@latest.zip +0 -0
  150. package/recipes/image-analysis/packages/backend/convex/imageAnalysis/index.ts +2 -2
  151. package/recipes/image-analysis/packages/backend/convex/imageAnalysis.ts +0 -1
  152. package/recipes/image-analysis/recipe.json +15 -55
  153. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/analysis-options-screen.tsx +304 -0
  154. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/camera.tsx +221 -0
  155. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/image-capture-screen.tsx +333 -0
  156. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/loading-screen.tsx +214 -0
  157. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/loading.tsx +191 -0
  158. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/results.tsx +137 -0
  159. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/trait-details.tsx +172 -0
  160. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/use-analysis-data.ts +160 -0
  161. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/use-results-screen.ts +151 -0
  162. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-badge.tsx +77 -0
  163. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-card.tsx +75 -0
  164. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-unlocked-modal.tsx +162 -0
  165. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievements-section.tsx +44 -0
  166. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/advice-list.tsx +42 -0
  167. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/circular-progress.tsx +233 -0
  168. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/content-card.tsx +38 -0
  169. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/error-state.tsx +42 -0
  170. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/index.ts +9 -0
  171. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/loading-state.tsx +26 -0
  172. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/profile-image.tsx +60 -0
  173. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/results-header.tsx +62 -0
  174. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/score-display.tsx +54 -0
  175. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/share-options-modal.tsx +110 -0
  176. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/traits-grid.tsx +74 -0
  177. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/config/analysis-config.ts +80 -0
  178. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/config/master-analysis-config.ts +157 -0
  179. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/index.ts +1 -0
  180. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/use-analysis.ts +38 -0
  181. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/use-image-analysis.ts +208 -0
  182. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/analysis-service.ts +262 -0
  183. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/share-service.ts +176 -0
  184. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/trait-details-service.ts +289 -0
  185. package/recipes/image-analysis-supabase/packages/backend/src/services/image-analyses.ts +132 -0
  186. package/recipes/image-analysis-supabase/packages/backend/supabase/functions/analyze-image/index.ts +312 -0
  187. package/recipes/image-analysis-supabase/packages/backend/supabase/migrations/image_analysis.sql +42 -0
  188. package/recipes/image-analysis-supabase/recipe.json +57 -0
  189. package/recipes/image-analysis-supabase@latest.zip +0 -0
  190. package/recipes/image-analysis@latest.zip +0 -0
  191. package/recipes/image-generator/apps/native/src/features/image-generator/app/index.tsx +16 -2
  192. package/recipes/image-generator/apps/native/src/features/image-generator/components/image-model-selector.tsx +11 -5
  193. package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator.ts +11 -5
  194. package/recipes/image-generator/packages/backend/convex/imageGeneration/index.ts +2 -2
  195. package/recipes/image-generator/recipe.json +16 -39
  196. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/_layout.tsx +26 -0
  197. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/gallery.tsx +217 -0
  198. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/index.tsx +251 -0
  199. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/gallery-image.tsx +25 -0
  200. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-detail-modal.tsx +215 -0
  201. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-model-selector.tsx +216 -0
  202. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-placeholder.tsx +26 -0
  203. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-gallery.ts +71 -0
  204. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-generator-settings.ts +152 -0
  205. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-generator.ts +103 -0
  206. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/models/models.ts +66 -0
  207. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/services/image-gallery-service.ts +96 -0
  208. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/services/image-save-service.ts +120 -0
  209. package/recipes/image-generator-supabase/packages/backend/supabase/functions/generate-image/index.ts +291 -0
  210. package/recipes/image-generator-supabase/packages/backend/supabase/migrations/image_generator.sql +71 -0
  211. package/recipes/image-generator-supabase/recipe.json +59 -0
  212. package/recipes/image-generator-supabase@latest.zip +0 -0
  213. package/recipes/image-generator@latest.zip +0 -0
  214. package/recipes/ios-widget/recipe.json +15 -24
  215. package/recipes/ios-widget@latest.zip +0 -0
  216. package/recipes/onboarding/apps/native/src/features/onboarding/analytics/index.ts +9 -0
  217. package/recipes/onboarding/apps/native/src/features/onboarding/components/onboarding-with-analytics.tsx +141 -0
  218. package/recipes/onboarding/apps/native/src/features/onboarding/components/onboarding.tsx +173 -0
  219. package/recipes/onboarding/apps/native/src/features/onboarding/config/onboarding-flow-config.ts +189 -0
  220. package/recipes/onboarding/apps/native/src/features/onboarding/demo-one/app/index.tsx +42 -0
  221. package/recipes/onboarding/apps/native/src/features/onboarding/demo-one/data.ts +32 -0
  222. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/app/index.tsx +43 -0
  223. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/interactive-onboarding.tsx +222 -0
  224. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/ai-tone-step.tsx +133 -0
  225. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/currency-step.tsx +165 -0
  226. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-ai-step.tsx +199 -0
  227. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-chatbot-step.tsx +154 -0
  228. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-manual-step.tsx +156 -0
  229. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-scan-step.tsx +158 -0
  230. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/main-reason-step.tsx +139 -0
  231. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/notification-step.tsx +129 -0
  232. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/overspend-step.tsx +138 -0
  233. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/personalizing-step.tsx +190 -0
  234. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/rating-step.tsx +98 -0
  235. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/reminder-step.tsx +181 -0
  236. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/safety-step.tsx +110 -0
  237. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/struggle-step.tsx +139 -0
  238. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/welcome-step.tsx +217 -0
  239. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/ui/onboarding-header.tsx +58 -0
  240. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/constants.ts +179 -0
  241. package/recipes/onboarding/apps/native/src/features/onboarding/hooks/use-onboarding-analytics.ts +323 -0
  242. package/recipes/onboarding/apps/native/src/features/onboarding/services/onboarding-analytics.ts +432 -0
  243. package/recipes/onboarding/recipe.json +15 -0
  244. package/recipes/onboarding@latest.zip +0 -0
  245. package/recipes/payments/recipe.json +28 -61
  246. package/recipes/payments-supabase/apps/native/src/features/payments/README.md +200 -0
  247. package/recipes/payments-supabase/apps/native/src/features/payments/app/local-paywall.tsx +194 -0
  248. package/recipes/payments-supabase/apps/native/src/features/payments/app/remote-paywall.tsx +79 -0
  249. package/recipes/payments-supabase/apps/native/src/features/payments/components/payment-initializer.tsx +95 -0
  250. package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-error-state.tsx +60 -0
  251. package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-local-mode.tsx +116 -0
  252. package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-product-card.tsx +133 -0
  253. package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-remote-mode.tsx +146 -0
  254. package/recipes/payments-supabase/apps/native/src/features/payments/hooks/use-entitlement.ts +63 -0
  255. package/recipes/payments-supabase/apps/native/src/features/payments/index.ts +8 -0
  256. package/recipes/payments-supabase/apps/native/src/features/payments/services/revenuecat-adapter.ts +407 -0
  257. package/recipes/payments-supabase/packages/backend/src/services/payments.ts +201 -0
  258. package/recipes/payments-supabase/packages/backend/supabase/migrations/payments.sql +35 -0
  259. package/recipes/payments-supabase/recipe.json +51 -0
  260. package/recipes/payments-supabase@latest.zip +0 -0
  261. package/recipes/payments@latest.zip +0 -0
  262. package/recipes/quiz/apps/native/src/features/quiz/index.tsx +1 -2
  263. package/recipes/quiz/recipe.json +6 -9
  264. package/recipes/quiz@latest.zip +0 -0
  265. package/recipes/tracker-app/apps/native/src/features/tracker-app/app/index.tsx +1 -2
  266. package/recipes/tracker-app/recipe.json +7 -10
  267. package/recipes/tracker-app@latest.zip +0 -0
  268. package/recipes/voice-bot/recipe.json +8 -68
  269. package/recipes/voice-bot.zip +0 -0
  270. package/recipes/voice-bot@latest.zip +0 -0
  271. package/recipes/wake-word/recipe.json +10 -9
  272. package/recipes/wake-word.zip +0 -0
  273. package/recipes/wake-word@latest.zip +0 -0
  274. package/recipes/charts/apps/native/src/app/(root)/(protected)/charts/index.tsx +0 -3
  275. package/recipes/chatbot/packages/backend/convex/lib/rateLimit.ts +0 -100
  276. package/recipes/chatbot/packages/backend/convex/lib/telemetry.ts +0 -29
  277. package/recipes/chatbot/packages/backend/convex/ragKnowledge.ts +0 -0
  278. package/recipes/image-analysis/apps/native/assets/features/image-analyzer/front.jpg +0 -0
  279. package/recipes/image-analysis/apps/native/assets/features/image-analyzer/side.jpg +0 -0
  280. package/recipes/image-analysis/apps/native/assets/features/image-analyzer/threeQuarter.jpg +0 -0
  281. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/_layout.tsx +0 -5
  282. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/analysis-options.tsx +0 -50
  283. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/camera.tsx +0 -2
  284. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/index.tsx +0 -50
  285. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/loading.tsx +0 -50
  286. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/results.tsx +0 -2
  287. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/trait-details.tsx +0 -3
  288. package/recipes/image-analysis/packages/backend/convex/imageAnalysisFunctions.ts +0 -325
  289. package/recipes/image-analysis/packages/backend/convex/lib/ai/imageAnalysisAdapter.ts +0 -200
  290. package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/index.tsx +0 -74
  291. package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/local.tsx +0 -25
  292. package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/remote.tsx +0 -23
  293. package/recipes/quiz/apps/native/src/app/(root)/(protected)/quiz/index.tsx +0 -47
  294. package/recipes/tracker-app/apps/native/src/app/(root)/(protected)/tracker-app/index.tsx +0 -1
  295. package/recipes/voice-bot/apps/native/src/app/(root)/(protected)/voice-bot/index.tsx +0 -27
  296. package/recipes/voice-bot/packages/backend/convex/router.ts +0 -81
  297. /package/recipes/{chatbot/apps/native/src/app/(root)/(protected) → chatbot-supabase/apps/native/src/app}/chatbot/index.tsx +0 -0
  298. /package/recipes/{image-generator/apps/native/src/app/(root)/(protected) → image-generator-supabase/apps/native/src/app}/image-generator/gallery.tsx +0 -0
  299. /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,162 @@
1
+ import type { ModelConfig, Provider } from './types';
2
+
3
+ export const MODELS: ModelConfig[] = [
4
+ // Claude Models
5
+ {
6
+ id: 'claude-4-sonnet',
7
+ name: 'Claude 4 Sonnet',
8
+ provider: 'claude',
9
+ description: 'Most capable • Great at coding',
10
+ category: 'premium',
11
+ capabilities: ['coding', 'reasoning', 'analysis', 'writing'],
12
+ contextWindow: 200000,
13
+ speed: 'medium',
14
+ released: '2024',
15
+ tags: ['latest', 'most-capable'],
16
+ },
17
+ {
18
+ id: 'claude-4.5-sonnet',
19
+ name: 'Claude 4.5 Sonnet',
20
+ provider: 'claude',
21
+ description: 'Fast & efficient • Perfect for chat',
22
+ category: 'premium',
23
+ capabilities: ['chat', 'reasoning', 'coding', 'analysis'],
24
+ contextWindow: 200000,
25
+ speed: 'fast',
26
+ released: '2024',
27
+ tags: ['balanced', 'chat-optimized'],
28
+ },
29
+
30
+ // OpenAI Models
31
+ {
32
+ id: 'gpt-5',
33
+ name: 'GPT-5',
34
+ provider: 'openai',
35
+ description: 'For complex tasks and thinking',
36
+ category: 'premium',
37
+ capabilities: ['reasoning', 'coding', 'analysis', 'mathematics'],
38
+ contextWindow: 200000,
39
+ speed: 'medium',
40
+ released: '2024',
41
+ tags: ['most-capable', 'complex-tasks'],
42
+ },
43
+ {
44
+ id: 'gpt-5-mini',
45
+ name: 'GPT-5 Mini',
46
+ provider: 'openai',
47
+ description: 'Quick thinking & reliable',
48
+ category: 'free',
49
+ capabilities: ['chat', 'reasoning', 'coding', 'analysis'],
50
+ contextWindow: 128000,
51
+ speed: 'fast',
52
+ released: '2024',
53
+ tags: ['balanced', 'efficient'],
54
+ },
55
+ {
56
+ id: 'gpt-5-nano',
57
+ name: 'GPT-5 Nano',
58
+ provider: 'openai',
59
+ description: 'Very fast • Great for basic work',
60
+ category: 'free',
61
+ capabilities: ['chat', 'basic-tasks', 'quick-responses'],
62
+ contextWindow: 16000,
63
+ speed: 'fast',
64
+ released: '2024',
65
+ tags: ['fastest', 'basic-tasks'],
66
+ },
67
+ {
68
+ id: 'gpt-4o-mini',
69
+ name: 'GPT-4o Mini',
70
+ provider: 'openai',
71
+ description: 'Very fast • Great for basic work',
72
+ category: 'free',
73
+ capabilities: ['chat', 'basic-tasks', 'quick-responses'],
74
+ contextWindow: 16000,
75
+ speed: 'fast',
76
+ released: '2024',
77
+ tags: ['fastest', 'basic-tasks'],
78
+ },
79
+
80
+ // Gemini Models
81
+ {
82
+ id: 'gemini-2.0-flash',
83
+ name: 'Gemini 2.0 Flash',
84
+ provider: 'gemini',
85
+ description: 'Latest model • Ultra fast',
86
+ category: 'free',
87
+ capabilities: ['chat', 'reasoning', 'multimodal', 'coding'],
88
+ contextWindow: 1000000,
89
+ speed: 'fast',
90
+ released: '2024',
91
+ tags: ['latest', 'multimodal', 'fast'],
92
+ },
93
+ {
94
+ id: 'gemini-2.5-flash',
95
+ name: 'Gemini 2.5 Flash',
96
+ provider: 'gemini',
97
+ description: 'Balanced • Great performance',
98
+ category: 'free',
99
+ capabilities: ['chat', 'reasoning', 'multimodal', 'analysis'],
100
+ contextWindow: 1000000,
101
+ speed: 'fast',
102
+ released: '2024',
103
+ tags: ['balanced', 'multimodal'],
104
+ },
105
+ {
106
+ id: 'gemini-2.5-pro',
107
+ name: 'Gemini 2.5 Pro',
108
+ provider: 'gemini',
109
+ description: 'Advanced reasoning',
110
+ category: 'premium',
111
+ capabilities: ['reasoning', 'coding', 'mathematics', 'analysis'],
112
+ contextWindow: 2000000,
113
+ speed: 'medium',
114
+ released: '2024',
115
+ tags: ['most-capable', 'advanced-reasoning'],
116
+ },
117
+ ];
118
+
119
+ // Helper to get models by provider
120
+ export const getModelsByProvider = (provider: Provider): ModelConfig[] => {
121
+ return MODELS.filter((model) => model.provider === provider);
122
+ };
123
+
124
+ // Helper to get premium models
125
+ export const getPremiumModels = (): ModelConfig[] => {
126
+ return MODELS.filter((model) => model.category === 'premium');
127
+ };
128
+
129
+ // Helper to get free models
130
+ export const getFreeModels = (): ModelConfig[] => {
131
+ return MODELS.filter((model) => model.category === 'free');
132
+ };
133
+
134
+ // Helper to get model by ID
135
+ export const getModelById = (id: string): ModelConfig | undefined => {
136
+ return MODELS.find((model) => model.id === id);
137
+ };
138
+
139
+ // Default models for each provider
140
+ export const DEFAULT_MODELS: Record<Provider, string> = {
141
+ claude: 'claude-4.5-sonnet',
142
+ openai: 'gpt-5-nano',
143
+ gemini: 'gemini-2.0-flash',
144
+ };
145
+
146
+ // Get default model for a provider
147
+ export const getDefaultModel = (provider: Provider): ModelConfig => {
148
+ const defaultId = DEFAULT_MODELS[provider];
149
+ const model = getModelById(defaultId);
150
+ if (!model) {
151
+ throw new Error(
152
+ `Default model ${defaultId} not found for provider ${provider}`,
153
+ );
154
+ }
155
+ return model;
156
+ };
157
+
158
+ // Get model description (single source of truth)
159
+ export const getModelDescription = (modelId: string): string => {
160
+ const model = getModelById(modelId);
161
+ return model?.description || 'AI model';
162
+ };
@@ -0,0 +1,62 @@
1
+ import type React from 'react';
2
+
3
+ import { ClaudeIcon } from '@/components/ui/icons/claude';
4
+ import { GeminiIcon } from '@/components/ui/icons/gemini';
5
+ import { OpenaiIcon } from '@/components/ui/icons/openai';
6
+
7
+ import type { Provider, ProviderConfig } from './types';
8
+
9
+ export const PROVIDER_CONFIGS: Record<Provider, ProviderConfig> = {
10
+ claude: {
11
+ id: 'claude',
12
+ name: 'claude',
13
+ displayName: 'Anthropic Claude',
14
+ icon: ClaudeIcon,
15
+ defaultModel: 'claude-4.5-sonnet',
16
+ description: 'Advanced AI assistant with strong reasoning capabilities',
17
+ website: 'https://anthropic.com',
18
+ color: '#D97706',
19
+ },
20
+ openai: {
21
+ id: 'openai',
22
+ name: 'openai',
23
+ displayName: 'OpenAI',
24
+ icon: OpenaiIcon,
25
+ defaultModel: 'gpt-5-nano',
26
+ description: 'Leading AI research lab and ChatGPT creator',
27
+ website: 'https://openai.com',
28
+ color: '#10A37F',
29
+ },
30
+ gemini: {
31
+ id: 'gemini',
32
+ name: 'gemini',
33
+ displayName: 'Google Gemini',
34
+ icon: GeminiIcon,
35
+ defaultModel: 'gemini-2.0-flash',
36
+ description: "Google's multimodal AI models",
37
+ website: 'https://gemini.google.com',
38
+ color: '#4285F4',
39
+ },
40
+ };
41
+
42
+ // Get provider config by ID
43
+ export const getProviderConfig = (provider: Provider): ProviderConfig => {
44
+ return PROVIDER_CONFIGS[provider];
45
+ };
46
+
47
+ // Get all providers
48
+ export const getAllProviders = (): Provider[] => {
49
+ return Object.keys(PROVIDER_CONFIGS) as Provider[];
50
+ };
51
+
52
+ // Get provider icon component
53
+ export const getProviderIcon = (
54
+ provider: Provider,
55
+ ): React.ComponentType<any> => {
56
+ return PROVIDER_CONFIGS[provider].icon;
57
+ };
58
+
59
+ // Get provider display name
60
+ export const getProviderDisplayName = (provider: Provider): string => {
61
+ return PROVIDER_CONFIGS[provider].displayName;
62
+ };
@@ -0,0 +1,40 @@
1
+ export type Provider = 'claude' | 'openai' | 'gemini';
2
+
3
+ export type ModelCategory = 'free' | 'premium' | 'specialized';
4
+
5
+ export type ModelSpeed = 'fast' | 'medium' | 'slow';
6
+
7
+ export interface ModelConfig {
8
+ id: string;
9
+ name: string;
10
+ provider: Provider;
11
+ description: string;
12
+ category: ModelCategory;
13
+ capabilities: string[];
14
+ contextWindow?: number;
15
+ speed?: ModelSpeed;
16
+ released?: string;
17
+ tags?: string[];
18
+ }
19
+
20
+ export interface ProviderConfig {
21
+ id: Provider;
22
+ name: string;
23
+ displayName: string;
24
+ icon: React.ComponentType<any>;
25
+ defaultModel: string;
26
+ description: string;
27
+ website?: string;
28
+ color?: string;
29
+ }
30
+
31
+ export interface ModelOptions {
32
+ models: ModelConfig[];
33
+ providers: ProviderConfig[];
34
+ categories: Record<ModelCategory, ModelConfig[]>;
35
+ byProvider: Record<Provider, ModelConfig[]>;
36
+ premium: ModelConfig[];
37
+ free: ModelConfig[];
38
+ }
39
+
40
+ export type ModelId = string;
@@ -0,0 +1,287 @@
1
+ import { Buffer } from 'buffer';
2
+ // Use legacy FS API to avoid deprecation errors in RN runtime
3
+ import * as FileSystem from 'expo-file-system/legacy';
4
+ import { manipulateAsync, SaveFormat } from 'expo-image-manipulator';
5
+ import { Image } from 'react-native';
6
+
7
+ import { getSupabase } from '@/api-client/supabase/client';
8
+ import { handleError } from '@/components/ui';
9
+ import { error as logError, info } from '@/core/logging';
10
+
11
+ // Configuration constants for Supabase uploads
12
+ const CONFIG = {
13
+ MAX_IMAGE_DIMENSION: 1024,
14
+ COMPRESSION_QUALITY: 0.7,
15
+ MAX_FILE_SIZE_MB: 2,
16
+ MAX_FILE_SIZE_BYTES: 2 * 1024 * 1024, // 2MB
17
+ } as const;
18
+
19
+ const TARGET_ASPECT_RATIO = 16 / 9;
20
+
21
+ /**
22
+ * Service for uploading images to Supabase Storage
23
+ */
24
+ export class FileUploadService {
25
+ /**
26
+ * Uploads an image file to Supabase storage
27
+ */
28
+ async uploadImage(
29
+ fileUri: string,
30
+ fileName?: string,
31
+ mimeTypeHint?: string,
32
+ ): Promise<string> {
33
+ try {
34
+ info('Starting image upload process', {
35
+ feature: 'chatbot.file_upload',
36
+ fileUri,
37
+ });
38
+
39
+ // Step 1: Compress and optimize the image
40
+ const optimizedUri = await this.optimizeImage(fileUri);
41
+ if (!optimizedUri) {
42
+ throw new Error('Failed to optimize image');
43
+ }
44
+
45
+ // Step 2: Validate file size using FileSystem (works on React Native)
46
+ const infoResult = await FileSystem.getInfoAsync(optimizedUri);
47
+ if (!infoResult.exists) {
48
+ throw new Error('Optimized file is missing');
49
+ }
50
+
51
+ const fileSize = infoResult.size ?? 0;
52
+
53
+ if (fileSize > CONFIG.MAX_FILE_SIZE_BYTES) {
54
+ throw new Error(
55
+ `File size (${(fileSize / 1024 / 1024).toFixed(1)}MB) exceeds maximum allowed size of ${CONFIG.MAX_FILE_SIZE_MB}MB`,
56
+ );
57
+ }
58
+
59
+ info('Image optimized and validated', {
60
+ feature: 'chatbot.file_upload',
61
+ originalUri: fileUri,
62
+ optimizedUri,
63
+ fileSize,
64
+ });
65
+
66
+ const supabase = getSupabase();
67
+ const contentType = mimeTypeHint || 'image/jpeg';
68
+ const finalFileName = fileName ?? this.buildFileName(contentType);
69
+
70
+ const { data: sessionData, error: sessionError } =
71
+ await supabase.auth.getSession();
72
+ if (sessionError || !sessionData.session?.access_token) {
73
+ throw new Error('Not authenticated');
74
+ }
75
+
76
+ const {
77
+ data: { user },
78
+ error: authError,
79
+ } = await supabase.auth.getUser();
80
+ if (authError || !user) {
81
+ throw new Error('Not authenticated');
82
+ }
83
+
84
+ const storagePath = `${user.id}/${finalFileName}`;
85
+ // Read file as base64 and convert to binary for upload
86
+ const base64 = await FileSystem.readAsStringAsync(optimizedUri, {
87
+ encoding: FileSystem.EncodingType.Base64,
88
+ });
89
+ const fileBytes = Buffer.from(base64, 'base64');
90
+
91
+ const { data: uploadData, error: uploadError } = await supabase.storage
92
+ .from('chat-attachments')
93
+ .upload(storagePath, fileBytes, {
94
+ contentType,
95
+ upsert: true,
96
+ });
97
+
98
+ if (uploadError) {
99
+ console.error('[chatbot.file_upload] Storage upload failed', {
100
+ message: uploadError.message,
101
+ });
102
+ throw new Error(
103
+ uploadError.message || 'Failed to upload image to storage',
104
+ );
105
+ }
106
+
107
+ info('Image uploaded successfully', {
108
+ feature: 'chatbot.file_upload',
109
+ storageId: uploadData?.path ?? storagePath,
110
+ fileSize,
111
+ });
112
+
113
+ return uploadData?.path ?? storagePath;
114
+ } catch (error) {
115
+ const err =
116
+ error instanceof Error
117
+ ? error
118
+ : new Error(
119
+ typeof error === 'string' ? error : 'Unknown upload error',
120
+ );
121
+
122
+ handleError(err, {
123
+ feature: 'chatbot.file_upload',
124
+ fallbackMessage: 'Failed to upload image',
125
+ });
126
+
127
+ throw err;
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Optimizes an image by resizing and compressing it while preserving aspect ratio and alpha
133
+ */
134
+ private async optimizeImage(fileUri: string): Promise<string | null> {
135
+ try {
136
+ // Detect image format to preserve alpha channels
137
+ const response = await fetch(fileUri);
138
+ const blob = await response.blob();
139
+ const isPng = blob.type?.includes('png');
140
+ const isWebp = blob.type?.includes('webp');
141
+
142
+ const actions: Parameters<typeof manipulateAsync>[1][number][] = [];
143
+
144
+ try {
145
+ const { width, height } = await this.getImageDimensions(fileUri);
146
+ const cropRect = this.calculateCenterCrop(width, height);
147
+
148
+ if (cropRect) {
149
+ actions.push({ crop: cropRect });
150
+ }
151
+
152
+ const workingWidth = cropRect ? cropRect.width : width;
153
+ const workingHeight = cropRect ? cropRect.height : height;
154
+ const resize = this.calculateResizeDimensions(
155
+ workingWidth,
156
+ workingHeight,
157
+ );
158
+
159
+ if (resize) {
160
+ actions.push({ resize });
161
+ }
162
+ } catch (dimensionError) {
163
+ logError(
164
+ dimensionError instanceof Error
165
+ ? dimensionError
166
+ : new Error('Failed to read image dimensions'),
167
+ { feature: 'chatbot.file_upload', fileUri },
168
+ );
169
+
170
+ actions.push({
171
+ resize: {
172
+ width: CONFIG.MAX_IMAGE_DIMENSION,
173
+ },
174
+ });
175
+ }
176
+
177
+ const result = await manipulateAsync(fileUri, actions, {
178
+ compress: CONFIG.COMPRESSION_QUALITY,
179
+ format: isPng
180
+ ? SaveFormat.PNG
181
+ : isWebp
182
+ ? SaveFormat.WEBP
183
+ : SaveFormat.JPEG,
184
+ });
185
+
186
+ return result.uri;
187
+ } catch (error) {
188
+ logError(
189
+ error instanceof Error ? error : new Error('Failed to optimize image'),
190
+ { feature: 'chatbot.file_upload', fileUri },
191
+ );
192
+ return null;
193
+ }
194
+ }
195
+
196
+ private getImageDimensions(
197
+ uri: string,
198
+ ): Promise<{ width: number; height: number }> {
199
+ return new Promise((resolve, reject) => {
200
+ Image.getSize(
201
+ uri,
202
+ (width, height) => resolve({ width, height }),
203
+ (error) => reject(error),
204
+ );
205
+ });
206
+ }
207
+
208
+ private calculateCenterCrop(
209
+ width: number,
210
+ height: number,
211
+ ): {
212
+ originX: number;
213
+ originY: number;
214
+ width: number;
215
+ height: number;
216
+ } | null {
217
+ const aspectRatio = width / height;
218
+
219
+ if (Math.abs(aspectRatio - TARGET_ASPECT_RATIO) < 0.01) {
220
+ return null;
221
+ }
222
+
223
+ if (aspectRatio > TARGET_ASPECT_RATIO) {
224
+ const targetWidth = Math.round(height * TARGET_ASPECT_RATIO);
225
+ const originX = Math.round((width - targetWidth) / 2);
226
+
227
+ return {
228
+ originX,
229
+ originY: 0,
230
+ width: targetWidth,
231
+ height,
232
+ };
233
+ }
234
+
235
+ const targetHeight = Math.round(width / TARGET_ASPECT_RATIO);
236
+ const originY = Math.round((height - targetHeight) / 2);
237
+
238
+ return {
239
+ originX: 0,
240
+ originY,
241
+ width,
242
+ height: targetHeight,
243
+ };
244
+ }
245
+
246
+ private calculateResizeDimensions(
247
+ width: number,
248
+ height: number,
249
+ ): { width: number; height: number } | null {
250
+ const largestSide = Math.max(width, height);
251
+
252
+ if (largestSide <= CONFIG.MAX_IMAGE_DIMENSION) {
253
+ return null;
254
+ }
255
+
256
+ const scale = CONFIG.MAX_IMAGE_DIMENSION / largestSide;
257
+
258
+ return {
259
+ width: Math.round(width * scale),
260
+ height: Math.round(height * scale),
261
+ };
262
+ }
263
+
264
+ private buildFileName(contentType: string): string {
265
+ const ext = this.mapContentTypeToExtension(contentType);
266
+ const rand = Math.random().toString(36).slice(2, 8);
267
+ return `chat-${Date.now()}-${rand}.${ext}`;
268
+ }
269
+
270
+ private mapContentTypeToExtension(contentType?: string): string {
271
+ if (!contentType) return 'jpg';
272
+ if (contentType.includes('png')) return 'png';
273
+ if (contentType.includes('webp')) return 'webp';
274
+ if (contentType.includes('heic')) return 'heic';
275
+ if (contentType.includes('heif')) return 'heif';
276
+ return 'jpg';
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Hook to create a FileUploadService instance
282
+ *
283
+ * @returns FileUploadService instance with the mutation hook bound
284
+ */
285
+ export function useFileUploadService(): FileUploadService {
286
+ return new FileUploadService();
287
+ }