kasy-cli 1.21.8 → 1.22.0

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 (269) hide show
  1. package/lib/commands/add.js +93 -80
  2. package/lib/commands/configure.js +100 -32
  3. package/lib/commands/doctor.js +28 -2
  4. package/lib/commands/new.js +86 -38
  5. package/lib/commands/notifications.js +1 -1
  6. package/lib/commands/remove.js +43 -15
  7. package/lib/commands/run.js +2 -2
  8. package/lib/commands/update.js +2 -2
  9. package/lib/scaffold/CHANGELOG.json +14 -0
  10. package/lib/scaffold/backends/api/generator.js +14 -14
  11. package/lib/scaffold/backends/api/patch/README.md +83 -0
  12. package/lib/scaffold/backends/api/patch/lib/core/data/api/storage_api.dart +1 -1
  13. package/lib/scaffold/backends/api/patch/lib/core/data/entities/user_entity.dart +5 -0
  14. package/lib/scaffold/backends/api/patch/lib/{environnements.dart → environments.dart} +3 -11
  15. package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_api.dart +108 -0
  16. package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +51 -0
  17. package/lib/scaffold/backends/api/patch/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +5 -5
  18. package/lib/scaffold/backends/api/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +71 -38
  19. package/lib/scaffold/backends/api/patch/lib/features/authentication/api/authentication_api.dart +2 -2
  20. package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_request_api.dart +54 -0
  21. package/lib/scaffold/backends/api/patch/lib/features/onboarding/models/user_info.dart +16 -16
  22. package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  23. package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  24. package/lib/scaffold/backends/api/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +100 -0
  25. package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
  26. package/lib/scaffold/backends/api/patch/lib/features/subscriptions/api/stripe_backend_api.dart +60 -0
  27. package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  28. package/lib/scaffold/backends/api/pubspec.yaml.tpl +4 -5
  29. package/lib/scaffold/backends/firebase/deploy.js +87 -13
  30. package/lib/scaffold/backends/firebase/enable-auth-via-cli.js +14 -6
  31. package/lib/scaffold/backends/firebase/generator.js +5 -5
  32. package/lib/scaffold/backends/firebase/setup-from-scratch.js +69 -45
  33. package/lib/scaffold/backends/firebase/tokens.js +4 -4
  34. package/lib/scaffold/backends/supabase/deploy.js +63 -11
  35. package/lib/scaffold/backends/supabase/edge-functions/admin-list-users/index.ts +149 -0
  36. package/lib/scaffold/backends/supabase/edge-functions/{llm-chat → ai-chat}/index.ts +19 -19
  37. package/lib/scaffold/backends/supabase/edge-functions/revenuecat-webhook/index.ts +2 -0
  38. package/lib/scaffold/backends/supabase/edge-functions/stripe-create-checkout-session/index.ts +123 -0
  39. package/lib/scaffold/backends/supabase/edge-functions/stripe-create-portal-session/index.ts +97 -0
  40. package/lib/scaffold/backends/supabase/edge-functions/stripe-list-prices/index.ts +83 -0
  41. package/lib/scaffold/backends/supabase/edge-functions/stripe-webhook/index.ts +138 -0
  42. package/lib/scaffold/backends/supabase/generator.js +17 -17
  43. package/lib/scaffold/backends/supabase/migrations/20240101000009_ai_messages.sql +50 -0
  44. package/lib/scaffold/backends/supabase/migrations/20240101000012_stripe_customers.sql +36 -0
  45. package/lib/scaffold/backends/supabase/migrations/20240101000013_admin_role.sql +62 -0
  46. package/lib/scaffold/backends/supabase/patch/lib/core/data/entities/user_entity.dart +4 -0
  47. package/lib/scaffold/backends/supabase/patch/lib/{environnements.dart → environments.dart} +3 -13
  48. package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_api.dart +95 -0
  49. package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +52 -0
  50. package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +6 -6
  51. package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +63 -35
  52. package/lib/scaffold/backends/supabase/patch/lib/features/authentication/api/authentication_api.dart +1 -1
  53. package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/api/feature_request_api.dart +46 -0
  54. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/models/user_info.dart +16 -16
  55. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  56. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  57. package/lib/scaffold/backends/supabase/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +93 -0
  58. package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
  59. package/lib/scaffold/backends/supabase/patch/lib/features/subscriptions/api/stripe_backend_api.dart +52 -0
  60. package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  61. package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +4 -5
  62. package/lib/scaffold/backends/supabase/tokens.js +3 -3
  63. package/lib/scaffold/catalog.js +9 -11
  64. package/lib/scaffold/generate.js +45 -31
  65. package/lib/scaffold/shared/generator-utils.js +188 -81
  66. package/lib/scaffold/shared/sort-imports.js +191 -0
  67. package/lib/scaffold/shared/template-strings.js +3 -3
  68. package/lib/utils/checks.js +2 -2
  69. package/lib/utils/i18n/messages-en.js +50 -35
  70. package/lib/utils/i18n/messages-es.js +50 -35
  71. package/lib/utils/i18n/messages-pt.js +52 -37
  72. package/lib/utils/updates.js +15 -15
  73. package/package.json +1 -1
  74. package/templates/firebase/.env.example +2 -2
  75. package/templates/firebase/android/app/src/main/res/drawable/background.png +0 -0
  76. package/templates/firebase/android/app/src/main/res/drawable-night/background.png +0 -0
  77. package/templates/firebase/android/app/src/main/res/drawable-night-v21/background.png +0 -0
  78. package/templates/firebase/android/app/src/main/res/drawable-v21/background.png +0 -0
  79. package/templates/firebase/android/app/src/main/res/values-night-v31/styles.xml +1 -1
  80. package/templates/firebase/android/app/src/main/res/values-v31/styles.xml +1 -1
  81. package/templates/firebase/assets/images/logo_wordmark_dark.png +0 -0
  82. package/templates/firebase/assets/images/logo_wordmark_light.png +0 -0
  83. package/templates/firebase/docs/revenuecat-setup.es.md +1 -1
  84. package/templates/firebase/docs/revenuecat-setup.pt.md +1 -1
  85. package/templates/firebase/firestore.rules +24 -5
  86. package/templates/firebase/functions/package-lock.json +22 -1
  87. package/templates/firebase/functions/package.json +2 -1
  88. package/templates/firebase/functions/src/admin/functions.ts +113 -0
  89. package/templates/firebase/functions/src/{llm_chat → ai_chat}/index.ts +16 -16
  90. package/templates/firebase/functions/src/index.ts +8 -2
  91. package/templates/firebase/functions/src/notifications/device_triggers.ts +2 -2
  92. package/templates/firebase/functions/src/notifications/triggers.ts +3 -3
  93. package/templates/firebase/functions/src/subscriptions/models/subscription_status.ts +2 -0
  94. package/templates/firebase/functions/src/subscriptions/stripe_functions.ts +222 -0
  95. package/templates/firebase/functions/src/subscriptions/subscriptions_functions.ts +2 -2
  96. package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png +0 -0
  97. package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png +0 -0
  98. package/templates/firebase/lib/components/components.dart +4 -1
  99. package/templates/firebase/lib/components/kasy_app_bar.dart +22 -7
  100. package/templates/firebase/lib/components/kasy_avatar.dart +7 -6
  101. package/templates/firebase/lib/components/kasy_button.dart +23 -99
  102. package/templates/firebase/lib/components/kasy_dialog.dart +11 -11
  103. package/templates/firebase/lib/components/kasy_image_viewer.dart +84 -0
  104. package/templates/firebase/lib/components/{kasy_sidebar_pro.dart → kasy_sidebar.dart} +692 -425
  105. package/templates/firebase/lib/components/kasy_status_tag.dart +91 -0
  106. package/templates/firebase/lib/components/kasy_text_area.dart +1 -3
  107. package/templates/firebase/lib/components/kasy_text_field.dart +5 -6
  108. package/templates/firebase/lib/components/kasy_text_field_otp.dart +1 -3
  109. package/templates/firebase/lib/components/kasy_toast.dart +2 -2
  110. package/templates/firebase/lib/components/kasy_web_header.dart +209 -0
  111. package/templates/firebase/lib/core/ads/ads_provider.dart +1 -1
  112. package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +57 -4
  113. package/templates/firebase/lib/core/bottom_menu/bottom_router.dart +19 -91
  114. package/templates/firebase/lib/core/bottom_menu/kasy_bottom_bar_factory.dart +196 -96
  115. package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +41 -0
  116. package/templates/firebase/lib/core/config/app_env.dart +5 -11
  117. package/templates/firebase/lib/core/config/features.dart +5 -4
  118. package/templates/firebase/lib/core/data/api/analytics_api.dart +1 -1
  119. package/templates/firebase/lib/core/data/api/http_client.dart +1 -1
  120. package/templates/firebase/lib/core/data/entities/user_entity.dart +3 -0
  121. package/templates/firebase/lib/core/data/models/entitlement.dart +35 -0
  122. package/templates/firebase/lib/core/data/models/subscription.dart +13 -186
  123. package/templates/firebase/lib/core/data/models/user.dart +11 -0
  124. package/templates/firebase/lib/core/data/repositories/user_repository.dart +1 -1
  125. package/templates/firebase/lib/core/home_widgets/home_widget_background_task.dart +1 -1
  126. package/templates/firebase/lib/core/home_widgets/home_widget_mywidget_service.dart +1 -1
  127. package/templates/firebase/lib/core/icons/kasy_icons.dart +31 -1
  128. package/templates/firebase/lib/core/rating/api/rating_api.dart +2 -2
  129. package/templates/firebase/lib/core/states/logout_action.dart +25 -0
  130. package/templates/firebase/lib/core/states/user_state_notifier.dart +3 -3
  131. package/templates/firebase/lib/core/theme/colors.dart +488 -188
  132. package/templates/firebase/lib/core/theme/radius.dart +22 -11
  133. package/templates/firebase/lib/core/theme/shadows.dart +66 -0
  134. package/templates/firebase/lib/core/theme/texts.dart +75 -41
  135. package/templates/firebase/lib/core/theme/universal_theme.dart +9 -4
  136. package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +5 -4
  137. package/templates/firebase/lib/core/web_viewport_scale.dart +52 -0
  138. package/templates/firebase/lib/core/widgets/kasy_brand_badge.dart +118 -0
  139. package/templates/firebase/lib/core/widgets/kasy_brand_logo.dart +40 -0
  140. package/templates/firebase/lib/core/widgets/kasy_focus_ring.dart +125 -0
  141. package/templates/firebase/lib/core/widgets/kasy_hover.dart +33 -13
  142. package/templates/firebase/lib/core/widgets/kasy_pressable_depth.dart +18 -13
  143. package/templates/firebase/lib/{environnements.dart → environments.dart} +3 -14
  144. package/templates/firebase/lib/features/ai_chat/ai_chat_page.dart +159 -0
  145. package/templates/firebase/lib/features/ai_chat/api/ai_chat_api.dart +107 -0
  146. package/templates/firebase/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +64 -0
  147. package/templates/firebase/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +6 -6
  148. package/templates/firebase/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +73 -38
  149. package/templates/firebase/lib/features/ai_chat/providers/ai_conversations_notifier.dart +103 -0
  150. package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_avatars.dart → ai_chat/ui/widgets/ai_chat_avatars.dart} +13 -13
  151. package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_composer.dart → ai_chat/ui/widgets/ai_chat_composer.dart} +10 -10
  152. package/templates/firebase/lib/features/{llm_chat/llm_chat_page.dart → ai_chat/ui/widgets/ai_chat_conversation_view.dart} +80 -67
  153. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_list.dart +285 -0
  154. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +163 -0
  155. package/templates/firebase/lib/features/authentication/api/authentication_api.dart +52 -13
  156. package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher.dart +12 -0
  157. package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher_web.dart +35 -0
  158. package/templates/firebase/lib/features/authentication/ui/recover_password_page.dart +108 -68
  159. package/templates/firebase/lib/features/authentication/ui/signin_page.dart +38 -51
  160. package/templates/firebase/lib/features/authentication/ui/signup_page.dart +38 -51
  161. package/templates/firebase/lib/features/authentication/ui/widgets/auth_card_scaffold.dart +118 -0
  162. package/templates/firebase/lib/features/authentication/ui/widgets/recover_password_result.dart +61 -44
  163. package/templates/firebase/lib/features/feedbacks/api/feature_request_api.dart +32 -0
  164. package/templates/firebase/lib/features/feedbacks/models/feedback_state.dart +5 -5
  165. package/templates/firebase/lib/features/feedbacks/providers/feedback_page_notifier.dart +2 -2
  166. package/templates/firebase/lib/features/home/design_system_page.dart +808 -170
  167. package/templates/firebase/lib/features/home/home_components_page.dart +6 -3
  168. package/templates/firebase/lib/features/home/home_components_preview_page.dart +6 -6
  169. package/templates/firebase/lib/features/home/home_components_preview_registry.dart +325 -186
  170. package/templates/firebase/lib/features/home/home_feed.dart +289 -0
  171. package/templates/firebase/lib/features/home/home_image_grid.dart +355 -0
  172. package/templates/firebase/lib/features/home/home_page.dart +11 -250
  173. package/templates/firebase/lib/features/{local_reminder → local_reminders}/providers/reminder_notifier.dart +1 -1
  174. package/templates/firebase/lib/features/{local_reminder → local_reminders}/ui/reminder_page.dart +2 -2
  175. package/templates/firebase/lib/features/notifications/shared/att_permission.dart +1 -1
  176. package/templates/firebase/lib/features/notifications/ui/request_notification_permission.dart +25 -61
  177. package/templates/firebase/lib/features/notifications/ui/widgets/permission_request_view.dart +117 -0
  178. package/templates/firebase/lib/features/onboarding/models/user_info.dart +16 -16
  179. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  180. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_features.dart +7 -9
  181. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_loader.dart +71 -48
  182. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +3 -2
  183. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_questions.dart +5 -5
  184. package/templates/firebase/lib/features/onboarding/ui/onboarding_page.dart +4 -4
  185. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_background.dart +4 -2
  186. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_feature.dart +39 -121
  187. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_illustration_scaffold.dart +105 -70
  188. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_module_mockups.dart +639 -0
  189. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_progress.dart +62 -50
  190. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  191. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_step_header.dart +75 -0
  192. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_sticky_footer.dart +16 -5
  193. package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +26 -22
  194. package/templates/firebase/lib/features/settings/settings_page.dart +601 -90
  195. package/templates/firebase/lib/features/settings/ui/components/admin/admin_page.dart +1193 -0
  196. package/templates/firebase/lib/features/settings/ui/components/admin/admin_paywalls.dart +1 -1
  197. package/templates/firebase/lib/features/settings/ui/components/admin/admin_routes.dart +2 -3
  198. package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_api.dart +86 -0
  199. package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_tab.dart +1215 -0
  200. package/templates/firebase/lib/features/settings/ui/components/admin/send_push_notification_page.dart +236 -0
  201. package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +3 -3
  202. package/templates/firebase/lib/features/settings/ui/widgets/kasy_user_avatar.dart +77 -0
  203. package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +1 -0
  204. package/templates/firebase/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +17 -0
  205. package/templates/firebase/lib/features/{subscription → subscriptions}/api/inapp_subscription_api.dart +67 -46
  206. package/templates/firebase/lib/features/subscriptions/api/revenuecat_product.dart +189 -0
  207. package/templates/firebase/lib/features/subscriptions/api/stripe_backend_api.dart +55 -0
  208. package/templates/firebase/lib/features/subscriptions/api/stripe_payment_api.dart +82 -0
  209. package/templates/firebase/lib/features/subscriptions/api/stripe_product.dart +178 -0
  210. package/templates/firebase/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  211. package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api.dart +53 -0
  212. package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api_provider.dart +21 -0
  213. package/templates/firebase/lib/features/{subscription → subscriptions}/providers/premium_page_provider.dart +9 -6
  214. package/templates/firebase/lib/features/{subscription → subscriptions}/repositories/subscription_repository.dart +26 -30
  215. package/{lib/scaffold/backends/supabase/patch/lib/features/subscription → templates/firebase/lib/features/subscriptions}/shared/maybeshow_premium.dart +0 -2
  216. package/templates/firebase/lib/features/subscriptions/shared/subscription_management.dart +45 -0
  217. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/active_premium_content.dart +28 -4
  218. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_minimal.dart +7 -7
  219. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_row.dart +8 -8
  220. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_with_switch.dart +7 -7
  221. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_content.dart +7 -7
  222. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_page_factory.dart +5 -5
  223. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/premium_page.dart +5 -5
  224. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/comparison_table.dart +1 -1
  225. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/paywall_empty_state.dart +4 -4
  226. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_bottom_menu.dart +3 -4
  227. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_col.dart +1 -1
  228. package/templates/firebase/lib/i18n/en.i18n.json +171 -46
  229. package/templates/firebase/lib/i18n/es.i18n.json +175 -50
  230. package/templates/firebase/lib/i18n/pt.i18n.json +166 -41
  231. package/templates/firebase/lib/main.dart +6 -3
  232. package/templates/firebase/lib/router.dart +15 -23
  233. package/templates/firebase/pubspec.yaml +4 -5
  234. package/templates/firebase/test/core/data/repositories/user_repository_test.dart +3 -3
  235. package/templates/firebase/test/core/states/user_state_notifier_test.dart +4 -4
  236. package/templates/firebase/test/core/widgets/focus_ring_shape_test.dart +55 -0
  237. package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_inapp_subscription_api.dart +11 -4
  238. package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_revenuecat_product.dart +1 -0
  239. package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_subscription_api.dart +2 -2
  240. package/templates/firebase/test/features/{subscription → subscriptions}/subscription_page_test.dart +4 -4
  241. package/templates/firebase/test/test_utils.dart +6 -6
  242. package/templates/firebase/web/index.html +5 -2
  243. package/lib/scaffold/backends/api/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -58
  244. package/lib/scaffold/backends/api/patch/lib/features/subscription/shared/maybeshow_premium.dart +0 -86
  245. package/lib/scaffold/backends/supabase/migrations/20240101000009_llm_messages.sql +0 -22
  246. package/lib/scaffold/backends/supabase/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -47
  247. package/templates/firebase/assets/images/onboarding/authentication-login-template.jpg +0 -0
  248. package/templates/firebase/assets/images/onboarding/img2.jpg +0 -0
  249. package/templates/firebase/assets/images/onboarding/img3.jpg +0 -0
  250. package/templates/firebase/assets/images/onboarding/notifications.png +0 -0
  251. package/templates/firebase/assets/images/onboarding/purchase.png +0 -0
  252. package/templates/firebase/lib/core/sidebar/kasy_sidebar.dart +0 -2021
  253. package/templates/firebase/lib/features/authentication/ui/widgets/auth_brand.dart +0 -35
  254. package/templates/firebase/lib/features/home/home_features_page.dart +0 -207
  255. package/templates/firebase/lib/features/llm_chat/api/llm_chat_api.dart +0 -50
  256. package/templates/firebase/lib/features/settings/ui/components/admin/admin_bottom_sheet.dart +0 -316
  257. package/templates/firebase/lib/features/subscription/shared/maybeshow_premium.dart +0 -85
  258. /package/templates/firebase/lib/features/{local_reminder → local_reminders}/repositories/reminder_preferences.dart +0 -0
  259. /package/templates/firebase/lib/features/{subscription → subscriptions}/providers/models/premium_state.dart +0 -0
  260. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/feature_line.dart +0 -0
  261. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background.dart +0 -0
  262. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background_gradient.dart +0 -0
  263. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_banner.dart +0 -0
  264. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_card.dart +0 -0
  265. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_close_button.dart +0 -0
  266. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_feature.dart +0 -0
  267. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_row.dart +0 -0
  268. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/trial_switcher.dart +0 -0
  269. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/unsubscribe_feedback_popup.dart +0 -0
@@ -7,6 +7,7 @@ import 'package:kasy_kit/core/theme/theme.dart';
7
7
  import 'package:kasy_kit/core/widgets/responsive_layout.dart';
8
8
  import 'package:kasy_kit/features/onboarding/ui/widgets/onboarding_background.dart';
9
9
  import 'package:kasy_kit/features/onboarding/ui/widgets/onboarding_progress.dart';
10
+ import 'package:kasy_kit/features/onboarding/ui/widgets/onboarding_step_header.dart';
10
11
  import 'package:kasy_kit/features/onboarding/ui/widgets/onboarding_sticky_footer.dart';
11
12
  import 'package:kasy_kit/features/onboarding/ui/widgets/selectable_row_tile.dart';
12
13
 
@@ -18,9 +19,11 @@ typedef OnOptionIdSelected = void Function(String id);
18
19
 
19
20
  typedef OnValidate = void Function(String? key);
20
21
 
21
- /// Single choice question with radio buttons
22
+ /// Single choice question with selectable tiles, matching the clean‑premium
23
+ /// onboarding layout (shared header, left‑aligned title, sticky footer).
22
24
  class OnboardingRadioQuestion extends ConsumerStatefulWidget {
23
- final double? progress;
25
+ final int step;
26
+ final int totalSteps;
24
27
  final String title;
25
28
  final String description;
26
29
  final String btnText;
@@ -37,7 +40,8 @@ class OnboardingRadioQuestion extends ConsumerStatefulWidget {
37
40
  required this.btnText,
38
41
  required this.optionIds,
39
42
  required this.optionBuilder,
40
- this.progress,
43
+ required this.step,
44
+ this.totalSteps = kOnboardingSteps,
41
45
  this.onOptionIdSelected,
42
46
  this.onValidate,
43
47
  this.reassuranceBuilder,
@@ -54,61 +58,68 @@ class _OnboardingRadioQuestionState
54
58
 
55
59
  @override
56
60
  Widget build(BuildContext context) {
61
+ const gutter = KasySpacing.lg;
62
+
57
63
  final scrollBody = Column(
58
- crossAxisAlignment: CrossAxisAlignment.stretch,
64
+ crossAxisAlignment: CrossAxisAlignment.start,
59
65
  children: [
60
- if (widget.progress != null)
61
- OnboardingProgress(value: widget.progress!),
66
+ OnboardingStepHeader(step: widget.step, totalSteps: widget.totalSteps),
62
67
  Padding(
63
- padding: const EdgeInsets.fromLTRB(
64
- KasySpacing.md,
65
- KasySpacing.xl,
66
- KasySpacing.md,
67
- 0,
68
- ),
68
+ padding: const EdgeInsets.fromLTRB(gutter, KasySpacing.lg, gutter, 0),
69
69
  child: MoveFadeAnim(
70
- delayInMs: 100,
70
+ delayInMs: 120,
71
71
  child: Text(
72
72
  widget.title,
73
- textAlign: TextAlign.center,
74
- style: context.textTheme.headlineLarge?.copyWith(
73
+ textAlign: TextAlign.start,
74
+ style: context.textTheme.headlineMedium?.copyWith(
75
75
  color: context.colors.onBackground,
76
+ fontSize: 26,
77
+ fontWeight: FontWeight.w700,
78
+ letterSpacing: -0.2,
79
+ height: 1.2,
76
80
  ),
77
81
  ),
78
82
  ),
79
83
  ),
80
84
  Padding(
81
85
  padding: const EdgeInsets.fromLTRB(
86
+ gutter,
87
+ KasySpacing.smd,
88
+ gutter,
82
89
  KasySpacing.lg,
83
- KasySpacing.md,
84
- KasySpacing.lg,
85
- KasySpacing.xl,
86
90
  ),
87
91
  child: MoveFadeAnim(
88
92
  delayInMs: 200,
89
93
  child: Text(
90
94
  widget.description,
91
- textAlign: TextAlign.center,
95
+ textAlign: TextAlign.start,
92
96
  style: context.textTheme.bodyLarge?.copyWith(
93
- color: context.colors.onBackground.withValues(alpha: 0.6),
97
+ color: context.colors.muted,
98
+ height: 1.45,
94
99
  ),
95
100
  ),
96
101
  ),
97
102
  ),
98
103
  Padding(
99
- padding: const EdgeInsets.symmetric(horizontal: KasySpacing.md),
104
+ padding: const EdgeInsets.symmetric(horizontal: gutter),
100
105
  child: OnboardingSelectableRowGroup(
101
106
  physics: const NeverScrollableScrollPhysics(),
102
- options: widget.optionIds
103
- .map(
107
+ options: widget.optionIds.map(
104
108
  (e) {
105
109
  final index = widget.optionIds.indexOf(e);
106
110
  return Animate(
107
111
  effects: [
108
112
  FadeEffect(
109
- delay: Duration(milliseconds: 300 + index * 100),
110
- duration: const Duration(milliseconds: 550),
111
- curve: Curves.easeInOut,
113
+ delay: Duration(milliseconds: 280 + index * 80),
114
+ duration: const Duration(milliseconds: 450),
115
+ curve: Curves.easeOut,
116
+ ),
117
+ MoveEffect(
118
+ delay: Duration(milliseconds: 280 + index * 80),
119
+ duration: const Duration(milliseconds: 450),
120
+ curve: Curves.easeOut,
121
+ begin: const Offset(0, 24),
122
+ end: Offset.zero,
112
123
  ),
113
124
  ],
114
125
  child: widget.optionBuilder(e, e == selectedChoiceId),
@@ -153,8 +164,7 @@ class _OnboardingRadioQuestionState
153
164
  ),
154
165
  DeviceSizeBuilder(
155
166
  builder: (device) => OnboardingStickyFooter(
156
- maxContentWidth:
157
- device == DeviceType.small ? null : 600,
167
+ maxContentWidth: device == DeviceType.small ? null : 600,
158
168
  children: [
159
169
  KasyButton(
160
170
  label: widget.btnText,
@@ -0,0 +1,93 @@
1
+ import 'package:flutter_riverpod/flutter_riverpod.dart';
2
+ import 'package:kasy_kit/core/data/api/base_api_exceptions.dart';
3
+ import 'package:supabase_flutter/supabase_flutter.dart';
4
+
5
+ /// One row of the admin Users table, as returned by the `admin-list-users` Edge
6
+ /// Function. The function verifies the caller is `role == "admin"` and only then
7
+ /// reads across all users with the service role, so this data is never readable
8
+ /// by a non-admin client.
9
+ ///
10
+ /// This file mirrors the shared admin data-layer contract (see the Firebase
11
+ /// version): the public surface — [AdminUser], [AdminUsersResult] and
12
+ /// [adminUsersApiProvider] — is identical across backends so the Users tab UI
13
+ /// stays the same; only the body of [AdminUsersApi.fetch] differs.
14
+ class AdminUser {
15
+ final String id;
16
+ final String? email;
17
+ final String? name;
18
+ final DateTime? createdAt;
19
+ final bool subscriber;
20
+
21
+ const AdminUser({
22
+ required this.id,
23
+ required this.subscriber,
24
+ this.email,
25
+ this.name,
26
+ this.createdAt,
27
+ });
28
+
29
+ factory AdminUser.fromMap(Map<String, dynamic> m) {
30
+ final createdMillis = m['createdAt'];
31
+ return AdminUser(
32
+ id: (m['id'] as String?) ?? '',
33
+ email: m['email'] as String?,
34
+ name: m['name'] as String?,
35
+ createdAt: createdMillis is num
36
+ ? DateTime.fromMillisecondsSinceEpoch(createdMillis.toInt())
37
+ : null,
38
+ subscriber: m['subscriber'] == true,
39
+ );
40
+ }
41
+ }
42
+
43
+ /// The full (bounded) set of users plus collection metadata. The UI searches,
44
+ /// sorts and paginates this list locally, so those interactions are instant.
45
+ class AdminUsersResult {
46
+ final List<AdminUser> users;
47
+ final int totalUsers;
48
+ final bool truncated;
49
+
50
+ const AdminUsersResult({
51
+ required this.users,
52
+ required this.totalUsers,
53
+ required this.truncated,
54
+ });
55
+ }
56
+
57
+ final adminUsersApiProvider = Provider<AdminUsersApi>(
58
+ (ref) => AdminUsersApi(client: Supabase.instance.client),
59
+ );
60
+
61
+ class AdminUsersApi {
62
+ final SupabaseClient _client;
63
+
64
+ AdminUsersApi({required SupabaseClient client}) : _client = client;
65
+
66
+ /// Loads the users for the admin console via the `admin-list-users` Edge
67
+ /// Function. Returns the whole bounded set in one call; the UI handles
68
+ /// search/sort/pagination on the client.
69
+ Future<AdminUsersResult> fetch() async {
70
+ try {
71
+ final res = await _client.functions.invoke('admin-list-users');
72
+ if (res.status != 200) {
73
+ final msg = res.data is Map && res.data != null
74
+ ? (res.data as Map)['error'] as String? ?? 'Error listing users'
75
+ : 'Error listing users';
76
+ throw ApiError(code: res.status, message: msg);
77
+ }
78
+ final data = Map<String, dynamic>.from(res.data as Map);
79
+ final rawUsers = (data['users'] as List?) ?? const [];
80
+ return AdminUsersResult(
81
+ users: rawUsers
82
+ .map((e) => AdminUser.fromMap(Map<String, dynamic>.from(e as Map)))
83
+ .toList(),
84
+ totalUsers: (data['totalUsers'] as num?)?.toInt() ?? 0,
85
+ truncated: data['truncated'] == true,
86
+ );
87
+ } on ApiError {
88
+ rethrow;
89
+ } catch (e, stacktrace) {
90
+ throw ApiError(code: 0, message: '$e: $stacktrace');
91
+ }
92
+ }
93
+ }
@@ -15,6 +15,17 @@ enum SubscriptionStatus {
15
15
  CANCELLED,
16
16
  }
17
17
 
18
+ /// Where the subscription was purchased (its origin). `STRIPE` means it was
19
+ /// bought on the web via Stripe. Used to route the user to the correct
20
+ /// management flow regardless of the device they are currently on.
21
+ enum SubscriptionStore {
22
+ PLAY_STORE,
23
+ APPLE_STORE,
24
+ EARLY_BIRD,
25
+ STRIPE,
26
+ unknown,
27
+ }
28
+
18
29
 
19
30
  @freezed
20
31
  sealed class SubscriptionEntity with _$SubscriptionEntity {
@@ -27,6 +38,8 @@ sealed class SubscriptionEntity with _$SubscriptionEntity {
27
38
  @JsonKey(name: 'last_update_date') DateTime? lastUpdateDate,
28
39
  @JsonKey(name: 'period_end_date') DateTime? periodEndDate,
29
40
  @JsonKey(name: 'status') required SubscriptionStatus status,
41
+ @JsonKey(name: 'store', unknownEnumValue: SubscriptionStore.unknown)
42
+ SubscriptionStore? store,
30
43
  }) = SubscriptionEntityData;
31
44
 
32
45
  factory SubscriptionEntity.fromJson(Map<String, Object?> json) =>
@@ -0,0 +1,52 @@
1
+ import 'package:flutter_riverpod/flutter_riverpod.dart';
2
+ import 'package:kasy_kit/features/subscriptions/api/stripe_product.dart';
3
+ import 'package:supabase_flutter/supabase_flutter.dart';
4
+
5
+ final stripeBackendApiProvider = Provider<StripeBackendApi>(
6
+ (ref) => StripeBackendApi(client: Supabase.instance.client),
7
+ );
8
+
9
+ /// Talks to the Stripe backend (Supabase Edge Functions). The user identity is
10
+ /// taken server-side from the verified JWT — never trusted from the client.
11
+ /// This file replaces the Firebase version so the rest of the Stripe client
12
+ /// code stays backend-agnostic.
13
+ class StripeBackendApi {
14
+ final SupabaseClient _client;
15
+
16
+ StripeBackendApi({required SupabaseClient client}) : _client = client;
17
+
18
+ /// Active recurring prices, mapped to paywall offers.
19
+ Future<List<StripeProduct>> listPrices() async {
20
+ final res = await _client.functions.invoke('stripe-list-prices');
21
+ final list = (res.data as List).cast<dynamic>();
22
+ return list
23
+ .map((e) => StripeProduct.fromJson(Map<String, dynamic>.from(e as Map)))
24
+ .toList();
25
+ }
26
+
27
+ /// Create a hosted Checkout session for [priceId] and return its URL.
28
+ Future<String> createCheckoutSession({
29
+ required String priceId,
30
+ String? successUrl,
31
+ String? cancelUrl,
32
+ }) async {
33
+ final res = await _client.functions.invoke(
34
+ 'stripe-create-checkout-session',
35
+ body: {
36
+ 'priceId': priceId,
37
+ if (successUrl != null) 'successUrl': successUrl,
38
+ if (cancelUrl != null) 'cancelUrl': cancelUrl,
39
+ },
40
+ );
41
+ return (res.data as Map)['url'] as String;
42
+ }
43
+
44
+ /// Create a Customer Portal session (manage / cancel) and return its URL.
45
+ Future<String> createPortalSession({String? returnUrl}) async {
46
+ final res = await _client.functions.invoke(
47
+ 'stripe-create-portal-session',
48
+ body: {if (returnUrl != null) 'returnUrl': returnUrl},
49
+ );
50
+ return (res.data as Map)['url'] as String;
51
+ }
52
+ }
@@ -1,7 +1,7 @@
1
1
  import 'package:flutter_riverpod/flutter_riverpod.dart';
2
2
  import 'package:logger/logger.dart';
3
3
  import 'package:kasy_kit/core/data/api/base_api_exceptions.dart';
4
- import 'package:kasy_kit/features/subscription/api/entities/subscription_entity.dart';
4
+ import 'package:kasy_kit/features/subscriptions/api/entities/subscription_entity.dart';
5
5
  import 'package:supabase_flutter/supabase_flutter.dart';
6
6
 
7
7
  final subscriptionApiProvider = Provider(
@@ -95,7 +95,6 @@ flutter:
95
95
  assets:
96
96
  - .env
97
97
  - assets/images/
98
- - assets/images/onboarding/
99
98
  - assets/icons/
100
99
  flutter_launcher_icons:
101
100
  image_path: assets/images/icon.png
@@ -110,15 +109,15 @@ flutter_launcher_icons:
110
109
  background_color: "#01171f"
111
110
  theme_color: "#01171f"
112
111
  flutter_native_splash:
113
- color: "#FFFFFF"
114
- color_dark: "#000000"
112
+ color: "#FAF9FC"
113
+ color_dark: "#0C0A14"
115
114
  fullscreen: true
116
115
  ios: true
117
116
  android: true
118
117
  image: assets/images/splash_logo_light.png
119
118
  image_dark: assets/images/splash_logo_dark.png
120
119
  android_12:
121
- color: "#FFFFFF"
122
- color_dark: "#000000"
120
+ color: "#FAF9FC"
121
+ color_dark: "#0C0A14"
123
122
  image: assets/images/splash_logo_light_android12.png
124
123
  image_dark: assets/images/splash_logo_dark_android12.png
@@ -1,7 +1,7 @@
1
1
  /**
2
- * @deprecated Este arquivo não é importado por nenhum módulo.
3
- * O token map é compartilhado por todos os backends via firebase/tokens.js.
4
- * Mantido apenas para referência históricapode ser removido com segurança.
2
+ * @deprecated This file is not imported by any module.
3
+ * The token map is shared by all backends via firebase/tokens.js.
4
+ * Kept only for historical referencecan be safely removed.
5
5
  */
6
6
 
7
7
  const { buildTokens } = require('../firebase/tokens');
@@ -34,7 +34,6 @@ const AVAILABLE_BACKENDS = [
34
34
  * project but only sells real plans once RevenueCat is added.
35
35
  *
36
36
  * Note on id vs folder name (intentional, not a bug):
37
- * - id `local_notifications` → folder `lib/features/local_reminder/`
38
37
  * - id `feedback` → folder `lib/features/feedbacks/`
39
38
  * The id describes the user-facing capability; the folder describes the
40
39
  * Dart component. The generator (see generator-utils.js writeRouter and
@@ -47,13 +46,14 @@ const FEATURE_CATALOG = [
47
46
  { id: 'analytics', displayName: 'Analytics', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['starter', 'saas', 'content', 'full'] },
48
47
  { id: 'facebook', displayName: 'Facebook (Login + Ads)', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['full'] },
49
48
  // monetization
50
- { id: 'revenuecat', displayName: 'RevenueCat', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['saas', 'full'], enhances: 'subscription' },
49
+ { id: 'revenuecat', displayName: 'In-App Purchases (RevenueCat)', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['saas', 'full'], enhances: 'subscriptions' },
50
+ { id: 'stripe', displayName: 'Web Payments (Stripe)', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['saas', 'full'], enhances: 'subscriptions' },
51
51
  // features
52
52
  { id: 'onboarding', displayName: 'Onboarding', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['starter', 'saas', 'content', 'full'] },
53
53
  { id: 'web', displayName: 'Web Support (PWA)', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['full'] },
54
54
  { id: 'widget', displayName: 'Home Widget', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['full'] },
55
- { id: 'llm_chat', displayName: 'AI Chat', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['content', 'full'] },
56
- { id: 'local_notifications', displayName: 'Local Reminders', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: [] },
55
+ { id: 'ai_chat', displayName: 'AI Chat', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['content', 'full'] },
56
+ { id: 'local_reminders', displayName: 'Local Reminders', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: [] },
57
57
  // feedback (Firebase/Supabase only)
58
58
  { id: 'feedback', displayName: 'Feature Requests', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['saas', 'full'], tag: 'requiresDb' },
59
59
  // ci/cd
@@ -66,11 +66,11 @@ const FEATURE_CATALOG = [
66
66
  * Listed in the CLI so users understand what ships with every project.
67
67
  */
68
68
  const BASE_FEATURES = [
69
- { id: 'authentication', displayName: 'Auth' },
70
- { id: 'home', displayName: 'Home Screen' },
71
- { id: 'settings', displayName: 'Settings Screen' },
69
+ { id: 'authentication', displayName: 'Authentication' },
70
+ { id: 'home', displayName: 'Home' },
71
+ { id: 'settings', displayName: 'Settings' },
72
72
  { id: 'notifications', displayName: 'Push Notifications' },
73
- { id: 'subscription', displayName: 'Subscriptions' },
73
+ { id: 'subscriptions', displayName: 'Subscriptions' },
74
74
  ];
75
75
 
76
76
  function getBaseFeatures() {
@@ -203,11 +203,9 @@ function normalizeFeature(value) {
203
203
  }
204
204
 
205
205
  const aliases = {
206
- llm: 'llm_chat',
207
- llmchat: 'llm_chat',
208
- llm_chat: 'llm_chat',
209
206
  rc: 'revenuecat',
210
207
  revenue: 'revenuecat',
208
+ stripe: 'stripe',
211
209
  onboard: 'onboarding',
212
210
  fb: 'facebook',
213
211
  };
@@ -1,27 +1,27 @@
1
1
  /**
2
- * generate.js — Motor unificado de geração de projetos.
2
+ * generate.js — Unified project generation engine.
3
3
  *
4
- * Todos os backends (Firebase, Supabase, API) usam este motor.
5
- * Cada backend fornece dois hooks opcionais:
4
+ * All backends (Firebase, Supabase, API) use this engine.
5
+ * Each backend provides two optional hooks:
6
6
  *
7
7
  * applyBackendSetup(targetDir, tokens, pathReplacements, options)
8
- * → Chamado dentro do bloco project-setup, logo após copyWithTokens.
9
- * → Responsável por: aplicar patch do backend, trocar pubspec.yaml,
10
- * remover artefatos irrelevantes, escrever overrides de environment
11
- * e copiar arquivos extras do backend (ex: supabase/migrations/).
12
- * → Retorna: { detail?, extraAnswers?, kitSetupExtra?, returnExtra? }
13
- * - detail : string extra para o log do passo (ex: "12 patch files")
14
- * - extraAnswers : campos extras para writeVsCodeLaunch / writeEnvExample
15
- * - kitSetupExtra: campos extras para writeKitSetup
16
- * - returnExtra : campos extras no objeto de retorno da função
8
+ * → Called inside the project-setup block, right after copyWithTokens.
9
+ * → Responsible for: applying the backend patch, swapping pubspec.yaml,
10
+ * removing irrelevant artifacts, writing environment overrides
11
+ * and copying extra backend files (e.g. supabase/migrations/).
12
+ * → Returns: { detail?, extraAnswers?, kitSetupExtra?, returnExtra? }
13
+ * - detail : extra string for the step log (e.g. "12 patch files")
14
+ * - extraAnswers : extra fields for writeVsCodeLaunch / writeEnvExample
15
+ * - kitSetupExtra: extra fields for writeKitSetup
16
+ * - returnExtra : extra fields in the function's return object
17
17
  *
18
18
  * postBuild(targetDir, options, steps)
19
- * → Chamado após build-runner e flutterfire configure.
20
- * → Responsável por: deploy automático (Firebase), etc.
19
+ * → Called after build-runner and flutterfire configure.
20
+ * → Responsible for: automatic deploy (Firebase), etc.
21
21
  *
22
- * Passos comuns executados para todos os backends:
23
- * 1. Validação do template base (Firebase/)
24
- * 2. buildTokens (tokens de substituição de texto)
22
+ * Common steps executed for all backends:
23
+ * 1. Validate the base template (Firebase/)
24
+ * 2. buildTokens (text replacement tokens)
25
25
  * 3. copyWithTokens (Firebase/ → targetDir)
26
26
  * [hook: applyBackendSetup]
27
27
  * 3b. applyFeaturePatches (features/ci/, features/web/, etc.)
@@ -32,7 +32,7 @@
32
32
  * 8. flutter pub get
33
33
  * 9. dart run slang
34
34
  * 10. dart run build_runner build
35
- * 11. flutterfire configure (Firebase para FCM + Remote Config — todos os backends)
35
+ * 11. flutterfire configure (Firebase for FCM + Remote Config — all backends)
36
36
  * 12. writeFirebaserc
37
37
  * [hook: postBuild]
38
38
  */
@@ -61,6 +61,7 @@ const {
61
61
  patchLanguageSwitcherNoWidget,
62
62
  writeNoOpFeatureRequestRepository,
63
63
  writeNoOpSubscriptionStubs,
64
+ writeStripeOnlySubscription,
64
65
  writeNoOpSentryUsages,
65
66
  writeMainDart,
66
67
  removeModuleDirs,
@@ -69,21 +70,22 @@ const {
69
70
  localizeReleaseDocs,
70
71
  } = require('./shared/generator-utils');
71
72
  const { pubGet, slangGenerate, buildRunner, dartFix, flutterfireConfigure, writeGoogleAuthOptions, writeGoogleIosUrlScheme, patchFirebaseServiceWorker, deployFirestoreRules } = require('./shared/post-build');
73
+ const { sortImportsInDirs } = require('./shared/sort-imports');
72
74
  const { FIREBASE_SOURCE_DIR } = require('./shared/backend-config');
73
75
 
74
76
  /**
75
- * Gera um projeto Flutter para o backend indicado.
77
+ * Generates a Flutter project for the given backend.
76
78
  *
77
- * @param {string} targetDir - Caminho absoluto do diretório de destino.
78
- * @param {'firebase'|'supabase'|'api'} backend - Backend selecionado.
79
+ * @param {string} targetDir - Absolute path of the destination directory.
80
+ * @param {'firebase'|'supabase'|'api'} backend - Selected backend.
79
81
  * @param {object} options
80
82
  * @param {string} options.appName
81
83
  * @param {string} options.bundleId
82
84
  * @param {string} options.firebaseProjectId
83
85
  * @param {string[]} [options.modules=[]]
84
86
  * @param {object} [options.moduleAnswers={}]
85
- * @param {Function} [options.onProgress] - Callback para atualizar spinner no CLI.
86
- * @param {object} [options.deploy] - Usado pelo hook postBuild do Firebase.
87
+ * @param {Function} [options.onProgress] - Callback to update the spinner in the CLI.
88
+ * @param {object} [options.deploy] - Used by the Firebase postBuild hook.
87
89
  * @param {object} [hooks={}]
88
90
  * @param {Function|null} [hooks.applyBackendSetup]
89
91
  * @param {Function|null} [hooks.postBuild]
@@ -248,17 +250,24 @@ async function generateProject(targetDir, backend, options, hooks = {}) {
248
250
  await removeFacebookSigninFromAuthPages(targetDir);
249
251
  }
250
252
 
251
- // Write no-op feature_request_repository.dart if feedback not selected but revenuecat IS selected.
252
- // Only premium_page_provider.dart (subscription module) imports this when revenuecat is not
253
- // selected the subscription module is removed entirely, so the stub is not needed.
254
- if (!modules.includes('feedback') && modules.includes('revenuecat')) {
253
+ // Write no-op feature_request_repository.dart if feedback not selected but the
254
+ // subscription CORE is present (RevenueCat OR Stripe). Only premium_page_provider.dart
255
+ // (subscription module) imports this when neither is selected the subscription module
256
+ // is removed entirely, so the stub is not needed.
257
+ if (!modules.includes('feedback') && (modules.includes('revenuecat') || modules.includes('stripe'))) {
255
258
  await writeNoOpFeatureRequestRepository(targetDir, packageName);
256
259
  }
257
260
 
258
- // Write no-op subscription stubs if revenuecat not selected
259
- // (user_repository, home_page, admin_paywalls, onboarding_page reference subscription types)
260
- if (!modules.includes('revenuecat')) {
261
+ // Subscription core gating:
262
+ // - neither RevenueCat nor Stripe → remove the module, write no-op stubs
263
+ // (user_repository, home_page, admin_paywalls, onboarding_page reference subscription types).
264
+ // - Stripe without RevenueCat → keep the core but strip the purchases_flutter
265
+ // (RevenueCat) files so the app compiles without the RevenueCat SDK.
266
+ // - RevenueCat (with or without Stripe) → keep everything as-is.
267
+ if (!modules.includes('revenuecat') && !modules.includes('stripe')) {
261
268
  await writeNoOpSubscriptionStubs(targetDir, packageName);
269
+ } else if (modules.includes('stripe') && !modules.includes('revenuecat')) {
270
+ await writeStripeOnlySubscription(targetDir, packageName);
262
271
  }
263
272
 
264
273
  // Write no-op admin_home_widgets.dart if widget not selected
@@ -290,6 +299,11 @@ async function generateProject(targetDir, backend, options, hooks = {}) {
290
299
 
291
300
  // Remove internal DEVELOPMENT_TEAM from iOS project — clients use their own Apple team
292
301
  await removeDevelopmentTeam(targetDir);
302
+
303
+ // Sort Dart imports so the renamed package keeps the directives_ordering
304
+ // lint happy (the source order is alphabetical for `kasy_kit`, which breaks
305
+ // once renamed to the project's package). Best-effort, never throws.
306
+ sortImportsInDirs([path.join(targetDir, 'lib'), path.join(targetDir, 'test')]);
293
307
  // ── End Phase B ──────────────────────────────────────────────────────────
294
308
 
295
309
  steps.push({ name: 'project-setup', ok: true, detail: setupDetail });
@@ -383,7 +397,7 @@ async function generateProject(targetDir, backend, options, hooks = {}) {
383
397
  steps.push({ name: 'firestore-rules', ok: rulesResult.ok, detail: rulesResult.ok ? null : rulesResult.error });
384
398
  }
385
399
 
386
- // ── 3. Post-build específico do backend ────────────────────────────────────
400
+ // ── 3. Backend-specific post-build ────────────────────────────────────
387
401
  if (postBuild) {
388
402
  try {
389
403
  await postBuild(targetDir, options, steps);