kasy-cli 1.31.4 → 1.31.6
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 +2 -1
- package/lib/commands/remove.js +2 -1
- package/lib/commands/reset.js +2 -1
- package/lib/commands/run.js +6 -2
- package/lib/commands/update.js +4 -3
- package/lib/utils/env-tools.js +24 -0
- package/lib/utils/flutter-run.js +3 -3
- package/package.json +1 -1
- package/templates/firebase/lib/core/config/app_env.dart +77 -5
- package/templates/firebase/pubspec.yaml +1 -1
package/lib/commands/add.js
CHANGED
|
@@ -8,6 +8,7 @@ const kleur = require('kleur');
|
|
|
8
8
|
const ui = require('../utils/ui');
|
|
9
9
|
const { printCompactHeader, paintLime } = require('../utils/brand');
|
|
10
10
|
const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
|
|
11
|
+
const { augmentedEnv } = require('../utils/env-tools');
|
|
11
12
|
const {
|
|
12
13
|
AVAILABLE_FEATURES,
|
|
13
14
|
FEATURES_PATCH_DIR,
|
|
@@ -797,7 +798,7 @@ async function runAdd(module, options = {}) {
|
|
|
797
798
|
const spinner = ui.spinner({ color: paintLime });
|
|
798
799
|
spinner.start(t('add.pubGet'));
|
|
799
800
|
try {
|
|
800
|
-
await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000 });
|
|
801
|
+
await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000, env: augmentedEnv() });
|
|
801
802
|
spinner.stop(t('add.pubGetDone'));
|
|
802
803
|
} catch {
|
|
803
804
|
spinner.stop(`⚠ ${t('add.pubGetFailed')}`);
|
package/lib/commands/remove.js
CHANGED
|
@@ -9,6 +9,7 @@ const kleur = require('kleur');
|
|
|
9
9
|
const ui = require('../utils/ui');
|
|
10
10
|
const { printCompactHeader } = require('../utils/brand');
|
|
11
11
|
const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
|
|
12
|
+
const { augmentedEnv } = require('../utils/env-tools');
|
|
12
13
|
const {
|
|
13
14
|
AVAILABLE_FEATURES,
|
|
14
15
|
normalizeFeature,
|
|
@@ -471,7 +472,7 @@ async function runRemove(module, options = {}) {
|
|
|
471
472
|
const spinner = ui.spinner();
|
|
472
473
|
spinner.start(t('remove.pubGet'));
|
|
473
474
|
try {
|
|
474
|
-
await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000 });
|
|
475
|
+
await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000, env: augmentedEnv() });
|
|
475
476
|
spinner.stop(t('remove.pubGetDone'));
|
|
476
477
|
} catch {
|
|
477
478
|
spinner.stop(`⚠ ${t('remove.pubGetFailed')}`);
|
package/lib/commands/reset.js
CHANGED
|
@@ -7,6 +7,7 @@ const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
|
|
|
7
7
|
const { printCompactHeader } = require('../utils/brand');
|
|
8
8
|
const { readBundleId, readPackageName } = require('../utils/mobile-identity');
|
|
9
9
|
const { spawnFlutterWithSpinner } = require('../utils/flutter-run');
|
|
10
|
+
const { spawnSyncFlutter } = require('../utils/env-tools');
|
|
10
11
|
|
|
11
12
|
function runCmd(cmd, args) {
|
|
12
13
|
const res = spawnSync(cmd, args, { encoding: 'utf8' });
|
|
@@ -18,7 +19,7 @@ function runCmd(cmd, args) {
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
async function listFlutterDevices(projectDir) {
|
|
21
|
-
const res =
|
|
22
|
+
const res = spawnSyncFlutter(['devices', '--machine'], {
|
|
22
23
|
cwd: projectDir,
|
|
23
24
|
encoding: 'utf8',
|
|
24
25
|
});
|
package/lib/commands/run.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
const path = require('node:path');
|
|
2
|
-
const { spawnSync } = require('node:child_process');
|
|
3
2
|
const fs = require('fs-extra');
|
|
4
3
|
const kleur = require('kleur');
|
|
5
4
|
const ui = require('../utils/ui');
|
|
6
5
|
const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
|
|
7
6
|
const { printCompactHeader, paintLime } = require('../utils/brand');
|
|
8
7
|
const { spawnFlutterWithSpinner } = require('../utils/flutter-run');
|
|
8
|
+
const { spawnSyncFlutter } = require('../utils/env-tools');
|
|
9
9
|
|
|
10
10
|
function listFlutterDevices(projectDir) {
|
|
11
|
-
|
|
11
|
+
// Shared flutter spawner: exposes a freshly-installed SDK on PATH (the terminal
|
|
12
|
+
// may not have it yet right after `kasy new`) and handles the Windows flutter.bat
|
|
13
|
+
// without tripping Node's shell+args deprecation warning. Without it, a machine
|
|
14
|
+
// that just ran `kasy new` reports "Flutter not found" here.
|
|
15
|
+
const res = spawnSyncFlutter(['devices', '--machine'], {
|
|
12
16
|
cwd: projectDir,
|
|
13
17
|
encoding: 'utf8',
|
|
14
18
|
});
|
package/lib/commands/update.js
CHANGED
|
@@ -9,6 +9,7 @@ const kleur = require('kleur');
|
|
|
9
9
|
const ui = require('../utils/ui');
|
|
10
10
|
const { printCompactHeader, paintLime } = require('../utils/brand');
|
|
11
11
|
const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
|
|
12
|
+
const { augmentedEnv } = require('../utils/env-tools');
|
|
12
13
|
const {
|
|
13
14
|
AVAILABLE_FEATURES,
|
|
14
15
|
BASE_COMPONENT_FILES,
|
|
@@ -204,7 +205,7 @@ async function runUpdate(module, options = {}) {
|
|
|
204
205
|
const spinnerPubGet = ui.spinner({ color: paintLime });
|
|
205
206
|
spinnerPubGet.start(t('update.pubGet'));
|
|
206
207
|
try {
|
|
207
|
-
await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000 });
|
|
208
|
+
await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000, env: augmentedEnv() });
|
|
208
209
|
spinnerPubGet.stop(t('update.pubGetDone'));
|
|
209
210
|
} catch {
|
|
210
211
|
spinnerPubGet.stop(`⚠ ${t('update.pubGetFailed')}`);
|
|
@@ -252,7 +253,7 @@ async function runUpdate(module, options = {}) {
|
|
|
252
253
|
const spinnerPubGet = ui.spinner({ color: paintLime });
|
|
253
254
|
spinnerPubGet.start(t('update.pubGet'));
|
|
254
255
|
try {
|
|
255
|
-
await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000 });
|
|
256
|
+
await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000, env: augmentedEnv() });
|
|
256
257
|
spinnerPubGet.stop(t('update.pubGetDone'));
|
|
257
258
|
} catch {
|
|
258
259
|
spinnerPubGet.stop(`⚠ ${t('update.pubGetFailed')}`);
|
|
@@ -365,7 +366,7 @@ async function runUpdate(module, options = {}) {
|
|
|
365
366
|
const spinner = ui.spinner({ color: paintLime });
|
|
366
367
|
spinner.start(t('update.pubGet'));
|
|
367
368
|
try {
|
|
368
|
-
await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000 });
|
|
369
|
+
await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000, env: augmentedEnv() });
|
|
369
370
|
spinner.stop(t('update.pubGetDone'));
|
|
370
371
|
} catch {
|
|
371
372
|
spinner.stop(`⚠ ${t('update.pubGetFailed')}`);
|
package/lib/utils/env-tools.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
const os = require('node:os');
|
|
20
20
|
const path = require('node:path');
|
|
21
21
|
const fs = require('node:fs');
|
|
22
|
+
const { spawn, spawnSync } = require('node:child_process');
|
|
22
23
|
|
|
23
24
|
const isWindows = process.platform === 'win32';
|
|
24
25
|
const PATH_SEP = isWindows ? ';' : ':';
|
|
@@ -179,6 +180,27 @@ function augmentedEnv(extraDirs = []) {
|
|
|
179
180
|
return env;
|
|
180
181
|
}
|
|
181
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Spawn `flutter <args>` cross-platform, with the (possibly freshly-installed)
|
|
185
|
+
* SDK exposed on PATH via augmentedEnv().
|
|
186
|
+
*
|
|
187
|
+
* On Windows `flutter` is a .bat, which Node's spawn() refuses to run without a
|
|
188
|
+
* shell. But passing an ARGS ARRAY *together with* shell:true triggers Node's
|
|
189
|
+
* DEP0190 deprecation warning — and that warning, emitted asynchronously while a
|
|
190
|
+
* Clack prompt is on screen, corrupts its redraw (the device picker shows up
|
|
191
|
+
* duplicated). So on Windows we build ONE command STRING and pass shell:true with
|
|
192
|
+
* no args array (no array + shell ⇒ no warning); on Unix we pass the plain args.
|
|
193
|
+
*/
|
|
194
|
+
function flutterSpawn(spawnFn, args, options = {}) {
|
|
195
|
+
const base = { env: augmentedEnv(), ...options };
|
|
196
|
+
if (!isWindows) return spawnFn('flutter', args, base);
|
|
197
|
+
const quoted = args.map((a) => (/\s/.test(a) ? `"${a}"` : a));
|
|
198
|
+
return spawnFn(['flutter', ...quoted].join(' '), { ...base, shell: true });
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const spawnFlutter = (args, options) => flutterSpawn(spawn, args, options);
|
|
202
|
+
const spawnSyncFlutter = (args, options) => flutterSpawn(spawnSync, args, options);
|
|
203
|
+
|
|
182
204
|
module.exports = {
|
|
183
205
|
isWindows,
|
|
184
206
|
homeDir,
|
|
@@ -186,4 +208,6 @@ module.exports = {
|
|
|
186
208
|
pubCacheBin,
|
|
187
209
|
keytoolBin,
|
|
188
210
|
augmentedEnv,
|
|
211
|
+
spawnFlutter,
|
|
212
|
+
spawnSyncFlutter,
|
|
189
213
|
};
|
package/lib/utils/flutter-run.js
CHANGED
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
|
|
29
29
|
const path = require('node:path');
|
|
30
30
|
const fs = require('node:fs');
|
|
31
|
-
const { spawn } = require('node:child_process');
|
|
32
31
|
const kleur = require('kleur');
|
|
33
32
|
const ui = require('./ui');
|
|
33
|
+
const { spawnFlutter } = require('./env-tools');
|
|
34
34
|
|
|
35
35
|
// Markers that tell us the initial build is done and the app is running.
|
|
36
36
|
const FLUTTER_READY_RE = /Flutter run key commands\.|is listening on|VM Service|Dart VM service|To hot reload|Hot restart/i;
|
|
@@ -140,7 +140,7 @@ function spawnFlutterWithSpinner(args, projectDir, t, options = {}) {
|
|
|
140
140
|
*/
|
|
141
141
|
function spawnRaw(args, projectDir, t, log, onReady) {
|
|
142
142
|
return new Promise((resolve, reject) => {
|
|
143
|
-
const proc =
|
|
143
|
+
const proc = spawnFlutter(args, {
|
|
144
144
|
cwd: projectDir,
|
|
145
145
|
stdio: ['inherit', 'pipe', 'pipe'],
|
|
146
146
|
});
|
|
@@ -192,7 +192,7 @@ function spawnRaw(args, projectDir, t, log, onReady) {
|
|
|
192
192
|
*/
|
|
193
193
|
function spawnWithSpinner(args, projectDir, t, log, onReady) {
|
|
194
194
|
return new Promise((resolve, reject) => {
|
|
195
|
-
const proc =
|
|
195
|
+
const proc = spawnFlutter(args, {
|
|
196
196
|
cwd: projectDir,
|
|
197
197
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
198
198
|
});
|
package/package.json
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import 'package:flutter/foundation.dart' show kReleaseMode;
|
|
1
2
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
|
2
3
|
|
|
3
4
|
const String _kEnvFromDefine = String.fromEnvironment(
|
|
@@ -16,6 +17,15 @@ const String _kRcAndroidApiKeyFromDefine = String.fromEnvironment(
|
|
|
16
17
|
const String _kRcIosApiKeyFromDefine = String.fromEnvironment(
|
|
17
18
|
'RC_IOS_API_KEY',
|
|
18
19
|
);
|
|
20
|
+
const String _kRcTestKeyFromDefine = String.fromEnvironment(
|
|
21
|
+
'RC_TEST_KEY',
|
|
22
|
+
);
|
|
23
|
+
const String _kRcIosProdKeyFromDefine = String.fromEnvironment(
|
|
24
|
+
'RC_IOS_PROD_KEY',
|
|
25
|
+
);
|
|
26
|
+
const String _kRcAndroidProdKeyFromDefine = String.fromEnvironment(
|
|
27
|
+
'RC_ANDROID_PROD_KEY',
|
|
28
|
+
);
|
|
19
29
|
const String _kMixpanelTokenFromDefine = String.fromEnvironment(
|
|
20
30
|
'MIXPANEL_TOKEN',
|
|
21
31
|
);
|
|
@@ -57,13 +67,43 @@ class AppEnv {
|
|
|
57
67
|
dartDefineValue: _kSupabaseTokenFromDefine,
|
|
58
68
|
);
|
|
59
69
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
/// RevenueCat "Test Store" public key (`test_…`). Works only against the
|
|
71
|
+
/// RevenueCat fake store (simulator/emulator); the native SDK rejects it in
|
|
72
|
+
/// release builds.
|
|
73
|
+
static String get rcTestKey =>
|
|
74
|
+
_resolve(key: 'RC_TEST_KEY', dartDefineValue: _kRcTestKeyFromDefine);
|
|
75
|
+
|
|
76
|
+
/// RevenueCat production/sandbox iOS key (`appl_…`) — the App Store key used
|
|
77
|
+
/// on physical devices, TestFlight and production.
|
|
78
|
+
static String get rcIosProdKey => _resolve(
|
|
79
|
+
key: 'RC_IOS_PROD_KEY',
|
|
80
|
+
dartDefineValue: _kRcIosProdKeyFromDefine,
|
|
63
81
|
);
|
|
64
82
|
|
|
65
|
-
|
|
66
|
-
|
|
83
|
+
/// RevenueCat production/sandbox Android key (`goog_…`) — the Play Store key
|
|
84
|
+
/// used on physical devices, internal testing and production.
|
|
85
|
+
static String get rcAndroidProdKey => _resolve(
|
|
86
|
+
key: 'RC_ANDROID_PROD_KEY',
|
|
87
|
+
dartDefineValue: _kRcAndroidProdKeyFromDefine,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
/// Effective RevenueCat key for Android, resolved for the current build.
|
|
91
|
+
static String get rcAndroidApiKey => _resolveRcKey(
|
|
92
|
+
explicit: _resolve(
|
|
93
|
+
key: 'RC_ANDROID_API_KEY',
|
|
94
|
+
dartDefineValue: _kRcAndroidApiKeyFromDefine,
|
|
95
|
+
),
|
|
96
|
+
prodKey: rcAndroidProdKey,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
/// Effective RevenueCat key for iOS, resolved for the current build.
|
|
100
|
+
static String get rcIosApiKey => _resolveRcKey(
|
|
101
|
+
explicit: _resolve(
|
|
102
|
+
key: 'RC_IOS_API_KEY',
|
|
103
|
+
dartDefineValue: _kRcIosApiKeyFromDefine,
|
|
104
|
+
),
|
|
105
|
+
prodKey: rcIosProdKey,
|
|
106
|
+
);
|
|
67
107
|
|
|
68
108
|
static String get mixpanelToken => _resolve(
|
|
69
109
|
key: 'MIXPANEL_TOKEN',
|
|
@@ -91,4 +131,36 @@ class AppEnv {
|
|
|
91
131
|
if (dartDefineValue.isNotEmpty) return dartDefineValue;
|
|
92
132
|
return defaultValue;
|
|
93
133
|
}
|
|
134
|
+
|
|
135
|
+
/// Resolve the RevenueCat key that actually works for the current build.
|
|
136
|
+
///
|
|
137
|
+
/// A Test Store key (`test_…`) only works against RevenueCat's fake store
|
|
138
|
+
/// (simulator/emulator); the native SDK refuses it in release builds and the
|
|
139
|
+
/// paywall comes up empty. So:
|
|
140
|
+
///
|
|
141
|
+
/// - Release builds (TestFlight / App Store / Play Store) always use the
|
|
142
|
+
/// production key (`appl_…` / `goog_…`), read from the bundled `.env`
|
|
143
|
+
/// (`RC_IOS_PROD_KEY` / `RC_ANDROID_PROD_KEY`). Because `.env` ships as an
|
|
144
|
+
/// asset, this holds no matter how the IPA/AAB was built (`kasy ios
|
|
145
|
+
/// release`, Xcode archive, Codemagic, `flutter build …`). An explicit
|
|
146
|
+
/// non-test key (injected by `kasy run` on a device, or by Codemagic
|
|
147
|
+
/// variable groups) still wins.
|
|
148
|
+
/// - Debug builds honor whatever `kasy run` injected (`test_` for
|
|
149
|
+
/// simulators, the prod key for physical devices) and fall back to the
|
|
150
|
+
/// Test Store key.
|
|
151
|
+
static String _resolveRcKey({
|
|
152
|
+
required String explicit,
|
|
153
|
+
required String prodKey,
|
|
154
|
+
}) {
|
|
155
|
+
final bool explicitIsTest = explicit.startsWith('test_');
|
|
156
|
+
if (kReleaseMode) {
|
|
157
|
+
if (explicit.isNotEmpty && !explicitIsTest) return explicit;
|
|
158
|
+
if (prodKey.isNotEmpty) return prodKey;
|
|
159
|
+
return explicit;
|
|
160
|
+
}
|
|
161
|
+
if (explicit.isNotEmpty) return explicit;
|
|
162
|
+
final String test = rcTestKey;
|
|
163
|
+
if (test.isNotEmpty) return test;
|
|
164
|
+
return prodKey;
|
|
165
|
+
}
|
|
94
166
|
}
|
|
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|
|
16
16
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
|
17
17
|
# In Windows, build-name is used as the major, minor, and patch parts
|
|
18
18
|
# of the product and file versions while build-number is used as the build suffix.
|
|
19
|
-
version: 1.0.0+
|
|
19
|
+
version: 1.0.0+36
|
|
20
20
|
|
|
21
21
|
environment:
|
|
22
22
|
sdk: ^3.11.0
|