kasy-cli 1.21.4 → 1.21.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/new.js
CHANGED
|
@@ -44,7 +44,7 @@ const { generateApiProject } = require('../scaffold/backends/api/generator');
|
|
|
44
44
|
const { createProjectAndGetKeys, setupLinkedProject, checkLoggedIn, getOrgsList, getProjectsByOrg, getProjectKeys } = require('../scaffold/backends/supabase/deploy');
|
|
45
45
|
const { writeSupabaseGoogleAuthOptions, readSupabaseGoogleCredentials, getGoogleClientSecretViaGcloud, flutterfireConfigure, writeGoogleAuthOptions, writeGoogleIosUrlScheme, writeGoogleIosUrlSchemeFromClientId } = require('../scaffold/shared/post-build');
|
|
46
46
|
const { toPackageName } = require('../scaffold/backends/firebase/tokens');
|
|
47
|
-
const { setupFromScratch, setupExistingProject, listBillingAccounts, listGcpOrganizations, checkGcloudAuth, getGcloudInstallInstructions, enableAuthProviders, registerDebugSha1 } = require('../scaffold/backends/firebase/setup-from-scratch');
|
|
47
|
+
const { setupFromScratch, setupExistingProject, listBillingAccounts, listGcpOrganizations, checkGcloudAuth, getFirebaseAccount, getGcloudInstallInstructions, enableAuthProviders, registerDebugSha1 } = require('../scaffold/backends/firebase/setup-from-scratch');
|
|
48
48
|
const { enableAuthViaFirebaseCli } = require('../scaffold/backends/firebase/enable-auth-via-cli');
|
|
49
49
|
const { createFcmServiceAccountKey } = require('../scaffold/shared/fcm-service-account');
|
|
50
50
|
|
|
@@ -123,6 +123,42 @@ async function promptOrganizationIfNeeded(tr, onCancel) {
|
|
|
123
123
|
|
|
124
124
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
125
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Before creating any cloud project, show WHICH account each service is logged
|
|
128
|
+
* in as (gcloud, Firebase, and Supabase when relevant), so the user never
|
|
129
|
+
* creates the project on the wrong account. Warns if gcloud and Firebase are
|
|
130
|
+
* different accounts (a common cause of mid-flow failures), and lets the user
|
|
131
|
+
* bail out with the exact commands to switch.
|
|
132
|
+
*/
|
|
133
|
+
async function confirmIdentities(backend, gcloudAccount, tr, cancel) {
|
|
134
|
+
const firebaseAccount = await getFirebaseAccount();
|
|
135
|
+
const notLogged = kleur.yellow(tr('new.accounts.notLoggedIn'));
|
|
136
|
+
const lines = [
|
|
137
|
+
`🔑 Google Cloud: ${gcloudAccount ? kleur.cyan(gcloudAccount) : notLogged}`,
|
|
138
|
+
`🔥 Firebase: ${firebaseAccount ? kleur.cyan(firebaseAccount) : notLogged}`,
|
|
139
|
+
];
|
|
140
|
+
if (backend === 'supabase') {
|
|
141
|
+
const sb = await checkLoggedIn();
|
|
142
|
+
lines.push(`🟢 Supabase: ${sb.ok ? kleur.cyan(tr('new.accounts.connected')) : notLogged}`);
|
|
143
|
+
}
|
|
144
|
+
if (gcloudAccount && firebaseAccount && gcloudAccount !== firebaseAccount) {
|
|
145
|
+
lines.push('', kleur.yellow(`⚠ ${tr('new.accounts.mismatch')}`));
|
|
146
|
+
}
|
|
147
|
+
ui.note(lines.join('\n'), tr('new.accounts.title'));
|
|
148
|
+
|
|
149
|
+
const ok = await ui.confirm({ message: tr('new.accounts.confirm'), initialValue: true, onCancel: cancel });
|
|
150
|
+
if (!ok) {
|
|
151
|
+
const sw = [
|
|
152
|
+
`🔑 gcloud: ${kleur.cyan('gcloud auth login')}`,
|
|
153
|
+
`🔥 Firebase: ${kleur.cyan('firebase login --reauth')}`,
|
|
154
|
+
];
|
|
155
|
+
if (backend === 'supabase') sw.push(`🟢 Supabase: ${kleur.cyan('supabase login')}`);
|
|
156
|
+
ui.note(sw.join('\n'), tr('new.accounts.switchTitle'));
|
|
157
|
+
ui.cancel(tr('new.accounts.rerun'));
|
|
158
|
+
process.exit(0);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
126
162
|
function printPrerequisites(tr, backend, firebaseSetupMode = 'existing', checkResults = []) {
|
|
127
163
|
const gcloudOk = checkResults.every(
|
|
128
164
|
(r) => !r.name?.includes('gcloud') || r.ok
|
|
@@ -580,6 +616,10 @@ async function runNew(directory, { language: langHint = null, backend: backendHi
|
|
|
580
616
|
process.exit(1);
|
|
581
617
|
}
|
|
582
618
|
|
|
619
|
+
// Show which account each service is logged in as before creating anything,
|
|
620
|
+
// so the project never lands on the wrong account.
|
|
621
|
+
await confirmIdentities(backend, gcloudCheck.account, tr, cancel);
|
|
622
|
+
|
|
583
623
|
// ── Billing account check — Firebase needs an active billing account (Blaze) ─
|
|
584
624
|
// Without it, project creation succeeds but Storage and Cloud Functions fail later.
|
|
585
625
|
// Catching it here saves the user from a confusing mid-flow error.
|
|
@@ -49,6 +49,16 @@ const REQUIRED_APIS = [
|
|
|
49
49
|
'logging.googleapis.com', // Cloud Logging (Cloud Build writes build logs here)
|
|
50
50
|
];
|
|
51
51
|
|
|
52
|
+
// fcmOnly (Supabase/API): only the APIs needed for push + Google Sign-In, all
|
|
53
|
+
// of which work on the free Spark plan. Crucially NONE of these require billing
|
|
54
|
+
// — the heavy Cloud Run/Functions/Build/Compute APIs above all demand Blaze.
|
|
55
|
+
const FCM_ONLY_APIS = [
|
|
56
|
+
'firebase.googleapis.com', // Firebase Management (addFirebase)
|
|
57
|
+
'identitytoolkit.googleapis.com', // Firebase Auth / Google Sign-In
|
|
58
|
+
'fcm.googleapis.com', // Cloud Messaging (push) — free
|
|
59
|
+
'iam.googleapis.com', // service accounts (the FCM admin key)
|
|
60
|
+
];
|
|
61
|
+
|
|
52
62
|
async function run(cmd, cwd = process.cwd()) {
|
|
53
63
|
try {
|
|
54
64
|
const { stdout, stderr } = await execAsync(cmd, {
|
|
@@ -98,7 +108,16 @@ async function checkGcloudAuth() {
|
|
|
98
108
|
const auth = await run('gcloud auth print-access-token');
|
|
99
109
|
if (!auth.ok) return { ok: false, error: 'Not logged in. Run: gcloud auth login', missing: 'auth' };
|
|
100
110
|
|
|
101
|
-
|
|
111
|
+
const acct = await run('gcloud config get-value account');
|
|
112
|
+
return { ok: true, account: acct.ok ? acct.stdout.trim() : null };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** The Google account the Firebase CLI is logged in as, or null. */
|
|
116
|
+
async function getFirebaseAccount() {
|
|
117
|
+
const r = await run('firebase login:list');
|
|
118
|
+
if (!r.ok) return null;
|
|
119
|
+
const m = (r.stdout || '').match(/Logged in as ([^\s@]+@[^\s]+)/);
|
|
120
|
+
return m ? m[1] : null;
|
|
102
121
|
}
|
|
103
122
|
|
|
104
123
|
/**
|
|
@@ -382,8 +401,8 @@ async function applyStorageCors(projectId, options = {}) {
|
|
|
382
401
|
/**
|
|
383
402
|
* Enable required Google Cloud APIs.
|
|
384
403
|
*/
|
|
385
|
-
async function enableApis(projectId) {
|
|
386
|
-
const apis = REQUIRED_APIS.join(' ');
|
|
404
|
+
async function enableApis(projectId, fcmOnly = false) {
|
|
405
|
+
const apis = (fcmOnly ? FCM_ONLY_APIS : REQUIRED_APIS).join(' ');
|
|
387
406
|
const result = await run(`gcloud services enable ${apis} --project=${projectId}`);
|
|
388
407
|
if (!result.ok) {
|
|
389
408
|
return { ok: false, error: result.stderr || result.error };
|
|
@@ -954,7 +973,7 @@ async function setupFromScratch(appName, bundleId, options = {}) {
|
|
|
954
973
|
}
|
|
955
974
|
|
|
956
975
|
onProgress('enable-apis');
|
|
957
|
-
const apisResult = await enableApis(projectId);
|
|
976
|
+
const apisResult = await enableApis(projectId, fcmOnly);
|
|
958
977
|
if (!apisResult.ok) return { ok: false, error: apisResult.error };
|
|
959
978
|
|
|
960
979
|
// Set ADC quota project so Firebase REST API calls (createAndroidApp etc.) work with user credentials.
|
|
@@ -1222,6 +1241,7 @@ module.exports = {
|
|
|
1222
1241
|
listBillingAccounts,
|
|
1223
1242
|
listGcpOrganizations,
|
|
1224
1243
|
checkGcloudAuth,
|
|
1244
|
+
getFirebaseAccount,
|
|
1225
1245
|
getGcloudInstallInstructions,
|
|
1226
1246
|
generateProjectId,
|
|
1227
1247
|
extractSha1,
|
|
@@ -216,6 +216,13 @@ module.exports = {
|
|
|
216
216
|
'new.firebase.create.success': 'Firebase project created successfully.',
|
|
217
217
|
'new.firebase.create.failed': 'Could not create project',
|
|
218
218
|
'new.firebase.create.gcloudRequired': 'gcloud CLI is required for "create from scratch". Without it, the full Firebase flow cannot run.',
|
|
219
|
+
'new.accounts.title': 'Connected accounts (where the project will be created)',
|
|
220
|
+
'new.accounts.notLoggedIn': 'not connected',
|
|
221
|
+
'new.accounts.connected': 'connected',
|
|
222
|
+
'new.accounts.mismatch': 'gcloud and Firebase are on different accounts: this can fail while creating the project.',
|
|
223
|
+
'new.accounts.confirm': 'Create the project on these accounts?',
|
|
224
|
+
'new.accounts.switchTitle': 'To switch accounts, run and try again:',
|
|
225
|
+
'new.accounts.rerun': 'Switch the account and run `kasy new` again.',
|
|
219
226
|
'new.firebase.billing.required': 'You do not have a billing account on Google Cloud yet. Firebase needs the Blaze plan to use Storage and Cloud Functions.',
|
|
220
227
|
'new.firebase.billing.create.steps': 'Opening the billing account creation page. Create the account (credit card required, no charges within the free quota) and come back here:',
|
|
221
228
|
'new.firebase.billing.created.ready': 'I created the billing account, ready to continue?',
|
|
@@ -216,6 +216,13 @@ module.exports = {
|
|
|
216
216
|
'new.firebase.create.success': 'Proyecto Firebase creado correctamente.',
|
|
217
217
|
'new.firebase.create.failed': 'No se pudo crear el proyecto',
|
|
218
218
|
'new.firebase.create.gcloudRequired': 'gcloud CLI es obligatorio para "crear desde cero". Sin él, el flujo completo de Firebase no puede ejecutarse.',
|
|
219
|
+
'new.accounts.title': 'Cuentas conectadas (donde se creará el proyecto)',
|
|
220
|
+
'new.accounts.notLoggedIn': 'no conectado',
|
|
221
|
+
'new.accounts.connected': 'conectado',
|
|
222
|
+
'new.accounts.mismatch': 'gcloud y Firebase están en cuentas distintas: esto puede fallar al crear el proyecto.',
|
|
223
|
+
'new.accounts.confirm': '¿Crear el proyecto en estas cuentas?',
|
|
224
|
+
'new.accounts.switchTitle': 'Para cambiar de cuenta, ejecuta y prueba de nuevo:',
|
|
225
|
+
'new.accounts.rerun': 'Cambia la cuenta y ejecuta `kasy new` de nuevo.',
|
|
219
226
|
'new.firebase.billing.required': 'Aún no tienes una cuenta de facturación en Google Cloud. Firebase necesita el plan Blaze para usar Storage y Cloud Functions.',
|
|
220
227
|
'new.firebase.billing.create.steps': 'Abriendo la página de creación de cuenta de facturación. Crea la cuenta (tarjeta de crédito requerida, sin cargos dentro de la cuota gratuita) y vuelve aquí:',
|
|
221
228
|
'new.firebase.billing.created.ready': 'Ya creé la cuenta de facturación, ¿puedo continuar?',
|
|
@@ -216,6 +216,13 @@ module.exports = {
|
|
|
216
216
|
'new.firebase.create.success': 'Projeto Firebase criado com sucesso.',
|
|
217
217
|
'new.firebase.create.failed': 'Não foi possível criar o projeto',
|
|
218
218
|
'new.firebase.create.gcloudRequired': 'gcloud CLI é obrigatório para "criar do zero". Sem ele, o fluxo completo do Firebase não pode rodar.',
|
|
219
|
+
'new.accounts.title': 'Contas conectadas (onde o projeto será criado)',
|
|
220
|
+
'new.accounts.notLoggedIn': 'não conectado',
|
|
221
|
+
'new.accounts.connected': 'conectado',
|
|
222
|
+
'new.accounts.mismatch': 'gcloud e Firebase estão em contas diferentes: isso pode falhar ao criar o projeto.',
|
|
223
|
+
'new.accounts.confirm': 'É nessas contas que você quer criar o projeto?',
|
|
224
|
+
'new.accounts.switchTitle': 'Para trocar de conta, rode e tente de novo:',
|
|
225
|
+
'new.accounts.rerun': 'Troque a conta e rode `kasy new` novamente.',
|
|
219
226
|
'new.firebase.billing.required': 'Você ainda não tem uma conta de faturamento no Google Cloud. O Firebase precisa do plano Blaze para usar Storage e Cloud Functions.',
|
|
220
227
|
'new.firebase.billing.create.steps': 'Vou abrir a página de criação de conta de faturamento. Crie a conta (cartão de crédito, sem cobrança até bater a cota gratuita) e volte aqui:',
|
|
221
228
|
'new.firebase.billing.created.ready': 'Já criei a conta de faturamento, pode seguir?',
|