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,312 @@
1
+ /**
2
+ * Analyze Image Edge Function
3
+ *
4
+ * Handles AI image analysis with JWT authentication.
5
+ * Accepts base64 images and analysis preferences.
6
+ *
7
+ * Requirements: 7.1, 7.2, 7.3, 7.4
8
+ */
9
+
10
+ import 'jsr:@supabase/functions-js/edge-runtime.d.ts';
11
+ import { createClient } from 'npm:@supabase/supabase-js@2';
12
+
13
+ // CORS headers for browser requests
14
+ const corsHeaders = {
15
+ 'Access-Control-Allow-Origin': '*',
16
+ 'Access-Control-Allow-Headers':
17
+ 'authorization, x-client-info, apikey, content-type',
18
+ 'Access-Control-Allow-Methods': 'POST, OPTIONS',
19
+ };
20
+
21
+ interface AnalyzeImageRequest {
22
+ images: Array<{
23
+ data: string; // base64 encoded image
24
+ mimeType?: string;
25
+ }>;
26
+ preferences: {
27
+ goal?: string;
28
+ feedbackStyle?: 'detailed' | 'concise' | 'bullet-points';
29
+ focusAreas?: string[];
30
+ };
31
+ analysisConfigId?: string;
32
+ provider?: 'openai' | 'gemini';
33
+ }
34
+
35
+ interface AnalyzeImageResponse {
36
+ success: boolean;
37
+ analysisId: string;
38
+ status: 'processing' | 'completed' | 'failed';
39
+ results?: any;
40
+ error?: string;
41
+ }
42
+
43
+ Deno.serve(async (req: Request) => {
44
+ // Handle CORS preflight
45
+ if (req.method === 'OPTIONS') {
46
+ return new Response('ok', { headers: corsHeaders });
47
+ }
48
+
49
+ if (req.method !== 'POST') {
50
+ return new Response(JSON.stringify({ error: 'Method not allowed' }), {
51
+ status: 405,
52
+ headers: { ...corsHeaders, 'Content-Type': 'application/json' },
53
+ });
54
+ }
55
+
56
+ try {
57
+ // 7.1: Authenticate the request
58
+ const authHeader = req.headers.get('Authorization');
59
+ if (!authHeader) {
60
+ return new Response(JSON.stringify({ error: 'Missing authorization header' }), {
61
+ status: 401,
62
+ headers: { ...corsHeaders, 'Content-Type': 'application/json' },
63
+ });
64
+ }
65
+
66
+ const token = authHeader.replace('Bearer ', '');
67
+
68
+ // Create Supabase client with user's JWT
69
+ const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
70
+ const supabasePublishableKey = Deno.env.get('SUPABASE_ANON_KEY')!;
71
+ const supabaseSecretKey = Deno.env.get('SUPABASE_SECRET_KEY')!;
72
+
73
+ const supabase = createClient(supabaseUrl, supabasePublishableKey, {
74
+ global: { headers: { Authorization: `Bearer ${token}` } },
75
+ });
76
+
77
+ // Admin client for storage operations
78
+ const supabaseAdmin = createClient(supabaseUrl, supabaseSecretKey);
79
+
80
+ // Verify the user
81
+ const { data: { user }, error: authError } = await supabase.auth.getUser();
82
+ if (authError || !user) {
83
+ return new Response(JSON.stringify({ error: 'Invalid or expired token' }), {
84
+ status: 401,
85
+ headers: { ...corsHeaders, 'Content-Type': 'application/json' },
86
+ });
87
+ }
88
+
89
+ // 7.1: Parse request body - accept base64 images and preferences
90
+ const body: AnalyzeImageRequest = await req.json();
91
+ const { images, preferences, analysisConfigId, provider = 'openai' } = body;
92
+
93
+ if (!images || images.length === 0) {
94
+ return new Response(JSON.stringify({ error: 'At least one image is required' }), {
95
+ status: 400,
96
+ headers: { ...corsHeaders, 'Content-Type': 'application/json' },
97
+ });
98
+ }
99
+
100
+ // Upload images to storage and get storage IDs
101
+ const imageStorageIds: string[] = [];
102
+ for (const image of images) {
103
+ const imageBuffer = Uint8Array.from(atob(image.data), (c) => c.charCodeAt(0));
104
+ const filename = `${user.id}/analysis/${crypto.randomUUID()}.${image.mimeType?.split('/')[1] || 'png'}`;
105
+
106
+ const { data: uploadData, error: uploadError } = await supabaseAdmin.storage
107
+ .from('chat-attachments')
108
+ .upload(filename, imageBuffer, {
109
+ contentType: image.mimeType || 'image/png',
110
+ upsert: false,
111
+ });
112
+
113
+ if (uploadError) {
114
+ console.error('Storage upload error:', uploadError);
115
+ } else {
116
+ imageStorageIds.push(uploadData.path);
117
+ }
118
+ }
119
+
120
+ // 7.2: Create image_analyses record with status "processing"
121
+ const { data: analysisRecord, error: createError } = await supabase
122
+ .from('image_analyses')
123
+ .insert({
124
+ user_id: user.id,
125
+ status: 'processing',
126
+ image_storage_ids: imageStorageIds,
127
+ analysis_config_id: analysisConfigId || null,
128
+ preferences: preferences || {},
129
+ })
130
+ .select('id')
131
+ .single();
132
+
133
+ if (createError) {
134
+ console.error('Error creating analysis record:', createError);
135
+ return new Response(
136
+ JSON.stringify({ error: 'Failed to create analysis record' }),
137
+ {
138
+ status: 500,
139
+ headers: { ...corsHeaders, 'Content-Type': 'application/json' },
140
+ }
141
+ );
142
+ }
143
+
144
+ // Build the analysis prompt based on preferences
145
+ let analysisPrompt = 'Analyze this image';
146
+ if (preferences?.goal) {
147
+ analysisPrompt += ` with the goal of: ${preferences.goal}`;
148
+ }
149
+ if (preferences?.focusAreas && preferences.focusAreas.length > 0) {
150
+ analysisPrompt += `. Focus on: ${preferences.focusAreas.join(', ')}`;
151
+ }
152
+ if (preferences?.feedbackStyle) {
153
+ analysisPrompt += `. Provide ${preferences.feedbackStyle} feedback`;
154
+ }
155
+ analysisPrompt += '.';
156
+
157
+ try {
158
+ let analysisResults: any;
159
+
160
+ if (provider === 'gemini') {
161
+ // Use Gemini for analysis
162
+ const geminiApiKey = Deno.env.get('GEMINI_API_KEY');
163
+ if (!geminiApiKey) {
164
+ throw new Error('Gemini API not configured');
165
+ }
166
+
167
+ const imageParts = images.map((img) => ({
168
+ inlineData: {
169
+ mimeType: img.mimeType || 'image/png',
170
+ data: img.data,
171
+ },
172
+ }));
173
+
174
+ const geminiResponse = await fetch(
175
+ `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${geminiApiKey}`,
176
+ {
177
+ method: 'POST',
178
+ headers: { 'Content-Type': 'application/json' },
179
+ body: JSON.stringify({
180
+ contents: [
181
+ {
182
+ parts: [
183
+ ...imageParts,
184
+ { text: analysisPrompt },
185
+ ],
186
+ },
187
+ ],
188
+ }),
189
+ }
190
+ );
191
+
192
+ if (!geminiResponse.ok) {
193
+ const errorText = await geminiResponse.text();
194
+ throw new Error(`Gemini API error: ${errorText}`);
195
+ }
196
+
197
+ const geminiData = await geminiResponse.json();
198
+ analysisResults = {
199
+ provider: 'gemini',
200
+ model: 'gemini-2.0-flash',
201
+ analysis: geminiData.candidates?.[0]?.content?.parts?.[0]?.text || '',
202
+ raw: geminiData,
203
+ };
204
+ } else {
205
+ // Use OpenAI for analysis
206
+ const openaiApiKey = Deno.env.get('OPENAI_API_KEY');
207
+ if (!openaiApiKey) {
208
+ throw new Error('OpenAI API not configured');
209
+ }
210
+
211
+ const imageContents = images.map((img) => ({
212
+ type: 'image_url',
213
+ image_url: {
214
+ url: `data:${img.mimeType || 'image/png'};base64,${img.data}`,
215
+ },
216
+ }));
217
+
218
+ const openaiResponse = await fetch('https://api.openai.com/v1/chat/completions', {
219
+ method: 'POST',
220
+ headers: {
221
+ 'Content-Type': 'application/json',
222
+ Authorization: `Bearer ${openaiApiKey}`,
223
+ },
224
+ body: JSON.stringify({
225
+ model: 'gpt-4o',
226
+ messages: [
227
+ {
228
+ role: 'user',
229
+ content: [
230
+ { type: 'text', text: analysisPrompt },
231
+ ...imageContents,
232
+ ],
233
+ },
234
+ ],
235
+ max_tokens: 1000,
236
+ }),
237
+ });
238
+
239
+ if (!openaiResponse.ok) {
240
+ const errorData = await openaiResponse.json();
241
+ throw new Error(errorData.error?.message || 'OpenAI API error');
242
+ }
243
+
244
+ const openaiData = await openaiResponse.json();
245
+ analysisResults = {
246
+ provider: 'openai',
247
+ model: 'gpt-4o',
248
+ analysis: openaiData.choices?.[0]?.message?.content || '',
249
+ raw: openaiData,
250
+ };
251
+ }
252
+
253
+ // 7.3: Update record with results and status "completed"
254
+ const { error: updateError } = await supabase
255
+ .from('image_analyses')
256
+ .update({
257
+ status: 'completed',
258
+ results: analysisResults,
259
+ })
260
+ .eq('id', analysisRecord.id);
261
+
262
+ if (updateError) {
263
+ console.error('Error updating analysis record:', updateError);
264
+ }
265
+
266
+ const response: AnalyzeImageResponse = {
267
+ success: true,
268
+ analysisId: analysisRecord.id,
269
+ status: 'completed',
270
+ results: analysisResults,
271
+ };
272
+
273
+ return new Response(JSON.stringify(response), {
274
+ headers: { ...corsHeaders, 'Content-Type': 'application/json' },
275
+ });
276
+ } catch (analysisError) {
277
+ // 7.4: Update record with status "failed" and error message
278
+ const errorMessage = analysisError instanceof Error ? analysisError.message : 'Unknown error';
279
+
280
+ await supabase
281
+ .from('image_analyses')
282
+ .update({
283
+ status: 'failed',
284
+ error_message: errorMessage,
285
+ })
286
+ .eq('id', analysisRecord.id);
287
+
288
+ const response: AnalyzeImageResponse = {
289
+ success: false,
290
+ analysisId: analysisRecord.id,
291
+ status: 'failed',
292
+ error: errorMessage,
293
+ };
294
+
295
+ return new Response(JSON.stringify(response), {
296
+ status: 500,
297
+ headers: { ...corsHeaders, 'Content-Type': 'application/json' },
298
+ });
299
+ }
300
+ } catch (error) {
301
+ console.error('Analyze image error:', error);
302
+ return new Response(
303
+ JSON.stringify({
304
+ error: error instanceof Error ? error.message : 'Internal server error',
305
+ }),
306
+ {
307
+ status: 500,
308
+ headers: { ...corsHeaders, 'Content-Type': 'application/json' },
309
+ }
310
+ );
311
+ }
312
+ });
@@ -0,0 +1,42 @@
1
+ -- Image Analysis Feature Migration
2
+ -- Creates tables for AI image analysis results
3
+ -- Run this migration when adding the image-analysis feature via CLI
4
+
5
+ -- ============================================================================
6
+ -- IMAGE_ANALYSES TABLE
7
+ -- Stores AI image analysis requests and results
8
+ -- ============================================================================
9
+ CREATE TABLE IF NOT EXISTS image_analyses (
10
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
11
+ user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
12
+ status TEXT NOT NULL CHECK (status IN ('processing', 'completed', 'failed')),
13
+ image_storage_ids TEXT[] NOT NULL,
14
+ analysis_config_id TEXT,
15
+ preferences JSONB NOT NULL,
16
+ results JSONB,
17
+ error_message TEXT,
18
+ created_at TIMESTAMPTZ DEFAULT now()
19
+ );
20
+
21
+ -- ============================================================================
22
+ -- INDEXES
23
+ -- ============================================================================
24
+ CREATE INDEX IF NOT EXISTS idx_image_analyses_user_id ON image_analyses(user_id);
25
+ CREATE INDEX IF NOT EXISTS idx_image_analyses_status ON image_analyses(status);
26
+
27
+ -- ============================================================================
28
+ -- RLS POLICIES
29
+ -- ============================================================================
30
+ ALTER TABLE image_analyses ENABLE ROW LEVEL SECURITY;
31
+
32
+ CREATE POLICY "image_analyses_select_own" ON image_analyses
33
+ FOR SELECT USING (auth.uid() = user_id);
34
+
35
+ CREATE POLICY "image_analyses_insert_own" ON image_analyses
36
+ FOR INSERT WITH CHECK (auth.uid() = user_id);
37
+
38
+ CREATE POLICY "image_analyses_update_own" ON image_analyses
39
+ FOR UPDATE USING (auth.uid() = user_id);
40
+
41
+ CREATE POLICY "image_analyses_delete_own" ON image_analyses
42
+ FOR DELETE USING (auth.uid() = user_id);
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "image-analysis",
3
+ "version": "1.0.0",
4
+ "description": "AI-powered image analysis with Supabase backend",
5
+ "copy": [
6
+ {
7
+ "from": "apps/native/src/features/image-analyzer",
8
+ "to": "apps/native/src/features/image-analyzer"
9
+ },
10
+ {
11
+ "from": "packages/backend/supabase/functions/analyze-image",
12
+ "to": "packages/backend/supabase/functions/analyze-image"
13
+ },
14
+ {
15
+ "from": "packages/backend/supabase/migrations/image_analysis.sql",
16
+ "to": "packages/backend/supabase/migrations/image_analysis.sql"
17
+ },
18
+ {
19
+ "from": "packages/backend/src/services/image-analyses.ts",
20
+ "to": "packages/backend/src/services/image-analyses.ts"
21
+ }
22
+ ],
23
+ "nav": {
24
+ "href": "/(root)/(protected)/image-analyzer",
25
+ "label": "Image Analyzer",
26
+ "icon": "🔍",
27
+ "color": "#3B82F6"
28
+ },
29
+ "target": "native",
30
+ "dependencies": {
31
+ "expo": [
32
+ "@supabase/supabase-js",
33
+ "@tanstack/react-query",
34
+ "expo-camera",
35
+ "expo-image-picker"
36
+ ]
37
+ },
38
+ "env": [
39
+ {
40
+ "key": "OPENAI_API_KEY",
41
+ "description": "OpenAI API key for vision analysis",
42
+ "example": "sk-...",
43
+ "file": "packages/backend/supabase/.env",
44
+ "required": true
45
+ }
46
+ ],
47
+ "manualSteps": [
48
+ {
49
+ "title": "Apply Supabase migration",
50
+ "description": "Run: cd packages/backend && supabase db push"
51
+ },
52
+ {
53
+ "title": "Deploy Edge Function",
54
+ "description": "Run: cd packages/backend && supabase functions deploy analyze-image"
55
+ }
56
+ ]
57
+ }
Binary file
@@ -22,11 +22,18 @@ import type { ReportReason } from '@/features/chatbot/constants/report-reasons';
22
22
  import { ImageModelSelector } from '@/features/image-generator/components/image-model-selector';
23
23
  import { ImagePlaceholder } from '@/features/image-generator/components/image-placeholder';
24
24
  import { useImageGenerator } from '@/features/image-generator/hooks/use-image-generator';
25
+ import { useImageGeneratorSettings } from '@/features/image-generator/hooks/use-image-generator-settings';
25
26
  import { ImageSaveService } from '@/features/image-generator/services/image-save-service';
26
27
  import { translate } from '@/lib';
27
28
  import { useThemeConfig } from '@/lib/use-theme-config';
28
29
 
29
30
  export default function ImageGeneratorScreen() {
31
+ const {
32
+ settings,
33
+ isLoaded: isSettingsLoaded,
34
+ updateModel,
35
+ } = useImageGeneratorSettings();
36
+
30
37
  const {
31
38
  prompt,
32
39
  setPrompt,
@@ -34,7 +41,10 @@ export default function ImageGeneratorScreen() {
34
41
  generatedImageData,
35
42
  generatedImageUri,
36
43
  handleGenerateImage,
37
- } = useImageGenerator();
44
+ } = useImageGenerator({
45
+ settings,
46
+ isSettingsLoaded,
47
+ });
38
48
 
39
49
  const [isReportModalVisible, setIsReportModalVisible] = useState(false);
40
50
  const theme = useThemeConfig();
@@ -154,7 +164,11 @@ export default function ImageGeneratorScreen() {
154
164
  <Text className="text-lg font-semibold text-neutral-900 dark:text-neutral-100">
155
165
  Generated Image
156
166
  </Text>
157
- <ImageModelSelector testID="image-model-selector-inline" />
167
+ <ImageModelSelector
168
+ testID="image-model-selector-inline"
169
+ settings={settings}
170
+ onModelChange={updateModel}
171
+ />
158
172
  </View>
159
173
  {generatedImageUri ? (
160
174
  <Image
@@ -7,7 +7,7 @@ import colors from '@/components/ui/colors';
7
7
  import { Modal, useModal } from '@/components/ui/core/overlays/modal';
8
8
  import { GeminiIcon } from '@/components/ui/icons/gemini';
9
9
  import { OpenaiIcon } from '@/components/ui/icons/openai';
10
- import { useImageGeneratorSettings } from '@/features/image-generator/hooks/use-image-generator-settings';
10
+ import type { ImageGeneratorSettings } from '@/features/image-generator/hooks/use-image-generator-settings';
11
11
  import {
12
12
  DEFAULT_IMAGE_MODEL_ID,
13
13
  getImageModelById,
@@ -33,6 +33,8 @@ const getProviderIcon = (provider: ImageProvider): React.ComponentType<any> => {
33
33
 
34
34
  type ModelSelectorProps = {
35
35
  testID?: string;
36
+ settings: ImageGeneratorSettings;
37
+ onModelChange: (modelId: ImageModelId) => Promise<void> | void;
36
38
  };
37
39
 
38
40
  /**
@@ -40,10 +42,11 @@ type ModelSelectorProps = {
40
42
  */
41
43
  export const ImageModelSelector: React.FC<ModelSelectorProps> = ({
42
44
  testID = 'image-model-selector',
45
+ settings,
46
+ onModelChange,
43
47
  }) => {
44
48
  const theme = useThemeConfig();
45
49
  const modal = useModal();
46
- const { settings, updateModel } = useImageGeneratorSettings();
47
50
 
48
51
  const currentModel =
49
52
  getImageModelById(settings.modelId) ??
@@ -55,9 +58,12 @@ export const ImageModelSelector: React.FC<ModelSelectorProps> = ({
55
58
  return <IconComponent />;
56
59
  };
57
60
 
58
- const handleModelSelect = (modelId: ImageModelId) => {
59
- updateModel(modelId);
60
- modal.dismiss();
61
+ const handleModelSelect = async (modelId: ImageModelId) => {
62
+ try {
63
+ await onModelChange(modelId);
64
+ } finally {
65
+ modal.dismiss();
66
+ }
61
67
  };
62
68
 
63
69
  return (
@@ -5,7 +5,7 @@ import { Alert } from 'react-native';
5
5
  import { imageGeneratorApi } from '@/api-client/image-generator';
6
6
 
7
7
  import { getImageModelById } from '../models/models';
8
- import { useImageGeneratorSettings } from './use-image-generator-settings';
8
+ import type { ImageGeneratorSettings } from './use-image-generator-settings';
9
9
 
10
10
  type GeneratedImageData = {
11
11
  imageUri: string;
@@ -20,14 +20,20 @@ type GeneratedImageData = {
20
20
  /**
21
21
  * Custom hook for managing image generation state and operations
22
22
  */
23
- export const useImageGenerator = () => {
23
+ type UseImageGeneratorOptions = {
24
+ settings: ImageGeneratorSettings;
25
+ isSettingsLoaded: boolean;
26
+ };
27
+
28
+ export const useImageGenerator = ({
29
+ settings,
30
+ isSettingsLoaded,
31
+ }: UseImageGeneratorOptions) => {
24
32
  const [prompt, setPrompt] = useState('');
25
33
  const [isLoading, setIsLoading] = useState(false);
26
34
  const [generatedImageData, setGeneratedImageData] =
27
35
  useState<GeneratedImageData | null>(null);
28
36
 
29
- const { settings, isLoaded } = useImageGeneratorSettings();
30
-
31
37
  const generateImage = imageGeneratorApi.useGenerateImage();
32
38
 
33
39
  /**
@@ -39,7 +45,7 @@ export const useImageGenerator = () => {
39
45
  return;
40
46
  }
41
47
 
42
- if (!isLoaded) {
48
+ if (!isSettingsLoaded) {
43
49
  Alert.alert('Please wait', 'Settings are still loading...');
44
50
  return;
45
51
  }
@@ -2,11 +2,11 @@
2
2
  * Image Generation Domain Aggregator
3
3
  *
4
4
  * Single entry point for all image generation Convex functions.
5
- * Re-exports functions from imageGeneratorFunctions.ts to decouple
5
+ * Re-exports functions from imageGenerator.ts to decouple
6
6
  * frontend from internal file structure.
7
7
  */
8
8
 
9
9
  export {
10
10
  generateImageAction,
11
11
  saveImageRecord,
12
- } from '../imageGeneratorFunctions';
12
+ } from '../imageGenerator';
@@ -1,12 +1,8 @@
1
1
  {
2
2
  "name": "image-generator",
3
- "version": "1.1.0",
3
+ "version": "1.0.0",
4
4
  "description": "AI-powered image generation",
5
5
  "copy": [
6
- {
7
- "from": "apps/native/src/app/(root)/(protected)/image-generator",
8
- "to": "apps/native/src/app/(root)/(protected)/image-generator"
9
- },
10
6
  {
11
7
  "from": "apps/native/src/features/image-generator",
12
8
  "to": "apps/native/src/features/image-generator"
@@ -15,49 +11,30 @@
15
11
  "from": "apps/native/src/api-client/image-generator.ts",
16
12
  "to": "apps/native/src/api-client/image-generator.ts"
17
13
  },
18
- {
19
- "from": "packages/backend/convex/imageGeneration/index.ts",
20
- "to": "packages/backend/convex/imageGeneration/index.ts"
21
- },
22
14
  {
23
15
  "from": "packages/backend/convex/imageGenerator.ts",
24
16
  "to": "packages/backend/convex/imageGenerator.ts"
17
+ },
18
+ {
19
+ "from": "packages/backend/convex/imageGeneration",
20
+ "to": "packages/backend/convex/imageGeneration"
25
21
  }
26
22
  ],
23
+ "configuration": {
24
+ "apiClient": {
25
+ "exports": [
26
+ "export { type ImageGeneratorApi, imageGeneratorApi } from './image-generator';"
27
+ ]
28
+ }
29
+ },
27
30
  "nav": {
28
31
  "href": "/(root)/(protected)/image-generator",
29
32
  "label": "Image Generator",
30
33
  "icon": "🎨",
31
- "color": "#A855F7"
34
+ "color": "#8B5CF6"
32
35
  },
33
36
  "target": "native",
34
- "env": [
35
- {
36
- "key": "OPENAI_API_KEY",
37
- "description": "OpenAI key for DALL-E image generation (optional - use this OR Gemini, not both).",
38
- "example": "sk-abc123def456",
39
- "link": "https://platform.openai.com/account/api-keys",
40
- "file": "packages/backend/.env.local"
41
- },
42
- {
43
- "key": "GEMINI_API_KEY",
44
- "description": "Google Generative AI key for Gemini image generation (optional - use this OR OpenAI, not both).",
45
- "example": "AIzaSyExampleGeminiKey",
46
- "link": "https://aistudio.google.com/api-keys",
47
- "file": "packages/backend/.env.local"
48
- }
49
- ],
50
- "manualSteps": [
51
- {
52
- "title": "Get an LLM API key (OpenAI or Gemini)",
53
- "description": "You can start with either provider (OpenAI or Gemini). Add one now; add the other later if you want.",
54
- "link": "https://platform.openai.com/account/api-keys"
55
- },
56
- {
57
- "title": "Add key to .env file",
58
- "description": "Open your .env file and add at least one key:\n\n For OpenAI: OPENAI_API_KEY=sk-...\n For Gemini: GEMINI_API_KEY=AIzaSy...\nYou can add both; the app will use the configured provider.",
59
- "file": ".env",
60
- "content": "OPENAI_API_KEY=sk-...\nGEMINI_API_KEY=AIzaSy...\n"
61
- }
62
- ]
37
+ "dependencies": {
38
+ "expo": ["expo-file-system", "expo-media-library", "expo-sharing"]
39
+ }
63
40
  }
@@ -0,0 +1,26 @@
1
+ import { Stack } from 'expo-router';
2
+
3
+ import { translate } from '@/lib';
4
+
5
+ export default function ImageGeneratorLayout() {
6
+ return (
7
+ <Stack
8
+ screenOptions={{
9
+ headerShown: true,
10
+ }}
11
+ >
12
+ <Stack.Screen
13
+ name="index"
14
+ options={{
15
+ title: translate('image_generator.title'),
16
+ }}
17
+ />
18
+ <Stack.Screen
19
+ name="gallery"
20
+ options={{
21
+ title: `${translate('image_generator.gallery_title')} (0)`,
22
+ }}
23
+ />
24
+ </Stack>
25
+ );
26
+ }