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
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sorts Dart `import`/`export`/`part` directives to satisfy the
|
|
5
|
+
* `directives_ordering` lint, which otherwise fires across generated projects
|
|
6
|
+
* because renaming the `kasy_kit` package to the project's name breaks the
|
|
7
|
+
* source's alphabetical order.
|
|
8
|
+
*
|
|
9
|
+
* Order:
|
|
10
|
+
* 1. dart: imports
|
|
11
|
+
* 2. package: imports (alphabetical)
|
|
12
|
+
* 3. relative imports (alphabetical)
|
|
13
|
+
* 4. part / part of (kept after imports)
|
|
14
|
+
*
|
|
15
|
+
* Comments above the first directive (license / ignore_for_file) and the full
|
|
16
|
+
* directive line (with `as`/`show`/`hide`/conditional `if`) are preserved.
|
|
17
|
+
* Generated files (.g.dart / .freezed.dart) are skipped.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
|
|
23
|
+
const DIRECTIVE_RE = /^(import|export|part)\s+['"]([^'"]+)['"](.*?);?\s*$/;
|
|
24
|
+
|
|
25
|
+
// Groups, in output order:
|
|
26
|
+
// 0 import dart: 1 import package: 2 import relative
|
|
27
|
+
// 3 export dart: 4 export package: 5 export relative
|
|
28
|
+
// 6 part / part of
|
|
29
|
+
const OTHER_GROUP = 7;
|
|
30
|
+
|
|
31
|
+
function classify(line) {
|
|
32
|
+
const m = line.match(DIRECTIVE_RE);
|
|
33
|
+
if (!m) return OTHER_GROUP;
|
|
34
|
+
const keyword = m[1];
|
|
35
|
+
const uri = m[2];
|
|
36
|
+
if (keyword === 'part') return 6;
|
|
37
|
+
const base = uri.startsWith('dart:') ? 0 : uri.startsWith('package:') ? 1 : 2;
|
|
38
|
+
return keyword === 'export' ? base + 3 : base;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function sortKey(line) {
|
|
42
|
+
const m = line.match(DIRECTIVE_RE);
|
|
43
|
+
return m ? m[2] : '';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const DIRECTIVE_START_RE = /^(import|export|part)\b/;
|
|
47
|
+
|
|
48
|
+
function isHeaderComment(trimmed) {
|
|
49
|
+
return (
|
|
50
|
+
trimmed.startsWith('//') ||
|
|
51
|
+
trimmed.startsWith('/*') ||
|
|
52
|
+
trimmed.startsWith('*') ||
|
|
53
|
+
trimmed.startsWith('@')
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ASCII / code-unit ordering matches the Dart analyzer (where '/' (0x2F) sorts
|
|
58
|
+
// before '_' (0x5F), so 'flutter/material' < 'flutter_riverpod'). localeCompare
|
|
59
|
+
// gets this wrong. A directive may span multiple physical lines (e.g.
|
|
60
|
+
// `import '...'` then ` as foo;`, or a conditional `import '...' if (...) '...';`),
|
|
61
|
+
// so we accumulate lines until one ends with ';' and sort each unit by its first URI.
|
|
62
|
+
function processContent(original) {
|
|
63
|
+
const lines = original.split('\n');
|
|
64
|
+
|
|
65
|
+
// Find the first directive; bail if real code appears before any directive.
|
|
66
|
+
let firstDir = -1;
|
|
67
|
+
for (let k = 0; k < lines.length; k++) {
|
|
68
|
+
const t = lines[k].trim();
|
|
69
|
+
if (DIRECTIVE_START_RE.test(t)) {
|
|
70
|
+
firstDir = k;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
if (t !== '' && !isHeaderComment(t)) break;
|
|
74
|
+
}
|
|
75
|
+
if (firstDir === -1) return { changed: false, content: original };
|
|
76
|
+
|
|
77
|
+
const prefix = lines.slice(0, firstDir); // license / ignore_for_file — kept verbatim
|
|
78
|
+
|
|
79
|
+
// Parse directive units. A unit carries any comment lines directly above it
|
|
80
|
+
// (e.g. `// ignore: depend_on_referenced_packages`) so the comment travels
|
|
81
|
+
// with its import when reordered. A directive may also span multiple physical
|
|
82
|
+
// lines until one ends with ';'.
|
|
83
|
+
let i = firstDir;
|
|
84
|
+
const units = [];
|
|
85
|
+
let pending = [];
|
|
86
|
+
while (i < lines.length) {
|
|
87
|
+
const t = lines[i].trim();
|
|
88
|
+
if (t === '') {
|
|
89
|
+
i++;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (isHeaderComment(t)) {
|
|
93
|
+
pending.push(lines[i]);
|
|
94
|
+
i++;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (!DIRECTIVE_START_RE.test(t)) break; // first real code
|
|
98
|
+
const dir = [...pending, lines[i]];
|
|
99
|
+
pending = [];
|
|
100
|
+
while (!lines[i].trim().endsWith(';') && i + 1 < lines.length) {
|
|
101
|
+
i++;
|
|
102
|
+
dir.push(lines[i]);
|
|
103
|
+
}
|
|
104
|
+
i++;
|
|
105
|
+
const dirLine = dir.find((l) => DIRECTIVE_START_RE.test(l.trim())).trim();
|
|
106
|
+
units.push({ group: classify(dirLine), key: sortKey(dirLine), lines: dir });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Any comment lines that weren't attached to an import belong to the body.
|
|
110
|
+
const bodyLines = [...pending, ...lines.slice(i)];
|
|
111
|
+
|
|
112
|
+
units.sort((a, b) =>
|
|
113
|
+
a.group !== b.group
|
|
114
|
+
? a.group - b.group
|
|
115
|
+
: a.key < b.key
|
|
116
|
+
? -1
|
|
117
|
+
: a.key > b.key
|
|
118
|
+
? 1
|
|
119
|
+
: 0,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// Rebuild with a blank line between distinct groups.
|
|
123
|
+
const rebuilt = [];
|
|
124
|
+
let lastGroup = -1;
|
|
125
|
+
for (const u of units) {
|
|
126
|
+
if (lastGroup !== -1 && u.group !== lastGroup) rebuilt.push('');
|
|
127
|
+
rebuilt.push(...u.lines);
|
|
128
|
+
lastGroup = u.group;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const out = [...prefix, ...rebuilt];
|
|
132
|
+
if (bodyLines.length && bodyLines[0].trim() !== '') out.push('');
|
|
133
|
+
out.push(...bodyLines);
|
|
134
|
+
|
|
135
|
+
const newContent = out.join('\n');
|
|
136
|
+
if (newContent === original) return { changed: false, content: original };
|
|
137
|
+
return { changed: true, content: newContent };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function walkDartFiles(dir) {
|
|
141
|
+
const out = [];
|
|
142
|
+
let entries;
|
|
143
|
+
try {
|
|
144
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
145
|
+
} catch {
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
for (const entry of entries) {
|
|
149
|
+
const full = path.join(dir, entry.name);
|
|
150
|
+
if (entry.isDirectory()) {
|
|
151
|
+
if (['build', '.dart_tool', 'node_modules', '.git'].includes(entry.name)) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
out.push(...walkDartFiles(full));
|
|
155
|
+
} else if (
|
|
156
|
+
entry.isFile() &&
|
|
157
|
+
entry.name.endsWith('.dart') &&
|
|
158
|
+
!entry.name.endsWith('.g.dart') &&
|
|
159
|
+
!entry.name.endsWith('.freezed.dart')
|
|
160
|
+
) {
|
|
161
|
+
out.push(full);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Sorts directives in every .dart file under the given directories (in place).
|
|
169
|
+
* Returns the number of files changed. Never throws on a single bad file.
|
|
170
|
+
*/
|
|
171
|
+
function sortImportsInDirs(dirs) {
|
|
172
|
+
let changed = 0;
|
|
173
|
+
for (const dir of dirs) {
|
|
174
|
+
if (!fs.existsSync(dir)) continue;
|
|
175
|
+
for (const file of walkDartFiles(dir)) {
|
|
176
|
+
try {
|
|
177
|
+
const original = fs.readFileSync(file, 'utf8');
|
|
178
|
+
const result = processContent(original);
|
|
179
|
+
if (result.changed) {
|
|
180
|
+
fs.writeFileSync(file, result.content, 'utf8');
|
|
181
|
+
changed++;
|
|
182
|
+
}
|
|
183
|
+
} catch {
|
|
184
|
+
// skip unreadable/odd files — sorting is best-effort cosmetics
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return changed;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
module.exports = { sortImportsInDirs, processContent };
|
|
@@ -37,7 +37,7 @@ const TEMPLATE_STRINGS = {
|
|
|
37
37
|
revenuecatProd: '# Production keys — auto-used on physical devices',
|
|
38
38
|
sentry: '# Sentry (prod only)',
|
|
39
39
|
mixpanel: '# Mixpanel',
|
|
40
|
-
|
|
40
|
+
aiChat: '# AI Chat — Cloud/Edge Function endpoint (API key stays on the server, not here)',
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
43
|
pt: {
|
|
@@ -71,7 +71,7 @@ const TEMPLATE_STRINGS = {
|
|
|
71
71
|
revenuecatProd: '# Chaves de produção — usadas automaticamente em dispositivo físico',
|
|
72
72
|
sentry: '# Sentry (apenas prod)',
|
|
73
73
|
mixpanel: '# Mixpanel',
|
|
74
|
-
|
|
74
|
+
aiChat: '# AI Chat — endpoint da Cloud/Edge Function (a chave de API fica no servidor, não aqui)',
|
|
75
75
|
},
|
|
76
76
|
},
|
|
77
77
|
es: {
|
|
@@ -105,7 +105,7 @@ const TEMPLATE_STRINGS = {
|
|
|
105
105
|
revenuecatProd: '# Claves de producción — se usan automáticamente en dispositivo físico',
|
|
106
106
|
sentry: '# Sentry (solo prod)',
|
|
107
107
|
mixpanel: '# Mixpanel',
|
|
108
|
-
|
|
108
|
+
aiChat: '# AI Chat — endpoint de Cloud/Edge Function (la clave de API queda en el servidor, no aquí)',
|
|
109
109
|
},
|
|
110
110
|
},
|
|
111
111
|
};
|
package/lib/utils/checks.js
CHANGED
|
@@ -5,12 +5,13 @@ const ui = require('./ui');
|
|
|
5
5
|
const { createTranslator, detectDefaultLanguage } = require('./i18n');
|
|
6
6
|
const { augmentedEnv, pubCacheBin } = require('./env-tools');
|
|
7
7
|
const { promptOpenBrowser } = require('./browser');
|
|
8
|
+
const { installFlutterWindows } = require('./flutter-install');
|
|
8
9
|
|
|
9
10
|
const execAsync = promisify(exec);
|
|
10
11
|
|
|
11
|
-
// Timeout
|
|
12
|
+
// Timeout to check whether a tool is installed (15 s is more than enough)
|
|
12
13
|
const TOOL_CHECK_TIMEOUT = 15_000;
|
|
13
|
-
// Timeout
|
|
14
|
+
// Timeout for automatic tool installation (5 min)
|
|
14
15
|
const INSTALL_TIMEOUT = 300_000;
|
|
15
16
|
const MAX_BUFFER = 50 * 1024 * 1024;
|
|
16
17
|
|
|
@@ -66,6 +67,12 @@ const BASE_CHECKS = [
|
|
|
66
67
|
minVersion: MIN_FLUTTER_VERSION,
|
|
67
68
|
installGuide: () => getInstallGuide('flutter'),
|
|
68
69
|
confirmInstall: true,
|
|
70
|
+
// Windows has no clean winget path for Flutter, so we run a custom installer
|
|
71
|
+
// (download SDK zip + Git) instead of a package-manager command. macOS/Linux
|
|
72
|
+
// keep using installGuide().cmd (brew). See flutter-install.js.
|
|
73
|
+
installFn: process.platform === 'win32' ? installFlutterWindows : null,
|
|
74
|
+
installFnDescKey: 'checks.install.flutterWinDesc',
|
|
75
|
+
installFnNoteKey: 'checks.install.flutterWinNote',
|
|
69
76
|
},
|
|
70
77
|
{
|
|
71
78
|
name: 'Dart SDK',
|
|
@@ -268,16 +275,25 @@ async function recoverCheckInteractively(check, t) {
|
|
|
268
275
|
// The step list already flagged this tool as missing; go straight to fixing it.
|
|
269
276
|
const guide = typeof check.installGuide === 'function' ? check.installGuide() : null;
|
|
270
277
|
|
|
271
|
-
// 1) Offer auto-install for heavy tools
|
|
272
|
-
|
|
278
|
+
// 1) Offer auto-install for heavy tools. Most use a package-manager command
|
|
279
|
+
// (brew/winget); Flutter on Windows uses a custom installer (check.installFn)
|
|
280
|
+
// because winget ships no stable Flutter package.
|
|
281
|
+
if (check.confirmInstall && (check.installFn || (guide && guide.cmd))) {
|
|
282
|
+
const cmdLabel = check.installFn
|
|
283
|
+
? (check.installFnDescKey ? t(check.installFnDescKey) : check.name)
|
|
284
|
+
: guide.cmd;
|
|
273
285
|
const doInstall = await ui.confirm({
|
|
274
|
-
message: t('checks.install.confirm', { name: check.name, cmd:
|
|
286
|
+
message: t('checks.install.confirm', { name: check.name, cmd: cmdLabel }),
|
|
275
287
|
initialValue: true,
|
|
276
288
|
});
|
|
277
289
|
if (doInstall) {
|
|
290
|
+
// Heads-up for the custom installer: it's a big download and may pop a UAC.
|
|
291
|
+
if (check.installFn && check.installFnNoteKey) ui.log.info(t(check.installFnNoteKey));
|
|
278
292
|
const spinner = ui.timedSpinner();
|
|
279
293
|
spinner.start(t('checks.install.running', { name: check.name }));
|
|
280
|
-
const installed =
|
|
294
|
+
const installed = check.installFn
|
|
295
|
+
? await check.installFn({})
|
|
296
|
+
: await execTool(guide.cmd, INSTALL_TIMEOUT);
|
|
281
297
|
spinner.stop(t('checks.install.running', { name: check.name }));
|
|
282
298
|
if (installed.ok && (await revalidate(check, t))) return true;
|
|
283
299
|
ui.log.warn(t('checks.install.failedManual', { name: check.name }));
|
package/lib/utils/env-tools.js
CHANGED
|
@@ -105,6 +105,13 @@ function extraToolDirs() {
|
|
|
105
105
|
process.env.LOCALAPPDATA && path.win32.join(process.env.LOCALAPPDATA, 'Google', 'Cloud SDK', 'google-cloud-sdk', 'bin'),
|
|
106
106
|
process.env.ProgramFiles && path.win32.join(process.env.ProgramFiles, 'Google', 'Cloud SDK', 'google-cloud-sdk', 'bin'),
|
|
107
107
|
process.env['ProgramFiles(x86)'] && path.win32.join(process.env['ProgramFiles(x86)'], 'Google', 'Cloud SDK', 'google-cloud-sdk', 'bin'),
|
|
108
|
+
// Flutter SDK auto-installed by `kasy new` (archive unzipped into %LOCALAPPDATA%\flutter).
|
|
109
|
+
// Putting its bin here lets the same run's flutter pub get / build_runner /
|
|
110
|
+
// flutterfire find both `flutter` and `dart` without a new terminal.
|
|
111
|
+
process.env.LOCALAPPDATA && path.win32.join(process.env.LOCALAPPDATA, 'flutter', 'bin'),
|
|
112
|
+
// Git (a Flutter prerequisite) installed via winget Git.Git — default locations.
|
|
113
|
+
process.env.ProgramFiles && path.win32.join(process.env.ProgramFiles, 'Git', 'cmd'),
|
|
114
|
+
process.env.LOCALAPPDATA && path.win32.join(process.env.LOCALAPPDATA, 'Programs', 'Git', 'cmd'),
|
|
108
115
|
].filter(Boolean);
|
|
109
116
|
return candidates.filter((dir) => fs.existsSync(dir));
|
|
110
117
|
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-install the Flutter SDK on Windows, the only OS where there is no clean
|
|
3
|
+
* package-manager path (winget ships no stable Flutter package — the official
|
|
4
|
+
* route is the SDK archive). We mirror what the Flutter docs tell a human to do,
|
|
5
|
+
* but do it for the user so `kasy new` can prepare a bare machine end to end:
|
|
6
|
+
*
|
|
7
|
+
* 1. Install Git via winget if missing (Flutter refuses to run without it).
|
|
8
|
+
* 2. Download the current stable Flutter SDK zip and unzip it into
|
|
9
|
+
* %LOCALAPPDATA%\flutter (a per-user dir that never needs admin rights).
|
|
10
|
+
* 3. Persist %LOCALAPPDATA%\flutter\bin on the User PATH for future terminals.
|
|
11
|
+
*
|
|
12
|
+
* The freshly-installed dirs are added to `augmentedEnv()` (see env-tools), so
|
|
13
|
+
* the rest of THIS `kasy new` run — flutter pub get, build_runner, flutterfire —
|
|
14
|
+
* finds the SDK immediately, without the user opening a new terminal.
|
|
15
|
+
*
|
|
16
|
+
* macOS/Linux don't need this: there Flutter installs via `brew install --cask
|
|
17
|
+
* flutter` (handled by the generic install path in checks.js).
|
|
18
|
+
*/
|
|
19
|
+
const { exec } = require('node:child_process');
|
|
20
|
+
const path = require('node:path');
|
|
21
|
+
|
|
22
|
+
const isWindows = process.platform === 'win32';
|
|
23
|
+
|
|
24
|
+
// Where the SDK archive is unzipped. Must stay in sync with env-tools
|
|
25
|
+
// extraToolDirs() so the recheck and the build steps look in the same place.
|
|
26
|
+
function flutterWinHome() {
|
|
27
|
+
const base =
|
|
28
|
+
process.env.LOCALAPPDATA ||
|
|
29
|
+
path.win32.join(process.env.USERPROFILE || '', 'AppData', 'Local');
|
|
30
|
+
return path.win32.join(base, 'flutter');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// The PowerShell that does the actual work. Kept as a script (not a one-liner)
|
|
34
|
+
// because it has to download ~1 GB, unzip it, and edit the persistent PATH —
|
|
35
|
+
// none of which fits a single shell command cleanly.
|
|
36
|
+
const PS_SCRIPT = `
|
|
37
|
+
$ErrorActionPreference = 'Stop'
|
|
38
|
+
# Silencing the progress bar makes Invoke-WebRequest dramatically faster and
|
|
39
|
+
# keeps our spinner the only thing the user sees.
|
|
40
|
+
$ProgressPreference = 'SilentlyContinue'
|
|
41
|
+
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
42
|
+
|
|
43
|
+
$dest = Join-Path $env:LOCALAPPDATA 'flutter'
|
|
44
|
+
$bin = Join-Path $dest 'bin'
|
|
45
|
+
|
|
46
|
+
# 1. Git — Flutter uses it internally and won't run without it.
|
|
47
|
+
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
|
|
48
|
+
if (Get-Command winget -ErrorAction SilentlyContinue) {
|
|
49
|
+
winget install --id Git.Git -e --source winget --silent --accept-source-agreements --accept-package-agreements --disable-interactivity | Out-Null
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# 2. Flutter SDK — download + unzip, unless it's already there.
|
|
54
|
+
if (-not (Test-Path (Join-Path $bin 'flutter.bat'))) {
|
|
55
|
+
if (Test-Path $dest) { Remove-Item -Recurse -Force $dest }
|
|
56
|
+
$json = Invoke-RestMethod 'https://storage.googleapis.com/flutter_infra_release/releases/releases_windows.json'
|
|
57
|
+
$hash = $json.current_release.stable
|
|
58
|
+
$rel = $json.releases | Where-Object { $_.hash -eq $hash } | Select-Object -First 1
|
|
59
|
+
if (-not $rel) { throw 'Could not find the current stable Flutter release.' }
|
|
60
|
+
$url = $json.base_url + '/' + $rel.archive
|
|
61
|
+
$zip = Join-Path $env:TEMP ('flutter_sdk_' + $rel.version + '.zip')
|
|
62
|
+
Invoke-WebRequest -Uri $url -OutFile $zip
|
|
63
|
+
# ZipFile.ExtractToDirectory is much faster than Expand-Archive for a SDK-sized
|
|
64
|
+
# archive. The zip contains a top-level 'flutter\\' folder, so extracting into
|
|
65
|
+
# %LOCALAPPDATA% yields exactly %LOCALAPPDATA%\flutter.
|
|
66
|
+
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
67
|
+
[System.IO.Compression.ZipFile]::ExtractToDirectory($zip, $env:LOCALAPPDATA)
|
|
68
|
+
Remove-Item $zip -Force -ErrorAction SilentlyContinue
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# 3. Persist flutter\\bin on the User PATH so every future terminal finds it.
|
|
72
|
+
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
|
|
73
|
+
if (-not $userPath) { $userPath = '' }
|
|
74
|
+
if (($userPath -split ';') -notcontains $bin) {
|
|
75
|
+
$newPath = if ($userPath.Length -gt 0) { $userPath.TrimEnd(';') + ';' + $bin } else { $bin }
|
|
76
|
+
[Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
Write-Output ('FLUTTER_BIN=' + $bin)
|
|
80
|
+
`;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Run the installer. Resolves to the same shape as checks.execTool
|
|
84
|
+
* ({ ok, stdout, stderr, error }) so the caller can treat it uniformly.
|
|
85
|
+
*
|
|
86
|
+
* @param {{ timeout?: number }} [opts]
|
|
87
|
+
* @returns {Promise<{ ok: boolean, stdout: string, stderr: string, error: string|null }>}
|
|
88
|
+
*/
|
|
89
|
+
function installFlutterWindows({ timeout = 1_800_000 } = {}) {
|
|
90
|
+
return new Promise((resolve) => {
|
|
91
|
+
if (!isWindows) {
|
|
92
|
+
resolve({ ok: false, stdout: '', stderr: '', error: 'not windows' });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// -EncodedCommand (UTF-16LE base64) sidesteps every quoting headache of
|
|
96
|
+
// passing a multi-line script through a shell.
|
|
97
|
+
const encoded = Buffer.from(PS_SCRIPT, 'utf16le').toString('base64');
|
|
98
|
+
const cmd = `powershell -NoProfile -ExecutionPolicy Bypass -EncodedCommand ${encoded}`;
|
|
99
|
+
exec(
|
|
100
|
+
cmd,
|
|
101
|
+
{ timeout, maxBuffer: 50 * 1024 * 1024, windowsHide: true },
|
|
102
|
+
(error, stdout, stderr) => {
|
|
103
|
+
resolve({
|
|
104
|
+
ok: !error,
|
|
105
|
+
stdout: stdout || '',
|
|
106
|
+
stderr: stderr || '',
|
|
107
|
+
error: error ? error.message : null,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
module.exports = { installFlutterWindows, flutterWinHome };
|
|
@@ -43,7 +43,7 @@ module.exports = {
|
|
|
43
43
|
'cli.command.setup.langName': 'lang',
|
|
44
44
|
'cli.command.setup.langOption': 'Prompt language (en, pt, es)',
|
|
45
45
|
'cli.command.setup.backendOption': 'Backend adapter (firebase, supabase, api)',
|
|
46
|
-
'cli.command.setup.featuresOption': 'Comma separated optional features (web,widget,
|
|
46
|
+
'cli.command.setup.featuresOption': 'Comma separated optional features (web,widget,ai_chat,revenuecat,ci)',
|
|
47
47
|
'cli.command.help.paramName': 'command',
|
|
48
48
|
'cli.command.doctor.description': 'Check if your computer is ready to run Kasy',
|
|
49
49
|
'cli.command.modules.description': 'Show what comes included and what you can add',
|
|
@@ -109,15 +109,15 @@ module.exports = {
|
|
|
109
109
|
'modules.backend.supabase.description': 'Supabase backend adapter',
|
|
110
110
|
'modules.backend.api.description': 'REST/GraphQL API backend adapter',
|
|
111
111
|
'modules.feature.sentry.description': 'Sentry error tracking and crash reporting',
|
|
112
|
-
'modules.feature.analytics.description': 'Analytics event tracking (
|
|
112
|
+
'modules.feature.analytics.description': 'Analytics event tracking (Mixpanel)',
|
|
113
113
|
'modules.feature.facebook.description': 'Facebook Login and Meta Ads event tracking (always bundled together)',
|
|
114
114
|
'modules.feature.revenuecat.description': 'Enables real in-app payments on the Subscriptions screen',
|
|
115
115
|
'modules.feature.onboarding.description': 'Welcome flow shown on first launch',
|
|
116
116
|
'modules.feature.web.description': 'Web/PWA support',
|
|
117
117
|
'modules.feature.widget.description': 'iOS/Android home screen widget integration',
|
|
118
|
-
'modules.feature.
|
|
118
|
+
'modules.feature.ai_chat.description': 'AI chat screen with OpenAI or Gemini',
|
|
119
119
|
'modules.feature.feedback.description': 'In-app feature requests and voting',
|
|
120
|
-
'modules.feature.
|
|
120
|
+
'modules.feature.local_reminders.description': 'Local reminders scheduled by the user (no server required)',
|
|
121
121
|
'modules.feature.ci.description': 'CI/CD: GitHub/GitLab (tests + build) + Codemagic (publish to stores)',
|
|
122
122
|
'checks.checking': 'Checking {name}...',
|
|
123
123
|
'checks.found': '{name} found',
|
|
@@ -134,6 +134,8 @@ module.exports = {
|
|
|
134
134
|
'checks.thenRun': 'Then run',
|
|
135
135
|
'checks.recheck': 'After installing {name}, press Enter to check again',
|
|
136
136
|
'checks.install.confirm': 'Install {name} now? ({cmd})',
|
|
137
|
+
'checks.install.flutterWinDesc': 'downloads the official Flutter SDK + Git, ~1.8 GB',
|
|
138
|
+
'checks.install.flutterWinNote': 'This can take a few minutes (large download). If a Windows approval popup appears, click Yes.',
|
|
137
139
|
'checks.install.running': 'Installing {name}…',
|
|
138
140
|
'checks.install.failedManual': 'Could not install {name} automatically. Do it manually:',
|
|
139
141
|
'checks.install.openDocs': 'Open the install page in the browser?',
|
|
@@ -268,6 +270,9 @@ module.exports = {
|
|
|
268
270
|
'new.supabase.created': 'Project created successfully.',
|
|
269
271
|
'new.supabase.createFailed': 'Could not create project',
|
|
270
272
|
'new.supabase.loginHint': 'Run: supabase login. Then enter your existing project URL and key below.',
|
|
273
|
+
'new.supabase.createFailed.freeLimit': 'Your Supabase free plan reached the project limit for this organization.',
|
|
274
|
+
'new.supabase.freeLimit.title': 'How to unblock',
|
|
275
|
+
'new.supabase.freeLimit.options': '• Delete a project you no longer use\n• Pick another organization (if you have more than one)\n• Or upgrade your plan in the Supabase dashboard\nThen run kasy new again.',
|
|
271
276
|
'new.supabase.setup': 'Linking project and deploying…',
|
|
272
277
|
'new.supabase.setupManual': 'Run manually: supabase link, supabase db push, supabase functions deploy',
|
|
273
278
|
'new.supabase.passwordSaved': 'Database password auto-generated and saved to .kasy/supabase.json (gitignored).',
|
|
@@ -345,8 +350,10 @@ module.exports = {
|
|
|
345
350
|
'configure.section.sentry': 'Sentry (Crash Reports)',
|
|
346
351
|
'configure.section.mixpanel': 'Mixpanel (Analytics)',
|
|
347
352
|
'configure.section.revenuecat': 'RevenueCat (Subscriptions)',
|
|
353
|
+
'configure.section.stripe': 'Stripe (Web Payments)',
|
|
354
|
+
'configure.stripe.apiNote': 'API backend: set STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET on your own server (see Stripe-Guia.md). The CLI cannot store them for you.',
|
|
348
355
|
'configure.section.facebook': 'Facebook (Login + Ads)',
|
|
349
|
-
'configure.section.
|
|
356
|
+
'configure.section.aiChat': 'AI Chat',
|
|
350
357
|
'configure.savedFacebook': 'Facebook credentials written to Info.plist and strings.xml.',
|
|
351
358
|
'configure.facebookPlistMissing': 'ios/Runner/Info.plist not found — Facebook iOS was not updated.',
|
|
352
359
|
'configure.facebookStringsMissing': 'android/.../strings.xml not found — Facebook Android was not updated.',
|
|
@@ -501,7 +508,13 @@ module.exports = {
|
|
|
501
508
|
'doctor.revenuecat.prefixMismatch': 'Key has wrong prefix: {key} should start with {expected}',
|
|
502
509
|
'doctor.revenuecat.keysTest': 'Only Test Store keys (test_) configured — store releases require appl_/goog_, otherwise the app crashes',
|
|
503
510
|
'doctor.revenuecat.webhookUrlSupabase': 'Webhook URL (paste in RevenueCat → Integrations → Webhooks)',
|
|
504
|
-
'doctor.revenuecat.webhookUrlFirebase': 'Webhook URL: Firebase Console → Functions →
|
|
511
|
+
'doctor.revenuecat.webhookUrlFirebase': 'Webhook URL: Firebase Console → Functions → subscriptions-revenuecatWebhook',
|
|
512
|
+
'doctor.stripe.title': 'Stripe (Web Payments)',
|
|
513
|
+
'doctor.stripe.serverSide': 'Server-side only — no Stripe key ships in the app (hosted Checkout).',
|
|
514
|
+
'doctor.stripe.secretsFirebase': 'Set STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET via `kasy configure stripe`, then `kasy deploy`.',
|
|
515
|
+
'doctor.stripe.secretsSupabase': 'Secrets set with `supabase secrets set` (done at `kasy new` if provided).',
|
|
516
|
+
'doctor.stripe.secretsApi': 'Configure STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET on your own server (see Stripe-Guia.md).',
|
|
517
|
+
'doctor.stripe.webhookUrl': 'Stripe webhook URL (add in Stripe → Developers → Webhooks)',
|
|
505
518
|
|
|
506
519
|
'update.iosRelease.success': 'iOS release files updated',
|
|
507
520
|
'add.iosRelease.success': 'iOS release files added',
|
|
@@ -548,14 +561,15 @@ module.exports = {
|
|
|
548
561
|
'new.modules.header.feedback': '── Feedback (Firebase + Supabase) ──',
|
|
549
562
|
'new.modules.header.ci': '── CI/CD ──',
|
|
550
563
|
'new.modules.header.monetization': '── Monetization ──',
|
|
551
|
-
'new.firebase.module.revenuecat': '💰 RevenueCat (
|
|
564
|
+
'new.firebase.module.revenuecat': '💰 RevenueCat (mobile subscriptions)',
|
|
565
|
+
'new.firebase.module.stripe': '🌐 Stripe (web subscriptions)',
|
|
552
566
|
'new.firebase.module.sentry': '🚨 Crash Reports (Sentry)',
|
|
553
567
|
'new.firebase.module.analytics': '📊 Analytics (Mixpanel)',
|
|
554
568
|
'new.firebase.module.facebook': '👤 Facebook (Login + Ads)',
|
|
555
569
|
'new.firebase.module.web': '🌐 Web Support (PWA)',
|
|
556
570
|
'new.firebase.module.widget': '📱 Home Widget (iOS/Android)',
|
|
557
|
-
'new.firebase.module.
|
|
558
|
-
'new.firebase.module.
|
|
571
|
+
'new.firebase.module.ai_chat': '🤖 AI Chat (OpenAI/Gemini)',
|
|
572
|
+
'new.firebase.module.local_reminders': '🔔 Local Reminders (no server)',
|
|
559
573
|
'new.firebase.module.feedback': '💬 Feature Requests (requires Firebase or Supabase)',
|
|
560
574
|
'new.firebase.module.ci': '⚙️ CI/CD (GitHub + Codemagic)',
|
|
561
575
|
'new.firebase.module.onboarding': '👋 Onboarding (welcome flow)',
|
|
@@ -579,10 +593,12 @@ module.exports = {
|
|
|
579
593
|
'new.firebase.q.revenuecat.ios': 'RevenueCat API key for iOS',
|
|
580
594
|
'new.firebase.q.paywall': 'Which paywall style?',
|
|
581
595
|
'new.firebase.q.paywall.hint': 'Layout of the subscription screen — you can change it later in RevenueCat',
|
|
582
|
-
'new.firebase.q.
|
|
583
|
-
'new.firebase.q.
|
|
584
|
-
'new.firebase.q.
|
|
585
|
-
'new.firebase.
|
|
596
|
+
'new.firebase.q.stripe.secretKey': 'Stripe Secret Key (sk_test_… / sk_live_…) — optional, configure later',
|
|
597
|
+
'new.firebase.q.stripe.webhookSecret': 'Stripe Webhook Signing Secret (whsec_…) — optional, configure later',
|
|
598
|
+
'new.firebase.q.stripe.webhookSecret.hint': 'From Stripe → Developers → Webhooks → your endpoint',
|
|
599
|
+
'new.firebase.q.stripe.webhookSecret.invalid': 'Webhook signing secret must start with whsec_.',
|
|
600
|
+
'new.firebase.q.stripe.productId': 'Stripe Product ID (prod_…) — optional, limits the paywall to one product',
|
|
601
|
+
'new.firebase.q.stripe.productId.hint': 'Leave blank to list all active recurring prices',
|
|
586
602
|
'new.firebase.q.sentry.dsn': 'Sentry DSN (leave blank to configure later)',
|
|
587
603
|
'new.firebase.q.sentry.dsn.invalid': 'Invalid DSN. Expected format: https://key@host/project-id',
|
|
588
604
|
'new.firebase.q.mixpanel.token': 'Mixpanel Token (leave blank to configure later)',
|
|
@@ -594,7 +610,6 @@ module.exports = {
|
|
|
594
610
|
'new.firebase.q.revenuecat.android.required': 'RevenueCat Android key is required.',
|
|
595
611
|
'new.firebase.q.revenuecat.ios.required': 'RevenueCat iOS key is required.',
|
|
596
612
|
'new.firebase.q.revenuecat.metaDataset.invalid': 'Pixel ID must be numeric (e.g. 1234567890).',
|
|
597
|
-
'new.firebase.q.revenuecat.webKey.invalid': 'Web Billing key must start with rcb_ (e.g. rcb_sb_xxx or rcb_xxx).',
|
|
598
613
|
|
|
599
614
|
'new.firebase.confirm.title': 'Configuration summary:',
|
|
600
615
|
'new.firebase.confirm.app': 'App',
|
|
@@ -707,6 +722,8 @@ module.exports = {
|
|
|
707
722
|
'new.outdated.upgraded': 'kasy updated! Run kasy new again.',
|
|
708
723
|
'new.success.title': 'Project created successfully!',
|
|
709
724
|
'new.success.featuresInstalled': 'Features enabled:',
|
|
725
|
+
'new.success.bundleId': 'App identifier (bundle ID)',
|
|
726
|
+
'new.success.bundleId.hint': "Your app's unique identifier on Android, iOS and Firebase (push).",
|
|
710
727
|
'new.success.nextSteps': 'Next steps:',
|
|
711
728
|
'new.success.step.cd': 'Go to your project folder:',
|
|
712
729
|
'new.success.step.deploy': 'Push the server to Firebase (DB + functions):',
|
|
@@ -916,7 +933,7 @@ module.exports = {
|
|
|
916
933
|
'notifications.error.notKasyProject': 'No kit_setup.json found. Run this command from inside a Kasy project.',
|
|
917
934
|
'notifications.error.noI18n': 'lib/i18n/*.i18n.json not found in this project.',
|
|
918
935
|
'notifications.error.noFeatures': 'lib/core/config/features.dart not found.',
|
|
919
|
-
'notifications.error.notEnabled': 'Local notifications are disabled. Run: kasy add
|
|
936
|
+
'notifications.error.notEnabled': 'Local notifications are disabled. Run: kasy add local_reminders',
|
|
920
937
|
'notifications.error.cancelled': 'Cancelled.',
|
|
921
938
|
'notifications.prompt.intro': 'Local notification texts',
|
|
922
939
|
'notifications.prompt.hint': 'Home demo = instant test from Features. Reminder = scheduled alert from Settings.',
|
|
@@ -959,26 +976,26 @@ module.exports = {
|
|
|
959
976
|
// Legacy keys — kept for compatibility with old scripts.
|
|
960
977
|
'add.prompt.rcAndroidKey': 'RevenueCat Android API key (leave blank to configure later):',
|
|
961
978
|
'add.prompt.rcIosKey': 'RevenueCat iOS API key (leave blank to configure later):',
|
|
962
|
-
'add.note.facebook': 'Add your Facebook App ID and token in .vscode/launch.json (FB_APP_ID,
|
|
963
|
-
'new.q.
|
|
964
|
-
'new.q.
|
|
965
|
-
'add.
|
|
966
|
-
'add.prompt.
|
|
967
|
-
'add.prompt.
|
|
968
|
-
'add.prompt.
|
|
969
|
-
'add.prompt.
|
|
970
|
-
'add.
|
|
971
|
-
'add.
|
|
972
|
-
'add.
|
|
973
|
-
'add.
|
|
974
|
-
'add.
|
|
975
|
-
'add.
|
|
976
|
-
'add.
|
|
977
|
-
'add.
|
|
978
|
-
'add.
|
|
979
|
-
'add.
|
|
980
|
-
'add.
|
|
981
|
-
'add.
|
|
979
|
+
'add.note.facebook': 'Add your Facebook App ID and token in .vscode/launch.json (FB_APP_ID, FB_CLIENT_TOKEN).',
|
|
980
|
+
'new.q.ai_chat.configureNow': 'Configure the AI Chat agent now?',
|
|
981
|
+
'new.q.ai_chat.configureNow.hint': 'You can skip and run "kasy add ai_chat" later',
|
|
982
|
+
'add.ai_chat.reconfigure': 'Feature already active — reconfiguring credentials only.',
|
|
983
|
+
'add.prompt.aiProvider': 'AI provider:',
|
|
984
|
+
'add.prompt.aiSystemPrompt': 'Agent system prompt (leave blank for none):\n Example: "You are a support assistant for the Fitsync app. Only answer about workouts."\n >',
|
|
985
|
+
'add.prompt.aiApiKey': 'API key (OpenAI or Gemini) — stored as server secret, never in the app (leave blank to set later):',
|
|
986
|
+
'add.prompt.aiEndpoint': 'Your AI endpoint URL (leave blank to configure later):',
|
|
987
|
+
'add.ai_chat.settingSecret': 'Storing API key as server secret...',
|
|
988
|
+
'add.ai_chat.secretSet': 'API key stored as secret',
|
|
989
|
+
'add.ai_chat.secretFailed': 'Could not set secret automatically — set it manually (see instructions below)',
|
|
990
|
+
'add.ai_chat.skipSecret': 'API key skipped — set it later via the server CLI before deploying',
|
|
991
|
+
'add.ai_chat.deploying': 'Deploying AI function to server...',
|
|
992
|
+
'add.ai_chat.deployed': 'AI function deployed successfully',
|
|
993
|
+
'add.ai_chat.deployFailed': 'Auto-deploy failed — deploy manually (see instructions below)',
|
|
994
|
+
'add.ai_chat.nextSteps.firebase': '\n Next steps:\n 1. The AI_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 2. Run the app: kasy run\n',
|
|
995
|
+
'add.ai_chat.nextSteps.firebase.deployFailed': '\n Next steps:\n 1. Deploy manually: firebase deploy --only functions:aiChat\n 2. The AI_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 3. Run the app: kasy run\n',
|
|
996
|
+
'add.ai_chat.nextSteps.supabase': '\n Next steps:\n 1. The AI_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 2. Run the app: kasy run\n',
|
|
997
|
+
'add.ai_chat.nextSteps.supabase.deployFailed': '\n Next steps:\n 1. Deploy manually: supabase functions deploy ai-chat --no-verify-jwt\n 2. The AI_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 3. Run the app: kasy run\n',
|
|
998
|
+
'add.ai_chat.nextSteps.api': '\n Next steps:\n 1. Create an endpoint on your server that accepts {message, history} and calls your AI.\n 2. Update AI_CHAT_ENDPOINT in .vscode/launch.json with your endpoint URL.\n 3. Run the app: kasy run\n',
|
|
982
999
|
'cli.command.remove.description': 'Remove a feature you no longer use (e.g.: kasy remove sentry)',
|
|
983
1000
|
'remove.error.noModule': 'Provide a feature name. Usage: kasy remove <feature>',
|
|
984
1001
|
'remove.error.notKasyProject': 'No kit_setup.json found. Run this command from inside a Kasy project.',
|