kasy-cli 1.16.0 → 1.18.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/bin/kasy.js +16 -2
- package/lib/commands/add.js +52 -19
- package/lib/commands/configure.js +548 -0
- package/lib/commands/deploy.js +4 -4
- package/lib/commands/doctor.js +54 -6
- package/lib/commands/favicon.js +4 -4
- package/lib/commands/icon.js +5 -5
- package/lib/commands/new.js +404 -213
- package/lib/commands/remove.js +14 -3
- package/lib/commands/run.js +208 -6
- package/lib/commands/splash.js +5 -5
- package/lib/commands/update.js +9 -9
- package/lib/scaffold/CHANGELOG.json +23 -0
- package/lib/scaffold/backends/api/patch/README.md +3 -2
- package/lib/scaffold/backends/firebase/enable-auth-via-cli.js +108 -0
- package/lib/scaffold/backends/firebase/setup-from-scratch.js +44 -5
- package/lib/scaffold/backends/supabase/patch/README.md +3 -2
- package/lib/scaffold/generate.js +24 -8
- package/lib/scaffold/shared/generator-utils.js +52 -8
- package/lib/scaffold/shared/post-build.js +113 -31
- package/lib/scaffold/shared/template-strings.js +6 -0
- package/lib/utils/brand.js +16 -12
- package/lib/utils/flutter-run.js +139 -11
- package/lib/utils/i18n/messages-en.js +85 -7
- package/lib/utils/i18n/messages-es.js +85 -7
- package/lib/utils/i18n/messages-pt.js +86 -8
- package/lib/utils/ui.js +79 -4
- package/package.json +1 -1
- package/templates/firebase/README.en.md +18 -8
- package/templates/firebase/README.es.md +18 -8
- package/templates/firebase/README.md +18 -8
- package/templates/firebase/android/app/src/main/kotlin/com/aicrus/firebase/kit/MyWidget.kt +68 -45
- package/templates/firebase/android/app/src/main/kotlin/com/aicrus/firebase/kit/MyWidgetReceiver.kt +37 -0
- package/templates/firebase/android/app/src/main/kotlin/com/aicrus/firebase/kit/OpenAppAction.kt +26 -0
- package/templates/firebase/android/app/src/main/res/drawable/widget_add_button.xml +2 -2
- package/templates/firebase/android/app/src/main/res/drawable/widget_gradient_bg.xml +7 -2
- package/templates/firebase/android/app/src/main/res/drawable/widget_gradient_inner.xml +6 -6
- package/templates/firebase/android/app/src/main/res/drawable/widget_plan_pill_bg.xml +1 -1
- package/templates/firebase/android/app/src/main/res/drawable/widget_preview_image.xml +2 -2
- package/templates/firebase/android/app/src/main/res/drawable/widget_pro_pill_bg.xml +1 -1
- package/templates/firebase/android/app/src/main/res/drawable-hdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-hdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-mdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-mdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-hdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-hdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-mdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-mdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-xhdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-xhdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-xxhdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-xxxhdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-xhdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-xhdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-xxhdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-xxhdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-xxxhdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-xxxhdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/layout/widget_preview.xml +3 -3
- package/templates/firebase/android/app/src/main/res/values/colors.xml +32 -0
- package/templates/firebase/assets/images/splash_logo_dark.png +0 -0
- package/templates/firebase/assets/images/splash_logo_dark_android12.png +0 -0
- package/templates/firebase/assets/images/splash_logo_light.png +0 -0
- package/templates/firebase/assets/images/splash_logo_light_android12.png +0 -0
- package/templates/firebase/docs/revenuecat-setup.es.md +28 -8
- package/templates/firebase/docs/revenuecat-setup.pt.md +28 -8
- package/templates/firebase/ios/HomeWidgetExtension/MyWidget.swift +75 -29
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png +0 -0
- package/templates/firebase/ios/Runner/Base.lproj/LaunchScreen.storyboard +1 -1
- package/templates/firebase/lib/components/components.dart +1 -0
- package/templates/firebase/lib/components/kasy_avatar.dart +65 -17
- package/templates/firebase/lib/components/kasy_avatar_presets.dart +121 -97
- package/templates/firebase/lib/components/kasy_button.dart +8 -8
- package/templates/firebase/lib/components/kasy_date_picker.dart +834 -0
- package/templates/firebase/lib/components/kasy_tabs.dart +145 -61
- package/templates/firebase/lib/core/home_widgets/home_widget_mywidget_service.dart +45 -53
- package/templates/firebase/lib/features/home/home_components_preview_registry.dart +565 -77
- package/templates/firebase/lib/features/settings/ui/components/language_switcher.dart +10 -5
- package/templates/firebase/lib/i18n/en.i18n.json +2 -1
- package/templates/firebase/lib/i18n/es.i18n.json +2 -1
- package/templates/firebase/lib/i18n/pt.i18n.json +2 -1
- package/templates/firebase/lib/router.dart +15 -1
- package/templates/firebase/pubspec.yaml +1 -1
- package/templates/firebase/web/index.html +9 -0
- package/templates/firebase/web/splash/img/dark-1x.png +0 -0
- package/templates/firebase/web/splash/img/dark-2x.png +0 -0
- package/templates/firebase/web/splash/img/dark-3x.png +0 -0
- package/templates/firebase/web/splash/img/dark-4x.png +0 -0
- package/templates/firebase/web/splash/img/light-1x.png +0 -0
- package/templates/firebase/web/splash/img/light-2x.png +0 -0
- package/templates/firebase/web/splash/img/light-3x.png +0 -0
- package/templates/firebase/web/splash/img/light-4x.png +0 -0
package/bin/kasy.js
CHANGED
|
@@ -8,6 +8,7 @@ const { runDoctor } = require('../lib/commands/doctor');
|
|
|
8
8
|
const { runFeatures } = require('../lib/commands/features');
|
|
9
9
|
const { runValidate } = require('../lib/commands/validate');
|
|
10
10
|
const { runDeployCommand } = require('../lib/commands/deploy');
|
|
11
|
+
const { runConfigure } = require('../lib/commands/configure');
|
|
11
12
|
const { runCheck } = require('../lib/commands/check');
|
|
12
13
|
const { runRun } = require('../lib/commands/run');
|
|
13
14
|
const { runReset } = require('../lib/commands/reset');
|
|
@@ -137,7 +138,7 @@ function createLocalizedHelpConfig(t) {
|
|
|
137
138
|
// Group root commands by intent for easier scanning by non-devs.
|
|
138
139
|
const groups = [
|
|
139
140
|
{ id: 'start', ids: ['new', 'doctor', 'features'] },
|
|
140
|
-
{ id: 'work', ids: ['add', 'remove', 'update', 'run', 'reset', 'splash', 'icon', 'favicon', 'notifications'] },
|
|
141
|
+
{ id: 'work', ids: ['add', 'configure', 'remove', 'update', 'run', 'reset', 'splash', 'icon', 'favicon', 'notifications'] },
|
|
141
142
|
{ id: 'publish', ids: ['deploy', 'check', 'ios', 'codemagic'] },
|
|
142
143
|
{ id: 'maintenance', ids: ['upgrade', 'version', 'uninstall', 'docs'] },
|
|
143
144
|
{ id: 'advanced', ids: ['setup', 'validate'] },
|
|
@@ -240,7 +241,7 @@ function buildProgram(language) {
|
|
|
240
241
|
.argument('[directory]', 'Target folder (default: asks during setup)', '.')
|
|
241
242
|
.option('-b, --backend <backend>', t('cli.command.setup.backendOption'))
|
|
242
243
|
.option('--with <features>', t('cli.command.setup.featuresOption'))
|
|
243
|
-
.option('--yes', 'Skip interactive questions
|
|
244
|
+
.option('--yes', 'Skip interactive questions (Quick mode, all features)')
|
|
244
245
|
.option('-p, --project <id>', 'Firebase Project ID (used with --yes)')
|
|
245
246
|
.description(t('cli.command.new.description'))
|
|
246
247
|
.action(async (directory, options) => {
|
|
@@ -324,6 +325,17 @@ function buildProgram(language) {
|
|
|
324
325
|
t
|
|
325
326
|
);
|
|
326
327
|
|
|
328
|
+
applyLocalizedHelp(
|
|
329
|
+
program
|
|
330
|
+
.command('configure')
|
|
331
|
+
.argument('[directory]', 'Project folder (default: current directory)', '.')
|
|
332
|
+
.description(t('cli.command.configure.description'))
|
|
333
|
+
.action(async (directory) => {
|
|
334
|
+
await runConfigure({ directory, language });
|
|
335
|
+
}),
|
|
336
|
+
t
|
|
337
|
+
);
|
|
338
|
+
|
|
327
339
|
applyLocalizedHelp(
|
|
328
340
|
program
|
|
329
341
|
.command('check')
|
|
@@ -346,6 +358,8 @@ function buildProgram(language) {
|
|
|
346
358
|
.option('-d, --device <id>', 'Run on specific device ID')
|
|
347
359
|
.option('--prod', 'Use production dart-defines (from launch.json)')
|
|
348
360
|
.option('--no-defines', 'Skip dart-defines from launch.json')
|
|
361
|
+
.option('--rc <mode>', 'RevenueCat key mode: auto (default — picks by device), test, or prod')
|
|
362
|
+
.option('--raw', 'Disable spinner and pass Flutter output straight through (auto-on when stdout is not a TTY)')
|
|
349
363
|
.description(t('cli.command.run.description'))
|
|
350
364
|
.action(async (directory, options) => {
|
|
351
365
|
await runRun(directory, { language, ...options });
|
package/lib/commands/add.js
CHANGED
|
@@ -6,7 +6,7 @@ const fs = require('fs-extra');
|
|
|
6
6
|
const pkg = require('../../package.json');
|
|
7
7
|
const kleur = require('kleur');
|
|
8
8
|
const ui = require('../utils/ui');
|
|
9
|
-
const { printCompactHeader } = require('../utils/brand');
|
|
9
|
+
const { printCompactHeader, paintLime } = require('../utils/brand');
|
|
10
10
|
const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
|
|
11
11
|
const {
|
|
12
12
|
AVAILABLE_FEATURES,
|
|
@@ -24,7 +24,7 @@ function findBaseDisplayName(id) {
|
|
|
24
24
|
|
|
25
25
|
const KASY_AUDIENCE = process.env.KASY_INTERNAL === '1' ? 'internal' : 'public';
|
|
26
26
|
const { applyPatch } = require('../scaffold/engine');
|
|
27
|
-
const { writeRouter, writeNoOpAnalyticsApi, writeNoOpTrackingApi, writeNoOpAdminHomeWidgets, writeNoOpFeatureRequestRepository, writeMainDart, addPubspecDep, localizeReleaseDocs } = require('../scaffold/shared/generator-utils');
|
|
27
|
+
const { writeRouter, writeNoOpAnalyticsApi, writeNoOpTrackingApi, writeNoOpAdminHomeWidgets, writeNoOpFeatureRequestRepository, writeMainDart, addPubspecDep, localizeReleaseDocs, resolveDefaultRcKeys } = require('../scaffold/shared/generator-utils');
|
|
28
28
|
const { toPackageName, buildTokens } = require('../scaffold/backends/firebase/tokens');
|
|
29
29
|
|
|
30
30
|
const execAsync = promisify(exec);
|
|
@@ -217,6 +217,14 @@ function applyKitSetupFlag(config, module, answers) {
|
|
|
217
217
|
case 'revenuecat':
|
|
218
218
|
config.subscriptionModule = true;
|
|
219
219
|
if (answers.revenuecatWeb) config.revenuecatWeb = true;
|
|
220
|
+
// Track which RC keys the user configured so `kasy doctor` can warn
|
|
221
|
+
// about release readiness without re-reading .env. Booleans only — we
|
|
222
|
+
// never persist the key values themselves to kit_setup.json.
|
|
223
|
+
config.revenuecatKeys = {
|
|
224
|
+
test: !!(answers.rcTestKey && answers.rcTestKey.trim()),
|
|
225
|
+
iosProd: !!(answers.rcIosProdKey && answers.rcIosProdKey.trim()),
|
|
226
|
+
androidProd: !!(answers.rcAndroidProdKey && answers.rcAndroidProdKey.trim()),
|
|
227
|
+
};
|
|
220
228
|
break;
|
|
221
229
|
case 'onboarding':
|
|
222
230
|
config.withOnboarding = true;
|
|
@@ -263,14 +271,18 @@ const MODULE_META = {
|
|
|
263
271
|
pubspecDeps: { 'facebook_app_events': '^0.24.0', 'flutter_facebook_auth': '^7.1.5' },
|
|
264
272
|
},
|
|
265
273
|
revenuecat: {
|
|
266
|
-
promptKeys: ['
|
|
267
|
-
defineUpdates: (a) =>
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
274
|
+
promptKeys: ['rcTestKey', 'rcIosProdKey', 'rcAndroidProdKey'],
|
|
275
|
+
defineUpdates: (a) => {
|
|
276
|
+
const { android, ios } = resolveDefaultRcKeys(a);
|
|
277
|
+
return {
|
|
278
|
+
RC_ANDROID_API_KEY: android,
|
|
279
|
+
RC_IOS_API_KEY: ios,
|
|
280
|
+
};
|
|
281
|
+
},
|
|
271
282
|
envLines: (a) => [
|
|
272
|
-
`
|
|
273
|
-
`
|
|
283
|
+
`RC_TEST_KEY=${(a.rcTestKey || '').trim()}`,
|
|
284
|
+
`RC_IOS_PROD_KEY=${(a.rcIosProdKey || '').trim()}`,
|
|
285
|
+
`RC_ANDROID_PROD_KEY=${(a.rcAndroidProdKey || '').trim()}`,
|
|
274
286
|
],
|
|
275
287
|
featureFlag: null,
|
|
276
288
|
pubspecDeps: {},
|
|
@@ -337,12 +349,33 @@ const PROMPT_QUESTIONS = {
|
|
|
337
349
|
onCancel: cancel,
|
|
338
350
|
}),
|
|
339
351
|
// RevenueCat SDK keys ship inside the client binary — not real secrets, plain text input.
|
|
340
|
-
|
|
341
|
-
|
|
352
|
+
// Three optional keys: test_ (covers iOS+Android in simulator), appl_ (iOS prod), goog_ (Android prod).
|
|
353
|
+
// kasy run picks the right one based on the device at launch time.
|
|
354
|
+
rcTestKey: (t, cancel) => ui.text({
|
|
355
|
+
message: t('add.prompt.rcTestKey'),
|
|
356
|
+
validate: (v) => {
|
|
357
|
+
const s = (v || '').trim();
|
|
358
|
+
if (!s) return undefined;
|
|
359
|
+
return /^test_/.test(s) ? undefined : t('new.firebase.q.revenuecat.test.invalid');
|
|
360
|
+
},
|
|
361
|
+
onCancel: cancel,
|
|
362
|
+
}),
|
|
363
|
+
rcIosProdKey: (t, cancel) => ui.text({
|
|
364
|
+
message: t('add.prompt.rcIosProdKey'),
|
|
365
|
+
validate: (v) => {
|
|
366
|
+
const s = (v || '').trim();
|
|
367
|
+
if (!s) return undefined;
|
|
368
|
+
return /^appl_/.test(s) ? undefined : t('new.firebase.q.revenuecat.iosProd.invalid');
|
|
369
|
+
},
|
|
342
370
|
onCancel: cancel,
|
|
343
371
|
}),
|
|
344
|
-
|
|
345
|
-
message: t('add.prompt.
|
|
372
|
+
rcAndroidProdKey: (t, cancel) => ui.text({
|
|
373
|
+
message: t('add.prompt.rcAndroidProdKey'),
|
|
374
|
+
validate: (v) => {
|
|
375
|
+
const s = (v || '').trim();
|
|
376
|
+
if (!s) return undefined;
|
|
377
|
+
return /^goog_/.test(s) ? undefined : t('new.firebase.q.revenuecat.androidProd.invalid');
|
|
378
|
+
},
|
|
346
379
|
onCancel: cancel,
|
|
347
380
|
}),
|
|
348
381
|
llmProvider: (t, cancel) => ui.select({
|
|
@@ -415,7 +448,7 @@ async function postAddLlmChat(projectDir, kitSetup, answers, t) {
|
|
|
415
448
|
const refFlag = backend === 'supabase' && projectRef ? ` --project-ref ${projectRef}` : '';
|
|
416
449
|
|
|
417
450
|
if (backend === 'firebase') {
|
|
418
|
-
const spinner = ui.spinner();
|
|
451
|
+
const spinner = ui.spinner({ color: paintLime });
|
|
419
452
|
spinner.start(t('add.llm_chat.settingSecret'));
|
|
420
453
|
try {
|
|
421
454
|
// Write to temp file — avoids trailing newline (echo) and shell injection risks
|
|
@@ -430,7 +463,7 @@ async function postAddLlmChat(projectDir, kitSetup, answers, t) {
|
|
|
430
463
|
ui.log.message(kleur.dim('Run manually: firebase functions:secrets:set LLM_API_KEY'));
|
|
431
464
|
}
|
|
432
465
|
} else if (backend === 'supabase') {
|
|
433
|
-
const spinner = ui.spinner();
|
|
466
|
+
const spinner = ui.spinner({ color: paintLime });
|
|
434
467
|
spinner.start(t('add.llm_chat.settingSecret'));
|
|
435
468
|
// Set LLM_API_KEY, LLM_PROVIDER and LLM_SYSTEM_PROMPT all as Supabase Secrets.
|
|
436
469
|
// Deployed Edge Functions read from Deno.env.get() = Supabase Secrets, NOT from .env files.
|
|
@@ -460,7 +493,7 @@ async function postAddLlmChat(projectDir, kitSetup, answers, t) {
|
|
|
460
493
|
// 3. Deploy the LLM function automatically
|
|
461
494
|
if (backend === 'api') return { deployOk: false, deployAttempted: false };
|
|
462
495
|
|
|
463
|
-
const deploySpinner = ui.timedSpinner();
|
|
496
|
+
const deploySpinner = ui.timedSpinner({ color: paintLime });
|
|
464
497
|
deploySpinner.start(t('add.llm_chat.deploying'));
|
|
465
498
|
try {
|
|
466
499
|
if (backend === 'firebase') {
|
|
@@ -688,7 +721,7 @@ async function runAdd(module, options = {}) {
|
|
|
688
721
|
// 8. Apply patch if it exists under features/<module>/
|
|
689
722
|
const patchDir = path.join(FEATURES_PATCH_DIR, normalized);
|
|
690
723
|
if (await fs.pathExists(patchDir)) {
|
|
691
|
-
const spinner = ui.spinner();
|
|
724
|
+
const spinner = ui.spinner({ color: paintLime });
|
|
692
725
|
spinner.start(t('add.applyingPatch'));
|
|
693
726
|
try {
|
|
694
727
|
const { tokens: patchTokens, pathReplacements: patchPathReplacements } = buildTokens({
|
|
@@ -748,7 +781,7 @@ async function runAdd(module, options = {}) {
|
|
|
748
781
|
|
|
749
782
|
// 10. flutter pub get
|
|
750
783
|
{
|
|
751
|
-
const spinner = ui.spinner();
|
|
784
|
+
const spinner = ui.spinner({ color: paintLime });
|
|
752
785
|
spinner.start(t('add.pubGet'));
|
|
753
786
|
try {
|
|
754
787
|
await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000 });
|
|
@@ -761,7 +794,7 @@ async function runAdd(module, options = {}) {
|
|
|
761
794
|
// 11. build_runner (only when needed: features with codegen)
|
|
762
795
|
const needsBuildRunner = ['revenuecat', 'analytics', 'sentry', 'onboarding', 'llm_chat', 'feedback'].includes(normalized);
|
|
763
796
|
if (needsBuildRunner) {
|
|
764
|
-
const spinner = ui.timedSpinner();
|
|
797
|
+
const spinner = ui.timedSpinner({ color: paintLime });
|
|
765
798
|
spinner.start(t('add.buildRunner'));
|
|
766
799
|
try {
|
|
767
800
|
await execAsync('dart run build_runner build --delete-conflicting-outputs', { cwd: projectDir, timeout: 600_000 });
|