kasy-cli 1.21.9 → 1.23.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.
- package/lib/commands/add.js +93 -80
- package/lib/commands/configure.js +100 -32
- package/lib/commands/doctor.js +28 -2
- package/lib/commands/new.js +80 -37
- package/lib/commands/notifications.js +1 -1
- package/lib/commands/remove.js +43 -15
- package/lib/commands/run.js +2 -2
- package/lib/commands/update.js +2 -2
- package/lib/scaffold/CHANGELOG.json +14 -0
- package/lib/scaffold/backends/api/generator.js +14 -14
- package/lib/scaffold/backends/api/patch/README.md +83 -0
- package/lib/scaffold/backends/api/patch/lib/core/data/api/storage_api.dart +1 -1
- package/lib/scaffold/backends/api/patch/lib/core/data/entities/user_entity.dart +5 -0
- package/lib/scaffold/backends/api/patch/lib/{environnements.dart → environments.dart} +3 -11
- package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_api.dart +108 -0
- package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +51 -0
- 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
- package/lib/scaffold/backends/api/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +71 -38
- package/lib/scaffold/backends/api/patch/lib/features/authentication/api/authentication_api.dart +2 -2
- package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_request_api.dart +54 -0
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/models/user_info.dart +16 -16
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
- package/lib/scaffold/backends/api/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +100 -0
- package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
- package/lib/scaffold/backends/api/patch/lib/features/subscriptions/api/stripe_backend_api.dart +60 -0
- package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
- package/lib/scaffold/backends/api/pubspec.yaml.tpl +4 -5
- package/lib/scaffold/backends/firebase/deploy.js +87 -13
- package/lib/scaffold/backends/firebase/generator.js +5 -5
- package/lib/scaffold/backends/firebase/tokens.js +4 -4
- package/lib/scaffold/backends/supabase/deploy.js +63 -11
- package/lib/scaffold/backends/supabase/edge-functions/admin-list-users/index.ts +149 -0
- package/lib/scaffold/backends/supabase/edge-functions/{llm-chat → ai-chat}/index.ts +19 -19
- package/lib/scaffold/backends/supabase/edge-functions/revenuecat-webhook/index.ts +2 -0
- package/lib/scaffold/backends/supabase/edge-functions/stripe-create-checkout-session/index.ts +123 -0
- package/lib/scaffold/backends/supabase/edge-functions/stripe-create-portal-session/index.ts +97 -0
- package/lib/scaffold/backends/supabase/edge-functions/stripe-list-prices/index.ts +83 -0
- package/lib/scaffold/backends/supabase/edge-functions/stripe-webhook/index.ts +138 -0
- package/lib/scaffold/backends/supabase/generator.js +17 -17
- package/lib/scaffold/backends/supabase/migrations/20240101000009_ai_messages.sql +50 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000012_stripe_customers.sql +36 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000013_admin_role.sql +62 -0
- package/lib/scaffold/backends/supabase/patch/lib/core/data/entities/user_entity.dart +4 -0
- package/lib/scaffold/backends/supabase/patch/lib/{environnements.dart → environments.dart} +3 -13
- package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_api.dart +95 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +52 -0
- 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
- package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +63 -35
- package/lib/scaffold/backends/supabase/patch/lib/features/authentication/api/authentication_api.dart +1 -1
- package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/api/feature_request_api.dart +46 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/models/user_info.dart +16 -16
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
- package/lib/scaffold/backends/supabase/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +93 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/subscriptions/api/stripe_backend_api.dart +52 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
- package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +4 -5
- package/lib/scaffold/backends/supabase/tokens.js +3 -3
- package/lib/scaffold/catalog.js +9 -11
- package/lib/scaffold/generate.js +45 -31
- package/lib/scaffold/shared/generator-utils.js +188 -81
- package/lib/scaffold/shared/sort-imports.js +191 -0
- package/lib/scaffold/shared/template-strings.js +3 -3
- package/lib/utils/checks.js +22 -6
- package/lib/utils/env-tools.js +7 -0
- package/lib/utils/flutter-install.js +114 -0
- package/lib/utils/i18n/messages-en.js +52 -35
- package/lib/utils/i18n/messages-es.js +52 -35
- package/lib/utils/i18n/messages-pt.js +54 -37
- package/lib/utils/updates.js +15 -15
- package/package.json +1 -1
- package/templates/firebase/.env.example +2 -2
- package/templates/firebase/android/app/src/main/res/drawable/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-v21/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-v21/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/values-night-v31/styles.xml +1 -1
- package/templates/firebase/android/app/src/main/res/values-v31/styles.xml +1 -1
- package/templates/firebase/assets/images/logo_wordmark_dark.png +0 -0
- package/templates/firebase/assets/images/logo_wordmark_light.png +0 -0
- package/templates/firebase/docs/revenuecat-setup.es.md +1 -1
- package/templates/firebase/docs/revenuecat-setup.pt.md +1 -1
- package/templates/firebase/firestore.rules +24 -5
- package/templates/firebase/functions/package-lock.json +22 -1
- package/templates/firebase/functions/package.json +2 -1
- package/templates/firebase/functions/src/admin/functions.ts +113 -0
- package/templates/firebase/functions/src/{llm_chat → ai_chat}/index.ts +16 -16
- package/templates/firebase/functions/src/index.ts +8 -2
- package/templates/firebase/functions/src/notifications/device_triggers.ts +2 -2
- package/templates/firebase/functions/src/notifications/triggers.ts +3 -3
- package/templates/firebase/functions/src/subscriptions/models/subscription_status.ts +2 -0
- package/templates/firebase/functions/src/subscriptions/stripe_functions.ts +222 -0
- package/templates/firebase/functions/src/subscriptions/subscriptions_functions.ts +2 -2
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png +0 -0
- package/templates/firebase/lib/components/components.dart +4 -1
- package/templates/firebase/lib/components/kasy_app_bar.dart +22 -7
- package/templates/firebase/lib/components/kasy_avatar.dart +7 -6
- package/templates/firebase/lib/components/kasy_button.dart +23 -99
- package/templates/firebase/lib/components/kasy_dialog.dart +11 -11
- package/templates/firebase/lib/components/kasy_image_viewer.dart +84 -0
- package/templates/firebase/lib/components/{kasy_sidebar_pro.dart → kasy_sidebar.dart} +702 -425
- package/templates/firebase/lib/components/kasy_status_tag.dart +91 -0
- package/templates/firebase/lib/components/kasy_text_area.dart +1 -3
- package/templates/firebase/lib/components/kasy_text_field.dart +5 -6
- package/templates/firebase/lib/components/kasy_text_field_otp.dart +1 -3
- package/templates/firebase/lib/components/kasy_toast.dart +2 -2
- package/templates/firebase/lib/components/kasy_web_header.dart +209 -0
- package/templates/firebase/lib/core/ads/ads_provider.dart +1 -1
- package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +136 -23
- package/templates/firebase/lib/core/bottom_menu/bottom_router.dart +19 -91
- package/templates/firebase/lib/core/bottom_menu/kasy_bottom_bar_factory.dart +196 -96
- package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +54 -0
- package/templates/firebase/lib/core/config/app_env.dart +5 -11
- package/templates/firebase/lib/core/config/features.dart +5 -4
- package/templates/firebase/lib/core/data/api/analytics_api.dart +1 -1
- package/templates/firebase/lib/core/data/api/http_client.dart +1 -1
- package/templates/firebase/lib/core/data/entities/user_entity.dart +3 -0
- package/templates/firebase/lib/core/data/models/entitlement.dart +35 -0
- package/templates/firebase/lib/core/data/models/subscription.dart +13 -186
- package/templates/firebase/lib/core/data/models/user.dart +11 -0
- package/templates/firebase/lib/core/data/repositories/user_repository.dart +1 -1
- package/templates/firebase/lib/core/home_widgets/home_widget_background_task.dart +1 -1
- package/templates/firebase/lib/core/home_widgets/home_widget_mywidget_service.dart +1 -1
- package/templates/firebase/lib/core/icons/kasy_icons.dart +31 -1
- package/templates/firebase/lib/core/rating/api/rating_api.dart +2 -2
- package/templates/firebase/lib/core/states/logout_action.dart +25 -0
- package/templates/firebase/lib/core/states/user_state_notifier.dart +3 -3
- package/templates/firebase/lib/core/theme/colors.dart +488 -188
- package/templates/firebase/lib/core/theme/radius.dart +22 -11
- package/templates/firebase/lib/core/theme/shadows.dart +66 -0
- package/templates/firebase/lib/core/theme/texts.dart +75 -41
- package/templates/firebase/lib/core/theme/universal_theme.dart +9 -4
- package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +5 -4
- package/templates/firebase/lib/core/web_viewport_scale.dart +52 -0
- package/templates/firebase/lib/core/widgets/kasy_brand_badge.dart +118 -0
- package/templates/firebase/lib/core/widgets/kasy_brand_logo.dart +40 -0
- package/templates/firebase/lib/core/widgets/kasy_focus_ring.dart +125 -0
- package/templates/firebase/lib/core/widgets/kasy_hover.dart +53 -14
- package/templates/firebase/lib/core/widgets/kasy_pressable_depth.dart +18 -13
- package/templates/firebase/lib/{environnements.dart → environments.dart} +3 -14
- package/templates/firebase/lib/features/ai_chat/ai_chat_page.dart +159 -0
- package/templates/firebase/lib/features/ai_chat/api/ai_chat_api.dart +107 -0
- package/templates/firebase/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +64 -0
- package/templates/firebase/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +6 -6
- package/templates/firebase/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +73 -38
- package/templates/firebase/lib/features/ai_chat/providers/ai_conversations_notifier.dart +103 -0
- package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_avatars.dart → ai_chat/ui/widgets/ai_chat_avatars.dart} +13 -13
- package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_composer.dart → ai_chat/ui/widgets/ai_chat_composer.dart} +10 -10
- package/templates/firebase/lib/features/{llm_chat/llm_chat_page.dart → ai_chat/ui/widgets/ai_chat_conversation_view.dart} +80 -67
- package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_list.dart +285 -0
- package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +163 -0
- package/templates/firebase/lib/features/authentication/api/authentication_api.dart +52 -13
- package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher.dart +12 -0
- package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher_web.dart +35 -0
- package/templates/firebase/lib/features/authentication/ui/recover_password_page.dart +108 -68
- package/templates/firebase/lib/features/authentication/ui/signin_page.dart +38 -51
- package/templates/firebase/lib/features/authentication/ui/signup_page.dart +38 -51
- package/templates/firebase/lib/features/authentication/ui/widgets/auth_card_scaffold.dart +128 -0
- package/templates/firebase/lib/features/authentication/ui/widgets/recover_password_result.dart +61 -44
- package/templates/firebase/lib/features/feedbacks/api/feature_request_api.dart +32 -0
- package/templates/firebase/lib/features/feedbacks/models/feedback_state.dart +5 -5
- package/templates/firebase/lib/features/feedbacks/providers/feedback_page_notifier.dart +2 -2
- package/templates/firebase/lib/features/home/design_system_page.dart +808 -170
- package/templates/firebase/lib/features/home/home_components_page.dart +6 -3
- package/templates/firebase/lib/features/home/home_components_preview_page.dart +6 -6
- package/templates/firebase/lib/features/home/home_components_preview_registry.dart +325 -186
- package/templates/firebase/lib/features/home/home_feed.dart +289 -0
- package/templates/firebase/lib/features/home/home_image_grid.dart +355 -0
- package/templates/firebase/lib/features/home/home_page.dart +11 -250
- package/templates/firebase/lib/features/{local_reminder → local_reminders}/providers/reminder_notifier.dart +1 -1
- package/templates/firebase/lib/features/{local_reminder → local_reminders}/ui/reminder_page.dart +2 -2
- package/templates/firebase/lib/features/notifications/shared/att_permission.dart +1 -1
- package/templates/firebase/lib/features/notifications/ui/request_notification_permission.dart +25 -61
- package/templates/firebase/lib/features/notifications/ui/widgets/permission_request_view.dart +117 -0
- package/templates/firebase/lib/features/onboarding/models/user_info.dart +16 -16
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_features.dart +7 -9
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_loader.dart +71 -48
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +3 -2
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_questions.dart +5 -5
- package/templates/firebase/lib/features/onboarding/ui/onboarding_page.dart +4 -4
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_background.dart +4 -2
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_feature.dart +39 -121
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_illustration_scaffold.dart +105 -70
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_module_mockups.dart +639 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_progress.dart +62 -50
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_step_header.dart +75 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_sticky_footer.dart +16 -5
- package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +26 -22
- package/templates/firebase/lib/features/settings/settings_page.dart +601 -90
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_page.dart +1193 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_paywalls.dart +1 -1
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_routes.dart +2 -3
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_api.dart +86 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_tab.dart +1215 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/send_push_notification_page.dart +236 -0
- package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +3 -3
- package/templates/firebase/lib/features/settings/ui/widgets/kasy_user_avatar.dart +77 -0
- package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +1 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +17 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/api/inapp_subscription_api.dart +67 -46
- package/templates/firebase/lib/features/subscriptions/api/revenuecat_product.dart +189 -0
- package/templates/firebase/lib/features/subscriptions/api/stripe_backend_api.dart +55 -0
- package/templates/firebase/lib/features/subscriptions/api/stripe_payment_api.dart +82 -0
- package/templates/firebase/lib/features/subscriptions/api/stripe_product.dart +178 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
- package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api.dart +53 -0
- package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api_provider.dart +21 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/providers/premium_page_provider.dart +9 -6
- package/templates/firebase/lib/features/{subscription → subscriptions}/repositories/subscription_repository.dart +26 -30
- package/{lib/scaffold/backends/supabase/patch/lib/features/subscription → templates/firebase/lib/features/subscriptions}/shared/maybeshow_premium.dart +0 -2
- package/templates/firebase/lib/features/subscriptions/shared/subscription_management.dart +45 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/active_premium_content.dart +28 -4
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_minimal.dart +7 -7
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_row.dart +8 -8
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_with_switch.dart +7 -7
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_content.dart +7 -7
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_page_factory.dart +5 -5
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/premium_page.dart +5 -5
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/comparison_table.dart +1 -1
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/paywall_empty_state.dart +4 -4
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_bottom_menu.dart +3 -4
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_col.dart +1 -1
- package/templates/firebase/lib/i18n/en.i18n.json +171 -46
- package/templates/firebase/lib/i18n/es.i18n.json +175 -50
- package/templates/firebase/lib/i18n/pt.i18n.json +166 -41
- package/templates/firebase/lib/main.dart +6 -3
- package/templates/firebase/lib/router.dart +15 -23
- package/templates/firebase/pubspec.yaml +5 -6
- package/templates/firebase/test/core/data/repositories/user_repository_test.dart +3 -3
- package/templates/firebase/test/core/states/user_state_notifier_test.dart +4 -4
- package/templates/firebase/test/core/widgets/focus_ring_shape_test.dart +55 -0
- package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_inapp_subscription_api.dart +11 -4
- package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_revenuecat_product.dart +1 -0
- package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_subscription_api.dart +2 -2
- package/templates/firebase/test/features/{subscription → subscriptions}/subscription_page_test.dart +4 -4
- package/templates/firebase/test/test_utils.dart +6 -6
- package/templates/firebase/web/index.html +5 -2
- package/lib/scaffold/backends/api/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -58
- package/lib/scaffold/backends/api/patch/lib/features/subscription/shared/maybeshow_premium.dart +0 -86
- package/lib/scaffold/backends/supabase/migrations/20240101000009_llm_messages.sql +0 -22
- package/lib/scaffold/backends/supabase/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -47
- package/templates/firebase/assets/images/onboarding/authentication-login-template.jpg +0 -0
- package/templates/firebase/assets/images/onboarding/img2.jpg +0 -0
- package/templates/firebase/assets/images/onboarding/img3.jpg +0 -0
- package/templates/firebase/assets/images/onboarding/notifications.png +0 -0
- package/templates/firebase/assets/images/onboarding/purchase.png +0 -0
- package/templates/firebase/lib/core/sidebar/kasy_sidebar.dart +0 -2021
- package/templates/firebase/lib/features/authentication/ui/widgets/auth_brand.dart +0 -35
- package/templates/firebase/lib/features/home/home_features_page.dart +0 -207
- package/templates/firebase/lib/features/llm_chat/api/llm_chat_api.dart +0 -50
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_bottom_sheet.dart +0 -316
- package/templates/firebase/lib/features/subscription/shared/maybeshow_premium.dart +0 -85
- /package/templates/firebase/lib/features/{local_reminder → local_reminders}/repositories/reminder_preferences.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/providers/models/premium_state.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/feature_line.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background_gradient.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_banner.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_card.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_close_button.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_feature.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_row.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/trial_switcher.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/unsubscribe_feedback_popup.dart +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared utilities for all backend generators.
|
|
3
|
-
* Single source of truth for dart-defines, launch.json, .env.example,
|
|
3
|
+
* Single source of truth for dart-defines, launch.json, .env.example, environments.
|
|
4
4
|
*
|
|
5
5
|
* @module scaffold/shared/generator-utils
|
|
6
6
|
*/
|
|
@@ -75,11 +75,6 @@ function buildDartDefines(backend, modules, answers) {
|
|
|
75
75
|
dev.push(`--dart-define=RC_IOS_API_KEY=${iosDefault}`);
|
|
76
76
|
prod.push(`--dart-define=RC_ANDROID_API_KEY=${androidDefault}`);
|
|
77
77
|
prod.push(`--dart-define=RC_IOS_API_KEY=${iosDefault}`);
|
|
78
|
-
if (answers.revenuecatWeb) {
|
|
79
|
-
const webKey = answers.rcWebKey || 'YOUR_REVENUECAT_WEB_KEY';
|
|
80
|
-
dev.push(`--dart-define=RC_WEB_API_KEY=${webKey}`);
|
|
81
|
-
prod.push(`--dart-define=RC_WEB_API_KEY=${webKey}`);
|
|
82
|
-
}
|
|
83
78
|
}
|
|
84
79
|
if (modules.includes('sentry')) {
|
|
85
80
|
const dsn = answers.sentryDsn || 'YOUR_SENTRY_DSN';
|
|
@@ -90,22 +85,22 @@ function buildDartDefines(backend, modules, answers) {
|
|
|
90
85
|
dev.push(`--dart-define=MIXPANEL_TOKEN=${token}`);
|
|
91
86
|
prod.push(`--dart-define=MIXPANEL_TOKEN=${token}`);
|
|
92
87
|
}
|
|
93
|
-
if (modules.includes('
|
|
94
|
-
let endpoint = answers.
|
|
88
|
+
if (modules.includes('ai_chat')) {
|
|
89
|
+
let endpoint = answers.aiChatEndpoint || '';
|
|
95
90
|
if (!endpoint) {
|
|
96
91
|
if (backend === 'supabase' && answers.supabaseUrl) {
|
|
97
|
-
endpoint = `${answers.supabaseUrl}/functions/v1/
|
|
92
|
+
endpoint = `${answers.supabaseUrl}/functions/v1/ai-chat`;
|
|
98
93
|
} else if (backend === 'api') {
|
|
99
|
-
endpoint = answers.apiBaseUrl ? `${answers.apiBaseUrl}/
|
|
94
|
+
endpoint = answers.apiBaseUrl ? `${answers.apiBaseUrl}/ai-chat` : 'YOUR_AI_ENDPOINT';
|
|
100
95
|
} else {
|
|
101
96
|
// firebase — use the region configured for this project
|
|
102
97
|
const projectId = answers.firebaseProjectId || 'YOUR_PROJECT_ID';
|
|
103
98
|
const region = answers.functionsRegion || 'us-central1';
|
|
104
|
-
endpoint = `https://${region}-${projectId}.cloudfunctions.net/
|
|
99
|
+
endpoint = `https://${region}-${projectId}.cloudfunctions.net/aiChat`;
|
|
105
100
|
}
|
|
106
101
|
}
|
|
107
|
-
dev.push(`--dart-define=
|
|
108
|
-
prod.push(`--dart-define=
|
|
102
|
+
dev.push(`--dart-define=AI_CHAT_ENDPOINT=${endpoint}`);
|
|
103
|
+
prod.push(`--dart-define=AI_CHAT_ENDPOINT=${endpoint}`);
|
|
109
104
|
}
|
|
110
105
|
|
|
111
106
|
return { dev, prod };
|
|
@@ -178,10 +173,10 @@ async function writeEnvExample(projectDir, modules, answers, language = 'en') {
|
|
|
178
173
|
if (t.revenuecatProd) lines.push(t.revenuecatProd);
|
|
179
174
|
lines.push(`RC_IOS_PROD_KEY=${(answers.rcIosProdKey || '').trim()}`);
|
|
180
175
|
lines.push(`RC_ANDROID_PROD_KEY=${(answers.rcAndroidProdKey || '').trim()}`);
|
|
181
|
-
if (answers.revenuecatWeb) {
|
|
182
|
-
lines.push(`RC_WEB_API_KEY=${answers.rcWebKey || 'YOUR_REVENUECAT_WEB_KEY'}`);
|
|
183
|
-
}
|
|
184
176
|
}
|
|
177
|
+
// NOTE: the Stripe module needs NO client-side env. Hosted Checkout + Customer
|
|
178
|
+
// Portal use only server-side secrets (STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRET),
|
|
179
|
+
// which live on the backend (Firebase/Supabase secrets), never in the app.
|
|
185
180
|
if (modules.includes('sentry')) {
|
|
186
181
|
lines.push('');
|
|
187
182
|
lines.push(t.sentry);
|
|
@@ -192,10 +187,10 @@ async function writeEnvExample(projectDir, modules, answers, language = 'en') {
|
|
|
192
187
|
lines.push(t.mixpanel);
|
|
193
188
|
lines.push(`MIXPANEL_TOKEN=${answers.mixpanelToken || 'YOUR_MIXPANEL_TOKEN'}`);
|
|
194
189
|
}
|
|
195
|
-
if (modules.includes('
|
|
190
|
+
if (modules.includes('ai_chat')) {
|
|
196
191
|
lines.push('');
|
|
197
|
-
lines.push(t.
|
|
198
|
-
lines.push(`
|
|
192
|
+
lines.push(t.aiChat);
|
|
193
|
+
lines.push(`AI_CHAT_ENDPOINT=${answers.aiChatEndpoint || 'YOUR_FUNCTION_URL'}`);
|
|
199
194
|
}
|
|
200
195
|
|
|
201
196
|
await fs.outputFile(path.join(projectDir, '.env.example'), lines.join('\n') + '\n', 'utf8');
|
|
@@ -263,15 +258,15 @@ async function cleanFirebaseJsonKitRefs(projectDir) {
|
|
|
263
258
|
}
|
|
264
259
|
|
|
265
260
|
/**
|
|
266
|
-
* Write
|
|
261
|
+
* Write environments.dart overrides for backend-specific config.
|
|
267
262
|
*
|
|
268
263
|
* @param {string} projectDir
|
|
269
264
|
* @param {'firebase'|'supabase'|'api'} backend
|
|
270
265
|
* @param {Record<string,string>} tokens
|
|
271
266
|
* @param {object} answers - supabaseUrl, supabaseAnonKey, apiBaseUrl
|
|
272
267
|
*/
|
|
273
|
-
async function
|
|
274
|
-
const envPath = path.join(projectDir, 'lib', '
|
|
268
|
+
async function writeEnvironmentsOverrides(projectDir, backend, tokens, answers) {
|
|
269
|
+
const envPath = path.join(projectDir, 'lib', 'environments.dart');
|
|
275
270
|
if (!(await fs.pathExists(envPath))) return;
|
|
276
271
|
|
|
277
272
|
let content = await fs.readFile(envPath, 'utf8');
|
|
@@ -313,8 +308,8 @@ async function writeEnvironnementsOverrides(projectDir, backend, tokens, answers
|
|
|
313
308
|
async function writeRouter(projectDir, modules, packageName, defaultPaywall = 'basic') {
|
|
314
309
|
const pkg = packageName;
|
|
315
310
|
const withFeedback = modules.includes('feedback');
|
|
316
|
-
const
|
|
317
|
-
const
|
|
311
|
+
const withAiChat = modules.includes('ai_chat');
|
|
312
|
+
const withLocalReminders = modules.includes('local_reminders');
|
|
318
313
|
const withOnboarding = modules.includes('onboarding');
|
|
319
314
|
const withRevenuecat = modules.includes('revenuecat');
|
|
320
315
|
const withAnalytics = modules.includes('analytics');
|
|
@@ -347,12 +342,8 @@ async function writeRouter(projectDir, modules, packageName, defaultPaywall = 'b
|
|
|
347
342
|
lines.push(`import 'package:${pkg}/features/home/home_components_page.dart';`);
|
|
348
343
|
lines.push(`import 'package:${pkg}/features/home/home_components_preview_page.dart';`);
|
|
349
344
|
lines.push(`import 'package:${pkg}/features/home/home_components_preview_registry.dart';`);
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
lines.push(`import 'package:${pkg}/features/llm_chat/llm_chat_page.dart';`);
|
|
353
|
-
}
|
|
354
|
-
if (withLocalNotifications) {
|
|
355
|
-
lines.push(`import 'package:${pkg}/features/local_reminder/ui/reminder_page.dart';`);
|
|
345
|
+
if (withLocalReminders) {
|
|
346
|
+
lines.push(`import 'package:${pkg}/features/local_reminders/ui/reminder_page.dart';`);
|
|
356
347
|
}
|
|
357
348
|
if (withOnboarding) {
|
|
358
349
|
lines.push(`import 'package:${pkg}/features/onboarding/ui/onboarding_page.dart';`);
|
|
@@ -369,8 +360,8 @@ async function writeRouter(projectDir, modules, packageName, defaultPaywall = 'b
|
|
|
369
360
|
lines.push(`import 'package:${pkg}/features/settings/ui/components/admin/admin_routes.dart';`);
|
|
370
361
|
lines.push(`import 'package:${pkg}/features/settings/ui/components/admin/send_push_notification_page.dart';`);
|
|
371
362
|
if (withRevenuecat) {
|
|
372
|
-
lines.push(`import 'package:${pkg}/features/
|
|
373
|
-
lines.push(`import 'package:${pkg}/features/
|
|
363
|
+
lines.push(`import 'package:${pkg}/features/subscriptions/ui/component/premium_page_factory.dart';`);
|
|
364
|
+
lines.push(`import 'package:${pkg}/features/subscriptions/ui/premium_page.dart';`);
|
|
374
365
|
}
|
|
375
366
|
lines.push(`import 'package:logger/logger.dart';`);
|
|
376
367
|
|
|
@@ -427,11 +418,6 @@ async function writeRouter(projectDir, modules, packageName, defaultPaywall = 'b
|
|
|
427
418
|
// full-screen, above the bottom bar, URL-addressable. Returning pops back to
|
|
428
419
|
// the tab with its menu intact.
|
|
429
420
|
lines.push(` GoRoute(`);
|
|
430
|
-
lines.push(` name: 'features',`);
|
|
431
|
-
lines.push(` path: '/features',`);
|
|
432
|
-
lines.push(` builder: (context, state) => const HomeFeaturesPage(),`);
|
|
433
|
-
lines.push(` ),`);
|
|
434
|
-
lines.push(` GoRoute(`);
|
|
435
421
|
lines.push(` name: 'design_system',`);
|
|
436
422
|
lines.push(` path: '/design-system',`);
|
|
437
423
|
lines.push(` builder: (context, state) => const DesignSystemPage(),`);
|
|
@@ -505,17 +491,8 @@ async function writeRouter(projectDir, modules, packageName, defaultPaywall = 'b
|
|
|
505
491
|
lines.push(` ),`);
|
|
506
492
|
}
|
|
507
493
|
|
|
508
|
-
// LLM Chat
|
|
509
|
-
if (withLlmChat) {
|
|
510
|
-
lines.push(` GoRoute(`);
|
|
511
|
-
lines.push(` name: 'assistant',`);
|
|
512
|
-
lines.push(` path: '/assistant',`);
|
|
513
|
-
lines.push(` builder: (context, state) => const LlmChatPage(),`);
|
|
514
|
-
lines.push(` ),`);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
494
|
// Local notifications reminder
|
|
518
|
-
if (
|
|
495
|
+
if (withLocalReminders) {
|
|
519
496
|
lines.push(` GoRoute(`);
|
|
520
497
|
lines.push(` name: 'reminder',`);
|
|
521
498
|
lines.push(` path: '/reminder',`);
|
|
@@ -610,34 +587,34 @@ async function writeRouter(projectDir, modules, packageName, defaultPaywall = 'b
|
|
|
610
587
|
*
|
|
611
588
|
* @param {string} projectDir
|
|
612
589
|
* @param {string[]} modules
|
|
613
|
-
* @param {object} [answers={}] - moduleAnswers (
|
|
590
|
+
* @param {object} [answers={}] - moduleAnswers (rcTestKey, stripe keys, etc.)
|
|
614
591
|
* @param {string} [language='en'] - User's CLI language (en, pt, es)
|
|
615
592
|
*/
|
|
616
593
|
async function writeFeaturesConfig(projectDir, modules, answers = {}, language = 'en') {
|
|
617
594
|
const withOnboarding = modules.includes('onboarding');
|
|
618
|
-
const
|
|
595
|
+
const withAiChat = modules.includes('ai_chat');
|
|
619
596
|
const withFeedback = modules.includes('feedback');
|
|
620
597
|
const withRevenuecat = modules.includes('revenuecat');
|
|
621
|
-
const
|
|
598
|
+
const withStripe = modules.includes('stripe');
|
|
599
|
+
const withLocalReminders = modules.includes('local_reminders');
|
|
622
600
|
const withWeb = modules.includes('web');
|
|
623
|
-
const revenuecatWeb = !!(modules.includes('revenuecat') && modules.includes('web') && answers.revenuecatWeb);
|
|
624
601
|
|
|
625
602
|
const f = getStrings(language).features;
|
|
626
603
|
const content = `${f.comment1}
|
|
627
604
|
${f.comment2}
|
|
628
605
|
// ignore_for_file: avoid_redundant_argument_values
|
|
629
606
|
const bool withOnboarding = ${withOnboarding};
|
|
630
|
-
const bool
|
|
607
|
+
const bool withAiChat = ${withAiChat};
|
|
631
608
|
const bool withFeedback = ${withFeedback};
|
|
632
609
|
const bool withRevenuecat = ${withRevenuecat};
|
|
633
|
-
|
|
610
|
+
// Stripe web subscriptions module (independent from RevenueCat mobile IAP).
|
|
611
|
+
const bool withStripe = ${withStripe};
|
|
612
|
+
const bool withLocalReminders = ${withLocalReminders};
|
|
634
613
|
${f.comment3}
|
|
635
614
|
${f.comment4}
|
|
636
615
|
${f.comment5}
|
|
637
616
|
${f.comment6}
|
|
638
617
|
const bool withWeb = ${withWeb};
|
|
639
|
-
${f.comment7}
|
|
640
|
-
const bool revenuecatWeb = ${revenuecatWeb};
|
|
641
618
|
`;
|
|
642
619
|
await fs.ensureDir(path.join(projectDir, 'lib', 'core', 'config'));
|
|
643
620
|
await fs.outputFile(
|
|
@@ -655,7 +632,6 @@ const bool revenuecatWeb = ${revenuecatWeb};
|
|
|
655
632
|
*/
|
|
656
633
|
async function writeKitSetup(projectDir, options) {
|
|
657
634
|
const { appName, bundleId, backend, modules = [], firebaseProjectId, supabaseUrl, supabaseAnonKey, moduleAnswers = {} } = options;
|
|
658
|
-
const revenuecatWeb = !!(modules.includes('revenuecat') && modules.includes('web') && moduleAnswers.revenuecatWeb);
|
|
659
635
|
// Booleans tracking which RC keys the user configured. We never persist key
|
|
660
636
|
// values to kit_setup.json — those live in .env (gitignored). These flags
|
|
661
637
|
// let `kasy doctor` warn about release readiness without re-reading .env.
|
|
@@ -672,12 +648,12 @@ async function writeKitSetup(projectDir, options) {
|
|
|
672
648
|
backendProvider: backend || 'firebase',
|
|
673
649
|
functionsRegion: moduleAnswers.functionsRegion || 'us-central1',
|
|
674
650
|
subscriptionModule: modules.includes('revenuecat'),
|
|
651
|
+
stripeModule: modules.includes('stripe'),
|
|
675
652
|
feedbackModule: modules.includes('feedback'),
|
|
676
653
|
useFirebaseAuth: true,
|
|
677
654
|
useFirebaseFirestore: backend === 'firebase',
|
|
678
655
|
storageProvider: backend === 'firebase' ? 'firebase' : backend === 'supabase' ? 'supabase' : 'api',
|
|
679
656
|
webCompat: modules.includes('web'),
|
|
680
|
-
revenuecatWeb,
|
|
681
657
|
...(revenuecatKeys ? { revenuecatKeys } : {}),
|
|
682
658
|
internationalization: true,
|
|
683
659
|
useSentry: modules.includes('sentry'),
|
|
@@ -910,7 +886,7 @@ async function writeMainDart(projectDir, backend, modules, packageName, options
|
|
|
910
886
|
lines.push(`import 'package:${pkg}/core/dev_inspector/dev_inspector.dart';`);
|
|
911
887
|
lines.push(`import 'package:${pkg}/core/theme/theme.dart';`);
|
|
912
888
|
lines.push(`import 'package:${pkg}/core/web_device_preview/web_device_preview.dart';`);
|
|
913
|
-
lines.push(`import 'package:${pkg}/
|
|
889
|
+
lines.push(`import 'package:${pkg}/environments.dart';`);
|
|
914
890
|
if (withFirebase) {
|
|
915
891
|
lines.push(`import 'package:${pkg}/firebase_options_dev.dart' as firebase_dev;`);
|
|
916
892
|
}
|
|
@@ -922,7 +898,7 @@ async function writeMainDart(projectDir, backend, modules, packageName, options
|
|
|
922
898
|
}
|
|
923
899
|
lines.push(`import 'package:${pkg}/features/notifications/repositories/notifications_repository.dart';`);
|
|
924
900
|
if (withRevenuecat) {
|
|
925
|
-
lines.push(`import 'package:${pkg}/features/
|
|
901
|
+
lines.push(`import 'package:${pkg}/features/subscriptions/repositories/subscription_repository.dart';`);
|
|
926
902
|
}
|
|
927
903
|
lines.push(`import 'package:${pkg}/router.dart';`);
|
|
928
904
|
if (withSentry) {
|
|
@@ -972,7 +948,9 @@ async function writeMainDart(projectDir, backend, modules, packageName, options
|
|
|
972
948
|
lines.push(` // initialize Supabase`);
|
|
973
949
|
lines.push(` await Supabase.initialize(`);
|
|
974
950
|
lines.push(` url: AppEnv.backendUrl,`);
|
|
975
|
-
|
|
951
|
+
// supabase_flutter ≥2.x: anonKey is deprecated in favor of publishableKey.
|
|
952
|
+
// Both feed the same effectiveKey, so the existing token value is unchanged.
|
|
953
|
+
lines.push(` publishableKey: AppEnv.supabaseToken,`);
|
|
976
954
|
lines.push(` );`);
|
|
977
955
|
lines.push('');
|
|
978
956
|
}
|
|
@@ -1245,14 +1223,12 @@ async function writeMainDart(projectDir, backend, modules, packageName, options
|
|
|
1245
1223
|
async function removeModuleDirs(projectDir, modules) {
|
|
1246
1224
|
const removable = [
|
|
1247
1225
|
{ module: 'feedback', dir: path.join('lib', 'features', 'feedbacks') },
|
|
1248
|
-
{ module: '
|
|
1226
|
+
{ module: 'ai_chat', dir: path.join('lib', 'features', 'ai_chat') },
|
|
1249
1227
|
{ module: 'onboarding',dir: path.join('lib', 'features', 'onboarding') },
|
|
1250
1228
|
// home_widgets/ imports home_widget package — remove when widget not selected
|
|
1251
1229
|
{ module: 'widget', dir: path.join('lib', 'core', 'home_widgets') },
|
|
1252
|
-
//
|
|
1253
|
-
{ module: '
|
|
1254
|
-
// local_reminder/ uses flutter_timezone/timezone — remove when local_notifications not selected
|
|
1255
|
-
{ module: 'local_notifications', dir: path.join('lib', 'features', 'local_reminder') },
|
|
1230
|
+
// local_reminders/ uses flutter_timezone/timezone — remove when local_reminders not selected
|
|
1231
|
+
{ module: 'local_reminders', dir: path.join('lib', 'features', 'local_reminders') },
|
|
1256
1232
|
];
|
|
1257
1233
|
|
|
1258
1234
|
for (const { module, dir } of removable) {
|
|
@@ -1263,6 +1239,17 @@ async function removeModuleDirs(projectDir, modules) {
|
|
|
1263
1239
|
}
|
|
1264
1240
|
}
|
|
1265
1241
|
}
|
|
1242
|
+
|
|
1243
|
+
// subscription/ is the payment CORE shared by RevenueCat (mobile) and Stripe
|
|
1244
|
+
// (web). Keep it when EITHER module is selected; remove only when neither is.
|
|
1245
|
+
// The RevenueCat-only files (purchases_flutter) are stripped separately by
|
|
1246
|
+
// writeStripeOnlySubscription when Stripe is selected without RevenueCat.
|
|
1247
|
+
if (!modules.includes('revenuecat') && !modules.includes('stripe')) {
|
|
1248
|
+
const subDir = path.join(projectDir, 'lib', 'features', 'subscriptions');
|
|
1249
|
+
if (await fs.pathExists(subDir)) {
|
|
1250
|
+
await fs.remove(subDir);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1266
1253
|
}
|
|
1267
1254
|
|
|
1268
1255
|
/**
|
|
@@ -1674,7 +1661,7 @@ sealed class Subscription with _$Subscription {
|
|
|
1674
1661
|
// here) for source-compat with the bundled tests. ignore_for_file stops
|
|
1675
1662
|
// `dart fix` from stripping them via avoid_unused_constructor_parameters.
|
|
1676
1663
|
await fs.outputFile(
|
|
1677
|
-
path.join(projectDir, 'lib', 'features', '
|
|
1664
|
+
path.join(projectDir, 'lib', 'features', 'subscriptions', 'repositories', 'subscription_repository.dart'),
|
|
1678
1665
|
`// ignore_for_file: avoid_unused_constructor_parameters
|
|
1679
1666
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
1680
1667
|
import 'package:${pkg}/core/data/models/subscription.dart';
|
|
@@ -1721,7 +1708,7 @@ class UserCancelledPurchaseException implements Exception {}
|
|
|
1721
1708
|
|
|
1722
1709
|
// 2. No-op maybeshow_premium.dart (used by home_page — must implement MaybeShowWithRef)
|
|
1723
1710
|
await fs.outputFile(
|
|
1724
|
-
path.join(projectDir, 'lib', 'features', '
|
|
1711
|
+
path.join(projectDir, 'lib', 'features', 'subscriptions', 'shared', 'maybeshow_premium.dart'),
|
|
1725
1712
|
`import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
1726
1713
|
import 'package:${pkg}/core/states/components/maybeshow_component.dart';
|
|
1727
1714
|
import 'package:${pkg}/core/states/models/event_model.dart';
|
|
@@ -1736,7 +1723,7 @@ class MaybeShowPremiumPage implements MaybeShowWithRef {
|
|
|
1736
1723
|
|
|
1737
1724
|
// 3. No-op premium_page.dart (used by onboarding_page with args: PremiumPageArgs(redirect:))
|
|
1738
1725
|
await fs.outputFile(
|
|
1739
|
-
path.join(projectDir, 'lib', 'features', '
|
|
1726
|
+
path.join(projectDir, 'lib', 'features', 'subscriptions', 'ui', 'premium_page.dart'),
|
|
1740
1727
|
`import 'package:flutter/material.dart';
|
|
1741
1728
|
// No-op premium page. Run: kasy add revenuecat to activate.
|
|
1742
1729
|
class PremiumPage extends StatelessWidget {
|
|
@@ -1759,7 +1746,7 @@ class PremiumPageArgs {
|
|
|
1759
1746
|
// Mirror the constants declared in Firebase/.../premium_page_factory.dart so that
|
|
1760
1747
|
// admin_routes.dart compiles even without revenuecat selected.
|
|
1761
1748
|
await fs.outputFile(
|
|
1762
|
-
path.join(projectDir, 'lib', 'features', '
|
|
1749
|
+
path.join(projectDir, 'lib', 'features', 'subscriptions', 'ui', 'component', 'premium_page_factory.dart'),
|
|
1763
1750
|
`// No-op paywall factory. Run: kasy add revenuecat to activate.
|
|
1764
1751
|
enum PaywallFactory { basic, basicRow, minimal, withSwitch }
|
|
1765
1752
|
`,
|
|
@@ -1768,7 +1755,7 @@ enum PaywallFactory { basic, basicRow, minimal, withSwitch }
|
|
|
1768
1755
|
|
|
1769
1756
|
// 5. No-op subscription_entity.dart (used by test_utils, fake_subscription_api)
|
|
1770
1757
|
await fs.outputFile(
|
|
1771
|
-
path.join(projectDir, 'lib', 'features', '
|
|
1758
|
+
path.join(projectDir, 'lib', 'features', 'subscriptions', 'api', 'entities', 'subscription_entity.dart'),
|
|
1772
1759
|
`// ignore_for_file: constant_identifier_names
|
|
1773
1760
|
// No-op subscription entity. Run: kasy add revenuecat to activate.
|
|
1774
1761
|
enum SubscriptionStatus { ACTIVE, PAUSED, EXPIRED, LIFETIME, CANCELLED }
|
|
@@ -1793,9 +1780,9 @@ class SubscriptionEntity {
|
|
|
1793
1780
|
|
|
1794
1781
|
// 6. No-op subscription_api.dart (provider + abstract class used by test_utils and fake)
|
|
1795
1782
|
await fs.outputFile(
|
|
1796
|
-
path.join(projectDir, 'lib', 'features', '
|
|
1783
|
+
path.join(projectDir, 'lib', 'features', 'subscriptions', 'api', 'subscription_api.dart'),
|
|
1797
1784
|
`import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
1798
|
-
import 'package:${pkg}/features/
|
|
1785
|
+
import 'package:${pkg}/features/subscriptions/api/entities/subscription_entity.dart';
|
|
1799
1786
|
// No-op subscription API. Run: kasy add revenuecat to activate.
|
|
1800
1787
|
final subscriptionApiProvider = Provider<SubscriptionApi>(
|
|
1801
1788
|
(ref) => _NoOpSubscriptionApi(),
|
|
@@ -1815,7 +1802,7 @@ class _NoOpSubscriptionApi implements SubscriptionApi {
|
|
|
1815
1802
|
|
|
1816
1803
|
// 7. No-op inapp_subscription_api.dart (provider + class used by test_utils and fake)
|
|
1817
1804
|
await fs.outputFile(
|
|
1818
|
-
path.join(projectDir, 'lib', 'features', '
|
|
1805
|
+
path.join(projectDir, 'lib', 'features', 'subscriptions', 'api', 'inapp_subscription_api.dart'),
|
|
1819
1806
|
`import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
1820
1807
|
import 'package:${pkg}/core/data/models/subscription.dart';
|
|
1821
1808
|
// No-op in-app subscription API. Run: kasy add revenuecat to activate.
|
|
@@ -1841,17 +1828,17 @@ class RevenueCatPaymentApi {
|
|
|
1841
1828
|
'utf8',
|
|
1842
1829
|
);
|
|
1843
1830
|
|
|
1844
|
-
// 8. Remove test/features/
|
|
1845
|
-
const testSubscriptionDir = path.join(projectDir, 'test', 'features', '
|
|
1831
|
+
// 8. Remove test/features/subscriptions/ entirely (imports purchases_flutter and RevenueCat types)
|
|
1832
|
+
const testSubscriptionDir = path.join(projectDir, 'test', 'features', 'subscriptions');
|
|
1846
1833
|
if (await fs.pathExists(testSubscriptionDir)) {
|
|
1847
1834
|
await fs.remove(testSubscriptionDir);
|
|
1848
1835
|
}
|
|
1849
1836
|
|
|
1850
1837
|
// 9. Restore fake_subscription_api.dart with currentFake setter (required by test_utils.dart)
|
|
1851
1838
|
await fs.outputFile(
|
|
1852
|
-
path.join(projectDir, 'test', 'features', '
|
|
1853
|
-
`import 'package:${pkg}/features/
|
|
1854
|
-
import 'package:${pkg}/features/
|
|
1839
|
+
path.join(projectDir, 'test', 'features', 'subscriptions', 'api', 'fake_subscription_api.dart'),
|
|
1840
|
+
`import 'package:${pkg}/features/subscriptions/api/entities/subscription_entity.dart';
|
|
1841
|
+
import 'package:${pkg}/features/subscriptions/api/subscription_api.dart';
|
|
1855
1842
|
// No-op subscription API fake. Run: kasy add revenuecat to activate.
|
|
1856
1843
|
class SubscriptionApiFake implements SubscriptionApi {
|
|
1857
1844
|
SubscriptionEntity? currentFake;
|
|
@@ -1865,8 +1852,8 @@ class SubscriptionApiFake implements SubscriptionApi {
|
|
|
1865
1852
|
|
|
1866
1853
|
// 10. Restore fake_inapp_subscription_api.dart without purchases_flutter dependency
|
|
1867
1854
|
await fs.outputFile(
|
|
1868
|
-
path.join(projectDir, 'test', 'features', '
|
|
1869
|
-
`import 'package:${pkg}/features/
|
|
1855
|
+
path.join(projectDir, 'test', 'features', 'subscriptions', 'api', 'fake_inapp_subscription_api.dart'),
|
|
1856
|
+
`import 'package:${pkg}/features/subscriptions/api/inapp_subscription_api.dart';
|
|
1870
1857
|
// No-op in-app subscription API fake. Run: kasy add revenuecat to activate.
|
|
1871
1858
|
class InAppSubscriptionApiFake extends RevenueCatPaymentApi {}
|
|
1872
1859
|
`,
|
|
@@ -1874,6 +1861,125 @@ class InAppSubscriptionApiFake extends RevenueCatPaymentApi {}
|
|
|
1874
1861
|
);
|
|
1875
1862
|
}
|
|
1876
1863
|
|
|
1864
|
+
/**
|
|
1865
|
+
* Stripe-without-RevenueCat: keep the subscription CORE but strip the
|
|
1866
|
+
* RevenueCat (purchases_flutter) files so the app compiles without the
|
|
1867
|
+
* RevenueCat SDK. Called when the Stripe module is selected and RevenueCat is not.
|
|
1868
|
+
*
|
|
1869
|
+
* @param {string} projectDir
|
|
1870
|
+
* @param {string} packageName
|
|
1871
|
+
*/
|
|
1872
|
+
async function writeStripeOnlySubscription(projectDir, packageName) {
|
|
1873
|
+
const pkg = packageName;
|
|
1874
|
+
const subApiDir = path.join(projectDir, 'lib', 'features', 'subscriptions', 'api');
|
|
1875
|
+
|
|
1876
|
+
// 1. Remove the RevenueCat-only payment files (they import purchases_flutter).
|
|
1877
|
+
for (const f of ['inapp_subscription_api.dart', 'revenuecat_product.dart']) {
|
|
1878
|
+
const p = path.join(subApiDir, f);
|
|
1879
|
+
if (await fs.pathExists(p)) await fs.remove(p);
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
// 2. Rewrite the injection provider to a Stripe-only version (no RevenueCat import).
|
|
1883
|
+
await fs.outputFile(
|
|
1884
|
+
path.join(subApiDir, 'subscription_payment_api_provider.dart'),
|
|
1885
|
+
`import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
1886
|
+
import 'package:${pkg}/features/subscriptions/api/stripe_backend_api.dart';
|
|
1887
|
+
import 'package:${pkg}/features/subscriptions/api/stripe_payment_api.dart';
|
|
1888
|
+
import 'package:${pkg}/features/subscriptions/api/subscription_payment_api.dart';
|
|
1889
|
+
|
|
1890
|
+
/// Stripe-only subscription provider (web payments). Generated by the CLI for a
|
|
1891
|
+
/// project that enabled the Stripe module without RevenueCat, so it never
|
|
1892
|
+
/// references the RevenueCat SDK (purchases_flutter).
|
|
1893
|
+
final inAppSubscriptionApiProvider = Provider<SubscriptionPaymentApi>((ref) {
|
|
1894
|
+
return StripePaymentApi(backend: ref.read(stripeBackendApiProvider));
|
|
1895
|
+
});
|
|
1896
|
+
`,
|
|
1897
|
+
'utf8',
|
|
1898
|
+
);
|
|
1899
|
+
|
|
1900
|
+
// 3. Strip the RevenueCat device-id calls from tracking_api.dart when the
|
|
1901
|
+
// Facebook module kept the real file (it imports purchases_flutter).
|
|
1902
|
+
const trackingFile = path.join(projectDir, 'lib', 'core', 'data', 'api', 'tracking_api.dart');
|
|
1903
|
+
if (await fs.pathExists(trackingFile)) {
|
|
1904
|
+
let tracking = await fs.readFile(trackingFile, 'utf8');
|
|
1905
|
+
if (tracking.includes('purchases_flutter')) {
|
|
1906
|
+
tracking = tracking
|
|
1907
|
+
.replace("import 'package:purchases_flutter/purchases_flutter.dart';\n", '')
|
|
1908
|
+
.replace(/\n?[ \t]*\/\/ collect identifiers for REVENUECAT\n[ \t]*await Purchases\.collectDeviceIdentifiers\(\);/, '')
|
|
1909
|
+
.replace(
|
|
1910
|
+
/[ \t]*if \(userAnonId != null\) \{\n[ \t]*await Purchases\.setFBAnonymousID\(userAnonId\);\n[ \t]*\}/,
|
|
1911
|
+
' // RevenueCat device-id sync removed (no RevenueCat module).',
|
|
1912
|
+
);
|
|
1913
|
+
await fs.writeFile(trackingFile, tracking, 'utf8');
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
// 4. Tests: drop the RevenueCat-specific files and replace the in-app fake
|
|
1918
|
+
// with a no-op implementing the payment interface (no purchases_flutter).
|
|
1919
|
+
const testApiDir = path.join(projectDir, 'test', 'features', 'subscriptions', 'api');
|
|
1920
|
+
const fakeRcProduct = path.join(testApiDir, 'fake_revenuecat_product.dart');
|
|
1921
|
+
if (await fs.pathExists(fakeRcProduct)) await fs.remove(fakeRcProduct);
|
|
1922
|
+
const pageTest = path.join(projectDir, 'test', 'features', 'subscriptions', 'subscription_page_test.dart');
|
|
1923
|
+
if (await fs.pathExists(pageTest)) await fs.remove(pageTest);
|
|
1924
|
+
|
|
1925
|
+
if (await fs.pathExists(testApiDir)) {
|
|
1926
|
+
await fs.outputFile(
|
|
1927
|
+
path.join(testApiDir, 'fake_inapp_subscription_api.dart'),
|
|
1928
|
+
`import 'package:${pkg}/core/data/models/entitlement.dart';
|
|
1929
|
+
import 'package:${pkg}/core/data/models/subscription.dart';
|
|
1930
|
+
import 'package:${pkg}/features/subscriptions/api/entities/subscription_entity.dart';
|
|
1931
|
+
import 'package:${pkg}/features/subscriptions/api/subscription_payment_api.dart';
|
|
1932
|
+
|
|
1933
|
+
/// No-op payment API fake for a Stripe-only project (no RevenueCat SDK).
|
|
1934
|
+
/// Implements [SubscriptionPaymentApi] so the shared tests can override
|
|
1935
|
+
/// inAppSubscriptionApiProvider without depending on purchases_flutter.
|
|
1936
|
+
class InAppSubscriptionApiFake implements SubscriptionPaymentApi {
|
|
1937
|
+
String? userId;
|
|
1938
|
+
final List<SubscriptionProduct> activeSubscriptions = [];
|
|
1939
|
+
|
|
1940
|
+
@override
|
|
1941
|
+
Future<void> init() async {}
|
|
1942
|
+
|
|
1943
|
+
@override
|
|
1944
|
+
Future<void> initUser(String userId) async {
|
|
1945
|
+
this.userId = userId;
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
@override
|
|
1949
|
+
Future<void> disconnectUser() async {}
|
|
1950
|
+
|
|
1951
|
+
@override
|
|
1952
|
+
Future<List<SubscriptionProduct>> getOffers(String? offerId) async => [];
|
|
1953
|
+
|
|
1954
|
+
@override
|
|
1955
|
+
Future<void> purchaseProduct(SubscriptionProduct product) async {
|
|
1956
|
+
activeSubscriptions.add(product);
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
@override
|
|
1960
|
+
Future<void> unsubscribe(SubscriptionStore? origin) async {}
|
|
1961
|
+
|
|
1962
|
+
@override
|
|
1963
|
+
Future<void> restorePurchase() async {}
|
|
1964
|
+
|
|
1965
|
+
@override
|
|
1966
|
+
Future<List<Entitlement>> getPermissions() async => [];
|
|
1967
|
+
|
|
1968
|
+
@override
|
|
1969
|
+
Future<List<Entitlement>?> getEntitlements() async => [];
|
|
1970
|
+
|
|
1971
|
+
@override
|
|
1972
|
+
Future<SubscriptionProduct?> getFromProductId(String productId) async => null;
|
|
1973
|
+
|
|
1974
|
+
@override
|
|
1975
|
+
Future<void> presentCodeRedemptionSheet() async {}
|
|
1976
|
+
}
|
|
1977
|
+
`,
|
|
1978
|
+
'utf8',
|
|
1979
|
+
);
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1877
1983
|
/**
|
|
1878
1984
|
* Remove DEVELOPMENT_TEAM entries from the generated iOS project.pbxproj.
|
|
1879
1985
|
* Clients use their own Apple team — leaving the internal team ID would cause
|
|
@@ -1933,7 +2039,7 @@ module.exports = {
|
|
|
1933
2039
|
writeEnvFileIfMissing,
|
|
1934
2040
|
writeFirebaserc,
|
|
1935
2041
|
cleanFirebaseJsonKitRefs,
|
|
1936
|
-
|
|
2042
|
+
writeEnvironmentsOverrides,
|
|
1937
2043
|
writeFeaturesConfig,
|
|
1938
2044
|
writeKitSetup,
|
|
1939
2045
|
writeMakefile,
|
|
@@ -1948,6 +2054,7 @@ module.exports = {
|
|
|
1948
2054
|
patchLanguageSwitcherNoWidget,
|
|
1949
2055
|
writeNoOpFeatureRequestRepository,
|
|
1950
2056
|
writeNoOpSubscriptionStubs,
|
|
2057
|
+
writeStripeOnlySubscription,
|
|
1951
2058
|
writeNoOpSentryUsages,
|
|
1952
2059
|
stripPubspecDeps,
|
|
1953
2060
|
addPubspecDep,
|