vibefast-cli 1.2.1 → 1.3.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 (348) hide show
  1. package/README.md +30 -95
  2. package/dist/__tests__/recipes.test.js +94 -91
  3. package/dist/__tests__/recipes.test.js.map +1 -1
  4. package/dist/commands/add.d.ts.map +1 -1
  5. package/dist/commands/add.js +301 -125
  6. package/dist/commands/add.js.map +1 -1
  7. package/dist/commands/checklist.d.ts.map +1 -1
  8. package/dist/commands/checklist.js +85 -44
  9. package/dist/commands/checklist.js.map +1 -1
  10. package/dist/commands/health.d.ts.map +1 -1
  11. package/dist/commands/health.js +13 -4
  12. package/dist/commands/health.js.map +1 -1
  13. package/dist/commands/init.d.ts.map +1 -1
  14. package/dist/commands/init.js +118 -26
  15. package/dist/commands/init.js.map +1 -1
  16. package/dist/commands/migrate.d.ts +3 -0
  17. package/dist/commands/migrate.d.ts.map +1 -0
  18. package/dist/commands/migrate.js +202 -0
  19. package/dist/commands/migrate.js.map +1 -0
  20. package/dist/commands/remove.d.ts.map +1 -1
  21. package/dist/commands/remove.js +61 -3
  22. package/dist/commands/remove.js.map +1 -1
  23. package/dist/core/auth.d.ts.map +1 -1
  24. package/dist/core/auth.js +20 -18
  25. package/dist/core/auth.js.map +1 -1
  26. package/dist/core/codemod.d.ts +33 -0
  27. package/dist/core/codemod.d.ts.map +1 -1
  28. package/dist/core/codemod.js +116 -0
  29. package/dist/core/codemod.js.map +1 -1
  30. package/dist/core/detect.d.ts.map +1 -1
  31. package/dist/core/detect.js +24 -7
  32. package/dist/core/detect.js.map +1 -1
  33. package/dist/core/journal.d.ts +1 -0
  34. package/dist/core/journal.d.ts.map +1 -1
  35. package/dist/core/journal.js.map +1 -1
  36. package/dist/core/recipes.d.ts.map +1 -1
  37. package/dist/core/recipes.js +25 -7
  38. package/dist/core/recipes.js.map +1 -1
  39. package/dist/index.js +2 -2
  40. package/dist/index.js.map +1 -1
  41. package/docs/architecture.md +50 -0
  42. package/docs/commands.md +78 -0
  43. package/docs/contributing.md +27 -0
  44. package/docs/quickstart.md +50 -0
  45. package/docs/recipes.md +57 -0
  46. package/docs/troubleshooting.md +31 -0
  47. package/package.json +2 -2
  48. package/recipes/0/apps/native/src/components/advanced-ui/timeline/demo.tsx +445 -0
  49. package/recipes/0/apps/native/src/components/advanced-ui/timeline/timeline-view.tsx +355 -0
  50. package/recipes/0/apps/native/src/components/advanced-ui/timeline/types.ts +31 -0
  51. package/recipes/0/recipe.json +18 -0
  52. package/recipes/animated-chip/apps/native/src/components/advanced-ui/chip/demo.tsx +2 -1
  53. package/recipes/animated-chip/recipe.json +5 -2
  54. package/recipes/animated-chip-native@latest.zip +0 -0
  55. package/recipes/animated-chip@latest.zip +0 -0
  56. package/recipes/animated-switch/apps/native/src/components/advanced-ui/switch/demo.tsx +1 -1
  57. package/recipes/animated-switch/recipe.json +5 -2
  58. package/recipes/animated-switch-native@latest.zip +0 -0
  59. package/recipes/animated-switch@latest.zip +0 -0
  60. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +2 -1
  61. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +2 -2
  62. package/recipes/audio-recorder/recipe.json +7 -2
  63. package/recipes/audio-recorder-native@latest.zip +0 -0
  64. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +2 -1
  65. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +2 -1
  66. package/recipes/audio-recorder-supabase/recipe.json +12 -16
  67. package/recipes/audio-recorder-supabase-native@latest.zip +0 -0
  68. package/recipes/audio-recorder-supabase@latest.zip +0 -0
  69. package/recipes/audio-recorder@latest.zip +0 -0
  70. package/recipes/charts/apps/native/src/app/charts/index.tsx +3 -0
  71. package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +3 -1
  72. package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +3 -1
  73. package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +3 -1
  74. package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +3 -1
  75. package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +3 -1
  76. package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +3 -1
  77. package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +3 -1
  78. package/recipes/charts/recipe.json +13 -4
  79. package/recipes/charts-native@latest.zip +0 -0
  80. package/recipes/charts@latest.zip +0 -0
  81. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +86 -86
  82. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +4 -4
  83. package/recipes/chatbot/recipe.json +3 -40
  84. package/recipes/chatbot-native@latest.zip +0 -0
  85. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-markdown.tsx +4 -1
  86. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/code-block.tsx +86 -53
  87. package/recipes/chatbot-supabase/recipe.json +3 -42
  88. package/recipes/chatbot-supabase-native@latest.zip +0 -0
  89. package/recipes/chatbot-supabase@latest.zip +0 -0
  90. package/recipes/chatbot@latest.zip +0 -0
  91. package/recipes/glowing-button/recipe.json +6 -2
  92. package/recipes/glowing-button-native@latest.zip +0 -0
  93. package/recipes/glowing-button@latest.zip +0 -0
  94. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/_layout.tsx +5 -0
  95. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/analysis-options.tsx +50 -0
  96. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/camera.tsx +2 -0
  97. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/index.tsx +50 -0
  98. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/loading.tsx +50 -0
  99. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/results.tsx +2 -0
  100. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/trait-details.tsx +3 -0
  101. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/analysis-options-screen.tsx +2 -2
  102. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/camera.tsx +72 -65
  103. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/image-capture-screen.tsx +65 -47
  104. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/loading-screen.tsx +43 -2
  105. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/loading.tsx +34 -1
  106. package/recipes/image-analysis/apps/native/src/features/image-analyzer/hooks/use-image-analysis.ts +83 -2
  107. package/recipes/image-analysis/recipe.json +11 -19
  108. package/recipes/image-analysis-native@latest.zip +0 -0
  109. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/_layout.tsx +5 -0
  110. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/analysis-options.tsx +50 -0
  111. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/camera.tsx +2 -0
  112. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/index.tsx +50 -0
  113. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/loading.tsx +50 -0
  114. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/results.tsx +2 -0
  115. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/trait-details.tsx +3 -0
  116. package/recipes/image-analysis-supabase/recipe.json +10 -37
  117. package/recipes/image-analysis-supabase-native@latest.zip +0 -0
  118. package/recipes/image-analysis-supabase@latest.zip +0 -0
  119. package/recipes/image-analysis@latest.zip +0 -0
  120. package/recipes/image-analyzer/apps/native/src/app/(root)/(protected)/image-analyzer/index.tsx +2 -0
  121. package/recipes/image-generator/apps/native/src/app/image-generator/gallery.tsx +3 -0
  122. package/recipes/image-generator/apps/native/src/app/image-generator/index.tsx +3 -0
  123. package/recipes/image-generator/recipe.json +8 -18
  124. package/recipes/image-generator-native@latest.zip +0 -0
  125. package/recipes/image-generator-supabase/recipe.json +6 -35
  126. package/recipes/image-generator-supabase-native@latest.zip +0 -0
  127. package/recipes/image-generator-supabase@latest.zip +0 -0
  128. package/recipes/image-generator@latest.zip +0 -0
  129. package/recipes/ios-widget/recipe.json +18 -119
  130. package/recipes/ios-widget-native@latest.zip +0 -0
  131. package/recipes/ios-widget@latest.zip +0 -0
  132. package/recipes/number-stepper/apps/native/src/components/advanced-ui/stepper/demo.tsx +1 -1
  133. package/recipes/number-stepper/recipe.json +5 -2
  134. package/recipes/number-stepper-native@latest.zip +0 -0
  135. package/recipes/number-stepper@latest.zip +0 -0
  136. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/interactive-onboarding.tsx +11 -18
  137. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/ai-tone-step.tsx +5 -7
  138. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/currency-step.tsx +9 -7
  139. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-ai-step.tsx +8 -7
  140. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-chatbot-step.tsx +6 -5
  141. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-manual-step.tsx +4 -3
  142. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-scan-step.tsx +6 -5
  143. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/main-reason-step.tsx +5 -7
  144. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/notification-step.tsx +7 -6
  145. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/overspend-step.tsx +5 -7
  146. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/personalizing-step.tsx +8 -7
  147. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/rating-step.tsx +6 -5
  148. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/reminder-step.tsx +5 -6
  149. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/safety-step.tsx +5 -4
  150. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/struggle-step.tsx +5 -7
  151. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/welcome-step.tsx +7 -6
  152. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/ui/onboarding-header.tsx +4 -3
  153. package/recipes/onboarding/recipe.json +9 -6
  154. package/recipes/onboarding-native@latest.zip +0 -0
  155. package/recipes/onboarding@latest.zip +0 -0
  156. package/recipes/payments/apps/native/src/app/paywall/index.tsx +74 -0
  157. package/recipes/payments/apps/native/src/app/paywall/local.tsx +25 -0
  158. package/recipes/payments/apps/native/src/app/paywall/remote.tsx +23 -0
  159. package/recipes/payments/packages/backend/convex/payments.ts +21 -3
  160. package/recipes/payments/recipe.json +14 -34
  161. package/recipes/payments-native@latest.zip +0 -0
  162. package/recipes/payments-supabase/apps/native/src/app/paywall/index.tsx +74 -0
  163. package/recipes/payments-supabase/apps/native/src/app/paywall/local.tsx +25 -0
  164. package/recipes/payments-supabase/apps/native/src/app/paywall/remote.tsx +23 -0
  165. package/recipes/payments-supabase/recipe.json +16 -23
  166. package/recipes/payments-supabase-native@latest.zip +0 -0
  167. package/recipes/payments-supabase@latest.zip +0 -0
  168. package/recipes/payments@latest.zip +0 -0
  169. package/recipes/posthog/apps/native/src/components/analytics/navigation-tracker.tsx +14 -0
  170. package/recipes/posthog/apps/native/src/lib/hooks/use-navigation-analytics.ts +44 -0
  171. package/recipes/posthog/apps/native/src/providers/posthog-provider.tsx +51 -0
  172. package/recipes/posthog/recipe.json +60 -0
  173. package/recipes/posthog-native@latest.zip +0 -0
  174. package/recipes/progress-circle/apps/native/src/components/advanced-ui/progress-bars/progress-circle-page.tsx +1 -1
  175. package/recipes/progress-circle/recipe.json +5 -2
  176. package/recipes/progress-circle-native@latest.zip +0 -0
  177. package/recipes/progress-circle@latest.zip +0 -0
  178. package/recipes/quiz/apps/native/src/app/quiz/index.tsx +47 -0
  179. package/recipes/quiz/recipe.json +9 -6
  180. package/recipes/quiz-native@latest.zip +0 -0
  181. package/recipes/quiz@latest.zip +0 -0
  182. package/recipes/screen-kits/apps/native/src/app/screen-kits/_layout.tsx +12 -0
  183. package/recipes/screen-kits/apps/native/src/app/screen-kits/index.tsx +114 -0
  184. package/recipes/screen-kits/apps/native/src/features/screen-kits/index.ts +1 -0
  185. package/recipes/screen-kits/apps/native/src/features/screen-kits/types.ts +28 -0
  186. package/recipes/screen-kits/recipe.json +26 -0
  187. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/_layout.tsx +12 -0
  188. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/home.tsx +5 -0
  189. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/index.tsx +5 -0
  190. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/lesson-complete.tsx +5 -0
  191. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/lesson-fail.tsx +5 -0
  192. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/lesson.tsx +5 -0
  193. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/skill-tree.tsx +5 -0
  194. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/components/duo-button.tsx +174 -0
  195. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/components/skill-button.tsx +186 -0
  196. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/components/xp-header.tsx +115 -0
  197. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/constants.ts +89 -0
  198. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/index.ts +3 -0
  199. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/home-screen.tsx +225 -0
  200. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/lesson-complete-screen.tsx +485 -0
  201. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/lesson-fail-screen.tsx +105 -0
  202. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/lesson-screen.tsx +384 -0
  203. package/recipes/screen-kits-duolingo/recipe.json +58 -0
  204. package/recipes/screen-kits-duolingo-native@latest.zip +0 -0
  205. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/_layout.tsx +45 -0
  206. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/asset-detail.tsx +3 -0
  207. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/notifications.tsx +3 -0
  208. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/receive.tsx +3 -0
  209. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/send.tsx +3 -0
  210. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/swap.tsx +3 -0
  211. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/wallet.tsx +3 -0
  212. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/components/ActionButtons.tsx +78 -0
  213. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/components/AssetRow.tsx +94 -0
  214. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/components/BalanceCard.tsx +118 -0
  215. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/constants.ts +85 -0
  216. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/asset-detail.tsx +378 -0
  217. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/notifications.tsx +210 -0
  218. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/receive-modal.tsx +317 -0
  219. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/send-modal.tsx +420 -0
  220. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/swap-modal.tsx +363 -0
  221. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/wallet-dashboard.tsx +281 -0
  222. package/recipes/screen-kits-finance/recipe.json +46 -0
  223. package/recipes/screen-kits-finance-native@latest.zip +0 -0
  224. package/recipes/screen-kits-fitness/apps/native/assets/sounds/timer-beep.wav +0 -0
  225. package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/_layout.tsx +10 -0
  226. package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/index.tsx +6 -0
  227. package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/timer.tsx +3 -0
  228. package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/workout.tsx +3 -0
  229. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/components/timer-components.tsx +500 -0
  230. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/components/timer-settings-modal.tsx +352 -0
  231. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/components/workout-card.tsx +105 -0
  232. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/constants.ts +189 -0
  233. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/hooks/use-timer.ts +307 -0
  234. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/index.ts +1 -0
  235. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/screens/timer-screen.tsx +278 -0
  236. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/screens/workout-dashboard.tsx +350 -0
  237. package/recipes/screen-kits-fitness/recipe.json +63 -0
  238. package/recipes/screen-kits-fitness-native@latest.zip +0 -0
  239. package/recipes/screen-kits-habits/apps/native/src/app/screen-kits/productivity/habits.tsx +1 -0
  240. package/recipes/screen-kits-habits/apps/native/src/app/screen-kits/productivity/kanban.tsx +1 -0
  241. package/recipes/screen-kits-habits/apps/native/src/app/screen-kits/productivity/routes.ts +4 -0
  242. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/AddTaskModal.tsx +246 -0
  243. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/DraggableTaskCard.tsx +92 -0
  244. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/KanbanColumn.tsx +238 -0
  245. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/TaskCard.tsx +144 -0
  246. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/add-habit-modal.tsx +271 -0
  247. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/constants.ts +295 -0
  248. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/kanban-utils.ts +62 -0
  249. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/screens/habit-tracker.tsx +1160 -0
  250. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/screens/kanban-board.tsx +432 -0
  251. package/recipes/screen-kits-habits/recipe.json +52 -0
  252. package/recipes/screen-kits-habits-native@latest.zip +0 -0
  253. package/recipes/screen-kits-native@latest.zip +0 -0
  254. package/recipes/sentry/apps/native/src/providers/sentry-provider.tsx +64 -0
  255. package/recipes/sentry/recipe.json +39 -0
  256. package/recipes/sentry-native@latest.zip +0 -0
  257. package/recipes/swipe-slider/apps/native/src/components/advanced-ui/sliders/swipe-slider-page.tsx +1 -1
  258. package/recipes/swipe-slider/recipe.json +5 -2
  259. package/recipes/swipe-slider-native@latest.zip +0 -0
  260. package/recipes/swipe-slider@latest.zip +0 -0
  261. package/recipes/timeline/apps/native/src/components/advanced-ui/timeline/demo.tsx +2 -1
  262. package/recipes/timeline/recipe.json +5 -2
  263. package/recipes/timeline-native@latest.zip +0 -0
  264. package/recipes/timeline@latest.zip +0 -0
  265. package/recipes/tracker-app/apps/native/src/app/tracker-app/index.tsx +1 -0
  266. package/recipes/tracker-app/recipe.json +10 -7
  267. package/recipes/tracker-app-native@latest.zip +0 -0
  268. package/recipes/tracker-app@latest.zip +0 -0
  269. package/recipes/upload-all.sh +8 -31
  270. package/recipes/voice-bot/apps/native/src/app/voice-bot/index.tsx +56 -0
  271. package/recipes/voice-bot/recipe.json +31 -7
  272. package/recipes/voice-bot-native@latest.zip +0 -0
  273. package/recipes/voice-bot@latest.zip +0 -0
  274. package/recipes/wake-word/apps/native/src/app/{(root)/(protected)/test-wake-word.tsx → test-wake-word.tsx} +43 -4
  275. package/recipes/wake-word/recipe.json +16 -26
  276. package/recipes/wake-word-native@latest.zip +0 -0
  277. package/recipes/wake-word@latest.zip +0 -0
  278. package/scripts/create-advanced-ui-recipes.sh +46 -19
  279. package/scripts/create-recipes.mjs +471 -117
  280. package/scripts/package-recipes.mjs +76 -0
  281. package/scripts/publish-all.sh +6 -2
  282. package/CHANGELOG.md +0 -198
  283. package/docs/archive/AUTO-DETECT-DEPS.md +0 -607
  284. package/docs/archive/FINAL-PACKAGE-STRATEGY.md +0 -583
  285. package/docs/archive/FINAL-SIMPLE-PLAN.md +0 -487
  286. package/docs/archive/FINAL-STATUS.md +0 -144
  287. package/docs/archive/FLOW-DIAGRAM.md +0 -1629
  288. package/docs/archive/GOTCHAS-AND-RISKS.md +0 -801
  289. package/docs/archive/IMPLEMENTATION-PLAN.md +0 -1360
  290. package/docs/archive/PLAN.md +0 -453
  291. package/docs/archive/PRODUCTION-READINESS.md +0 -684
  292. package/docs/archive/PRODUCTION-TEST-RESULTS.md +0 -465
  293. package/docs/archive/SIMPLIFIED-PLAN.md +0 -578
  294. package/docs/archive/STATUS.md +0 -199
  295. package/docs/archive/SUCCESS.md +0 -259
  296. package/docs/archive/TEST-SUMMARY.md +0 -261
  297. package/docs/archive/TESTING-CHECKLIST.md +0 -450
  298. package/docs/archive/USER-MODIFICATIONS.md +0 -448
  299. package/docs/decisions.md +0 -55
  300. package/docs/manual-testing.md +0 -91
  301. package/docs/next-steps.md +0 -12
  302. package/recipes/README.md +0 -156
  303. package/recipes/audio-recorder-supabase/packages/backend/src/services/recordings.ts +0 -369
  304. package/recipes/chatbot/apps/native/src/api-client/chatbot.ts +0 -83
  305. package/recipes/chatbot/packages/backend/convex/agents.ts +0 -115
  306. package/recipes/chatbot/packages/backend/convex/tools/index.ts +0 -18
  307. package/recipes/chatbot/packages/backend/convex/tools/knowledgeRetrieval.ts +0 -97
  308. package/recipes/chatbot/packages/backend/convex/tools/tavilySearch.ts +0 -83
  309. package/recipes/chatbot/packages/backend/convex/tools/userProfile.ts +0 -72
  310. package/recipes/chatbot-supabase/apps/native/src/api-client/supabase/chatbot.ts +0 -515
  311. package/recipes/chatbot-supabase/packages/backend/src/services/conversations.ts +0 -243
  312. package/recipes/chatbot-supabase/packages/backend/src/services/messages.ts +0 -327
  313. package/recipes/image-analysis/apps/native/src/api-client/image-analyzer.ts +0 -62
  314. package/recipes/image-analysis-supabase/packages/backend/src/services/image-analyses.ts +0 -132
  315. package/recipes/image-generator/apps/native/src/api-client/image-generator.ts +0 -34
  316. package/recipes/payments/apps/native/src/api-client/payments.ts +0 -44
  317. package/recipes/payments-supabase/packages/backend/src/services/payments.ts +0 -201
  318. package/recipes/posthog.json +0 -47
  319. package/recipes/revenuecat.json +0 -43
  320. package/recipes/sentry.json +0 -47
  321. package/recipes/wake-word/apps/native/assets/vosk-model/README.md +0 -103
  322. package/recipes/wake-word/apps/native/scripts/download-vosk-model.mjs +0 -127
  323. /package/recipes/{audio-recorder/apps/native/src/app/(root)/(protected) → audio-recorder-supabase/apps/native/src/app}/audio-recorder/index.tsx +0 -0
  324. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/AppIntent.swift +0 -0
  325. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@1x.png +0 -0
  326. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@2x.png +0 -0
  327. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@3x.png +0 -0
  328. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@1x.png +0 -0
  329. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@2x.png +0 -0
  330. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@3x.png +0 -0
  331. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@1x.png +0 -0
  332. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@2x.png +0 -0
  333. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@3x.png +0 -0
  334. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@2x.png +0 -0
  335. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@3x.png +0 -0
  336. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@1x.png +0 -0
  337. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@2x.png +0 -0
  338. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-83.5x83.5@2x.png +0 -0
  339. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
  340. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png +0 -0
  341. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/CalorieTrackerWidget.swift +0 -0
  342. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/HabitTrackerWidget.swift +0 -0
  343. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Info.plist +0 -0
  344. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/WidgetLiveActivity.swift +0 -0
  345. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/expo-target.config.js +0 -0
  346. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/generated.entitlements +0 -0
  347. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/index.swift +0 -0
  348. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/widgets.swift +0 -0
@@ -1,243 +0,0 @@
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
- };
@@ -1,327 +0,0 @@
1
- /**
2
- * Messages Service
3
- *
4
- * Handles message operations including storeMessage, listMessages,
5
- * deleteUserMessage, and clearConversationMessages.
6
- *
7
- * Requirements: 4.3, 4.4, 4.5, 4.6, 4.7
8
- */
9
-
10
- import type { SupabaseClientType } from '../lib/supabase';
11
- import type { Message } from '../types';
12
- import type { Json } from '../types/database';
13
-
14
- export interface StoreMessageInput {
15
- conversationId: string;
16
- authorType: 'user' | 'bot';
17
- text?: string | null;
18
- attachments?: Json | null;
19
- aiProvider?: string | null;
20
- aiModel?: string | null;
21
- toolCalls?: Json | null;
22
- metadata?: Json | null;
23
- }
24
-
25
- export interface StoreMessageResult {
26
- success: boolean;
27
- message?: Message;
28
- error?: string;
29
- }
30
-
31
- export interface ListMessagesResult {
32
- success: boolean;
33
- messages?: Message[];
34
- hasMore?: boolean;
35
- error?: string;
36
- }
37
-
38
- export interface DeleteMessageResult {
39
- success: boolean;
40
- error?: string;
41
- }
42
-
43
- export interface ClearMessagesResult {
44
- success: boolean;
45
- deletedCount?: number;
46
- error?: string;
47
- }
48
-
49
- const DEFAULT_PAGE_SIZE = 50;
50
- const BATCH_DELETE_SIZE = 100;
51
-
52
- /**
53
- * Store a new message in a conversation
54
- *
55
- * Validates that the message has either text or attachments (not both empty).
56
- *
57
- * @param supabase - Supabase client (authenticated)
58
- * @param input - Message data to store
59
- * @returns The created message
60
- *
61
- * Requirements: 4.3, 4.4
62
- */
63
- export async function storeMessage(
64
- supabase: SupabaseClientType,
65
- input: StoreMessageInput
66
- ): Promise<StoreMessageResult> {
67
- // Get the current auth user
68
- const { data: authData, error: authError } = await supabase.auth.getUser();
69
-
70
- if (authError || !authData.user) {
71
- return { success: false, error: 'Not authenticated' };
72
- }
73
-
74
- const userId = authData.user.id;
75
-
76
- // Validate input
77
- if (!input.conversationId) {
78
- return { success: false, error: 'Conversation ID is required' };
79
- }
80
-
81
- // Check if text is empty/whitespace and no attachments
82
- const hasText = input.text && input.text.trim().length > 0;
83
- const hasAttachments = input.attachments &&
84
- (Array.isArray(input.attachments) ? input.attachments.length > 0 : true);
85
-
86
- if (!hasText && !hasAttachments) {
87
- return { success: false, error: 'Message must have text or attachments' };
88
- }
89
-
90
- // Verify user owns the conversation
91
- const { data: conversation, error: convError } = await supabase
92
- .from('conversations')
93
- .select('id')
94
- .eq('id', input.conversationId)
95
- .eq('user_id', userId)
96
- .single();
97
-
98
- if (convError || !conversation) {
99
- return { success: false, error: 'Conversation not found or access denied' };
100
- }
101
-
102
- // Create the message
103
- const { data: message, error: createError } = await supabase
104
- .from('messages')
105
- .insert({
106
- conversation_id: input.conversationId,
107
- user_id: userId,
108
- author_type: input.authorType,
109
- text: input.text || null,
110
- attachments: input.attachments || null,
111
- ai_provider: input.aiProvider || null,
112
- ai_model: input.aiModel || null,
113
- tool_calls: input.toolCalls || null,
114
- metadata: input.metadata || null,
115
- })
116
- .select()
117
- .single();
118
-
119
- if (createError) {
120
- return { success: false, error: `Failed to store message: ${createError.message}` };
121
- }
122
-
123
- return { success: true, message };
124
- }
125
-
126
-
127
- /**
128
- * List messages for a conversation with pagination
129
- *
130
- * Returns messages ordered by creation time (oldest first for chat display).
131
- *
132
- * @param supabase - Supabase client (authenticated)
133
- * @param conversationId - The conversation to list messages from
134
- * @param options - Pagination options
135
- * @returns Paginated list of messages
136
- *
137
- * Requirements: 4.5
138
- */
139
- export async function listMessages(
140
- supabase: SupabaseClientType,
141
- conversationId: string,
142
- options?: {
143
- limit?: number;
144
- cursor?: string; // created_at timestamp for cursor-based pagination
145
- }
146
- ): Promise<ListMessagesResult> {
147
- // Get the current auth user
148
- const { data: authData, error: authError } = await supabase.auth.getUser();
149
-
150
- if (authError || !authData.user) {
151
- return { success: false, error: 'Not authenticated' };
152
- }
153
-
154
- if (!conversationId) {
155
- return { success: false, error: 'Conversation ID is required' };
156
- }
157
-
158
- const limit = options?.limit || DEFAULT_PAGE_SIZE;
159
-
160
- // Build query
161
- let query = supabase
162
- .from('messages')
163
- .select('*')
164
- .eq('conversation_id', conversationId)
165
- .order('created_at', { ascending: true })
166
- .limit(limit + 1); // Fetch one extra to check if there are more
167
-
168
- // Apply cursor if provided
169
- if (options?.cursor) {
170
- query = query.gt('created_at', options.cursor);
171
- }
172
-
173
- const { data: messages, error: listError } = await query;
174
-
175
- if (listError) {
176
- return { success: false, error: `Failed to list messages: ${listError.message}` };
177
- }
178
-
179
- // Check if there are more results
180
- const hasMore = messages && messages.length > limit;
181
- const resultMessages = hasMore ? messages.slice(0, limit) : (messages || []);
182
-
183
- return {
184
- success: true,
185
- messages: resultMessages,
186
- hasMore,
187
- };
188
- }
189
-
190
- /**
191
- * Delete a single user message
192
- *
193
- * Only allows deletion if the user owns the message.
194
- *
195
- * @param supabase - Supabase client (authenticated)
196
- * @param messageId - The ID of the message to delete
197
- * @returns Success or error
198
- *
199
- * Requirements: 4.7
200
- */
201
- export async function deleteUserMessage(
202
- supabase: SupabaseClientType,
203
- messageId: string
204
- ): Promise<DeleteMessageResult> {
205
- // Get the current auth user
206
- const { data: authData, error: authError } = await supabase.auth.getUser();
207
-
208
- if (authError || !authData.user) {
209
- return { success: false, error: 'Not authenticated' };
210
- }
211
-
212
- if (!messageId) {
213
- return { success: false, error: 'Message ID is required' };
214
- }
215
-
216
- // Delete the message (RLS + user_id check ensures ownership)
217
- const { data, error: deleteError } = await supabase
218
- .from('messages')
219
- .delete()
220
- .eq('id', messageId)
221
- .eq('user_id', authData.user.id)
222
- .select('id')
223
- .single();
224
-
225
- if (deleteError) {
226
- if (deleteError.code === 'PGRST116') {
227
- return { success: false, error: 'Message not found or access denied' };
228
- }
229
- return { success: false, error: `Failed to delete message: ${deleteError.message}` };
230
- }
231
-
232
- if (!data) {
233
- return { success: false, error: 'Message not found or access denied' };
234
- }
235
-
236
- return { success: true };
237
- }
238
-
239
- /**
240
- * Clear all messages in a conversation
241
- *
242
- * Deletes messages in batches to handle large conversations.
243
- * The conversation itself is preserved.
244
- *
245
- * @param supabase - Supabase client (authenticated)
246
- * @param conversationId - The conversation to clear
247
- * @returns Success with count of deleted messages
248
- *
249
- * Requirements: 4.6
250
- */
251
- export async function clearConversationMessages(
252
- supabase: SupabaseClientType,
253
- conversationId: string
254
- ): Promise<ClearMessagesResult> {
255
- // Get the current auth user
256
- const { data: authData, error: authError } = await supabase.auth.getUser();
257
-
258
- if (authError || !authData.user) {
259
- return { success: false, error: 'Not authenticated' };
260
- }
261
-
262
- if (!conversationId) {
263
- return { success: false, error: 'Conversation ID is required' };
264
- }
265
-
266
- const userId = authData.user.id;
267
-
268
- // Verify user owns the conversation
269
- const { data: conversation, error: convError } = await supabase
270
- .from('conversations')
271
- .select('id')
272
- .eq('id', conversationId)
273
- .eq('user_id', userId)
274
- .single();
275
-
276
- if (convError || !conversation) {
277
- return { success: false, error: 'Conversation not found or access denied' };
278
- }
279
-
280
- let totalDeleted = 0;
281
- let hasMore = true;
282
-
283
- // Delete in batches
284
- while (hasMore) {
285
- // Get batch of message IDs
286
- const { data: messagesToDelete, error: fetchError } = await supabase
287
- .from('messages')
288
- .select('id')
289
- .eq('conversation_id', conversationId)
290
- .limit(BATCH_DELETE_SIZE);
291
-
292
- if (fetchError) {
293
- return { success: false, error: `Failed to fetch messages: ${fetchError.message}` };
294
- }
295
-
296
- if (!messagesToDelete || messagesToDelete.length === 0) {
297
- hasMore = false;
298
- break;
299
- }
300
-
301
- const idsToDelete = messagesToDelete.map((m) => m.id);
302
-
303
- // Delete the batch
304
- const { error: deleteError } = await supabase
305
- .from('messages')
306
- .delete()
307
- .in('id', idsToDelete);
308
-
309
- if (deleteError) {
310
- return { success: false, error: `Failed to delete messages: ${deleteError.message}` };
311
- }
312
-
313
- totalDeleted += idsToDelete.length;
314
-
315
- // Check if we got a full batch (might be more)
316
- hasMore = messagesToDelete.length === BATCH_DELETE_SIZE;
317
- }
318
-
319
- return { success: true, deletedCount: totalDeleted };
320
- }
321
-
322
- export const messagesService = {
323
- storeMessage,
324
- listMessages,
325
- deleteUserMessage,
326
- clearConversationMessages,
327
- };
@@ -1,62 +0,0 @@
1
- import { api } from '@vibefast/backend/_generated/api';
2
- import type { Id } from '@vibefast/backend/_generated/dataModel';
3
- import { useAction, useQuery } from 'convex/react';
4
-
5
- const skipToken = 'skip' as const;
6
-
7
- /**
8
- * Image Analyzer API Gateway
9
- *
10
- * This gateway provides typed wrappers around Convex image analysis functions.
11
- * It handles AI-powered image analysis with configurable goals and feedback styles.
12
- *
13
- * Usage:
14
- * - Import this gateway in feature code: `import { imageAnalyzerApi } from '@/platform/api/image-analyzer'`
15
- * - Never import from `@vibefast/backend/_generated/api` directly in feature code
16
- */
17
- export const imageAnalyzerApi = {
18
- /**
19
- * Start image analysis action
20
- *
21
- * @returns Promise with analysis ID
22
- */
23
- useAnalyzeImages() {
24
- return useAction(api['imageAnalysis/index'].analyzeImages);
25
- },
26
-
27
- /**
28
- * Get analysis by ID
29
- */
30
- useGetAnalysisById(analysisId?: Id<'imageAnalyses'> | null) {
31
- return useQuery(
32
- api['imageAnalysis/index'].getAnalysisById,
33
- analysisId ? { analysisId } : skipToken,
34
- );
35
- },
36
-
37
- /**
38
- * Get full analysis with image URLs
39
- */
40
- useGetImageAnalysis(analysisId?: Id<'imageAnalyses'> | null) {
41
- return useQuery(
42
- api['imageAnalysis/index'].getImageAnalysis,
43
- analysisId ? { analysisId } : skipToken,
44
- );
45
- },
46
-
47
- /**
48
- * Get user's analysis history with pagination
49
- */
50
- useGetUserImageAnalyses(
51
- paginationOpts: { numItems: number; cursor: string | null } = {
52
- numItems: 50,
53
- cursor: null,
54
- },
55
- ) {
56
- return useQuery(api['imageAnalysis/index'].getUserImageAnalyses, {
57
- paginationOpts,
58
- });
59
- },
60
- };
61
-
62
- export type ImageAnalyzerApi = typeof imageAnalyzerApi;