@hot-updater/firebase 0.35.7 → 0.35.9
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/dist/firebase/functions/index.cjs +1 -1
- package/dist/iac/index.cjs +392 -214
- package/dist/iac/index.d.cts +4 -5
- package/dist/iac/index.d.mts +4 -5
- package/dist/iac/index.mjs +385 -208
- package/dist/init/index.cjs +43 -0
- package/dist/init/index.d.cts +40 -0
- package/dist/init/index.d.mts +40 -0
- package/dist/init/index.mjs +40 -0
- package/package.json +13 -8
package/dist/iac/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import { ConfigBuilder, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, copyDirToTmp, createHotUpdaterConfigScaffoldFromBuilder, link, makeEnv, p, resolveHotUpdaterServerVersion, resolvePackageVersion, transformEnv, transformTemplate, writeHotUpdaterConfig } from "@hot-updater/cli-tools";
|
|
4
|
+
import { ConfigBuilder, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, MissingInitInputsError, assertInitProviderInputs, confirmInitInputPersistence, copyDirToTmp, createHotUpdaterConfigScaffoldFromBuilder, getHotUpdaterInitInputEnv, getInitProviderEnvVars, getInitProviderTextPromptValues, link, makeEnv, p, readHotUpdaterInitEnv, resolveHotUpdaterServerVersion, resolveInitProviderInput, resolvePackageVersion, transformEnv, transformTemplate, writeHotUpdaterConfig } from "@hot-updater/cli-tools";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { ChildProcess, execFile, spawn, spawnSync } from "node:child_process";
|
|
7
7
|
import { StringDecoder } from "node:string_decoder";
|
|
@@ -10,7 +10,7 @@ import process$1, { execArgv, execPath, hrtime, platform } from "node:process";
|
|
|
10
10
|
import tty from "node:tty";
|
|
11
11
|
import path$1 from "node:path";
|
|
12
12
|
import { scheduler, setImmediate, setTimeout } from "node:timers/promises";
|
|
13
|
-
import { constants } from "node:os";
|
|
13
|
+
import os, { constants } from "node:os";
|
|
14
14
|
import { EventEmitter, addAbortListener, on, once, setMaxListeners } from "node:events";
|
|
15
15
|
import { serialize } from "node:v8";
|
|
16
16
|
import { appendFileSync, createReadStream, createWriteStream, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
@@ -6706,6 +6706,212 @@ createExeca(mapNode);
|
|
|
6706
6706
|
createExeca(mapScriptAsync, {}, deepScriptOptions, setScriptSync);
|
|
6707
6707
|
const { sendMessage, getOneMessage, getEachMessage, getCancelSignal } = getIpcExport();
|
|
6708
6708
|
//#endregion
|
|
6709
|
+
//#region iac/init/index.ts
|
|
6710
|
+
const isFirebaseRegion = (value) => value !== void 0 && /^[a-z]+(?:-[a-z]+)+[0-9]+$/.test(value);
|
|
6711
|
+
const isFirebaseProjectId = (value) => value !== void 0 && /^[a-z][a-z0-9-]{4,28}[a-z0-9]$/.test(value);
|
|
6712
|
+
const initProvider = {
|
|
6713
|
+
label: "Firebase",
|
|
6714
|
+
inputs: {
|
|
6715
|
+
projectId: {
|
|
6716
|
+
envKey: "HOT_UPDATER_FIREBASE_PROJECT_ID",
|
|
6717
|
+
help: "Firebase project ID",
|
|
6718
|
+
prompt: {
|
|
6719
|
+
message: "Enter the Firebase project ID:",
|
|
6720
|
+
placeholder: "hot-updater-app",
|
|
6721
|
+
type: "text"
|
|
6722
|
+
},
|
|
6723
|
+
validate: isFirebaseProjectId
|
|
6724
|
+
},
|
|
6725
|
+
region: {
|
|
6726
|
+
envKey: "HOT_UPDATER_FIREBASE_REGION",
|
|
6727
|
+
help: "Firebase Functions region",
|
|
6728
|
+
prompt: {
|
|
6729
|
+
message: "Select Region",
|
|
6730
|
+
type: "select"
|
|
6731
|
+
},
|
|
6732
|
+
validate: isFirebaseRegion
|
|
6733
|
+
},
|
|
6734
|
+
applicationCredentials: {
|
|
6735
|
+
envKey: "GOOGLE_APPLICATION_CREDENTIALS",
|
|
6736
|
+
help: "Service account JSON path",
|
|
6737
|
+
optional: true,
|
|
6738
|
+
persistence: "with-consent",
|
|
6739
|
+
prompt: {
|
|
6740
|
+
message: "Enter the service account JSON path (press Enter to configure later)",
|
|
6741
|
+
placeholder: "~/Downloads/firebase-service-account.json",
|
|
6742
|
+
type: "text"
|
|
6743
|
+
}
|
|
6744
|
+
}
|
|
6745
|
+
}
|
|
6746
|
+
};
|
|
6747
|
+
//#endregion
|
|
6748
|
+
//#region iac/firebaseApplicationCredentials.ts
|
|
6749
|
+
const inputFirebaseApplicationCredentials = async ({ applicationCredentials, nonInteractive, projectId }) => {
|
|
6750
|
+
if (nonInteractive) return applicationCredentials;
|
|
6751
|
+
const prompt = initProvider.inputs.applicationCredentials.prompt;
|
|
6752
|
+
p.log.step(`Service account JSON: ${link(`https://console.firebase.google.com/project/${projectId}/settings/serviceaccounts/adminsdk`)}`);
|
|
6753
|
+
p.log.step("Project settings > Service accounts > Generate new private key");
|
|
6754
|
+
const credentialsPath = await p.text({
|
|
6755
|
+
...getInitProviderTextPromptValues(prompt, applicationCredentials),
|
|
6756
|
+
message: prompt.message
|
|
6757
|
+
});
|
|
6758
|
+
if (p.isCancel(credentialsPath)) process.exit(1);
|
|
6759
|
+
return credentialsPath || void 0;
|
|
6760
|
+
};
|
|
6761
|
+
//#endregion
|
|
6762
|
+
//#region iac/firebaseInitInputs.ts
|
|
6763
|
+
const resolveFirebaseCredentialsPath = (credentialsPath, { cwd = process.cwd(), homeDir = os.homedir(), pathApi = path$1 }) => {
|
|
6764
|
+
const homeRelativePath = credentialsPath === "~" ? "" : credentialsPath.startsWith("~/") || credentialsPath.startsWith("~\\") ? credentialsPath.slice(2) : void 0;
|
|
6765
|
+
return homeRelativePath === void 0 ? pathApi.resolve(cwd, credentialsPath) : pathApi.resolve(homeDir, homeRelativePath);
|
|
6766
|
+
};
|
|
6767
|
+
const getFirebaseCliEnv = (applicationCredentials, pathContext = {}) => {
|
|
6768
|
+
if (!applicationCredentials) return;
|
|
6769
|
+
const resolvedCredentialsPath = resolveFirebaseCredentialsPath(applicationCredentials, pathContext);
|
|
6770
|
+
return { [initProvider.inputs.applicationCredentials.envKey]: resolvedCredentialsPath };
|
|
6771
|
+
};
|
|
6772
|
+
const resolveFirebaseInitInputs = (existingEnv) => {
|
|
6773
|
+
const { inputs } = initProvider;
|
|
6774
|
+
const applicationCredentials = resolveInitProviderInput(existingEnv, inputs.applicationCredentials);
|
|
6775
|
+
return {
|
|
6776
|
+
applicationCredentials: applicationCredentials === "your-credentials.json" ? void 0 : applicationCredentials,
|
|
6777
|
+
projectId: resolveInitProviderInput(existingEnv, inputs.projectId),
|
|
6778
|
+
region: resolveInitProviderInput(existingEnv, inputs.region)
|
|
6779
|
+
};
|
|
6780
|
+
};
|
|
6781
|
+
const assertFirebaseNonInteractiveInputs = (inputs, nonInteractive = false) => {
|
|
6782
|
+
assertInitProviderInputs({
|
|
6783
|
+
inputs,
|
|
6784
|
+
provider: initProvider,
|
|
6785
|
+
strict: nonInteractive
|
|
6786
|
+
});
|
|
6787
|
+
};
|
|
6788
|
+
//#endregion
|
|
6789
|
+
//#region iac/firebaseRegion.ts
|
|
6790
|
+
const REGIONS = [
|
|
6791
|
+
{
|
|
6792
|
+
value: "us-central1",
|
|
6793
|
+
label: "US Central (Iowa)"
|
|
6794
|
+
},
|
|
6795
|
+
{
|
|
6796
|
+
value: "us-east1",
|
|
6797
|
+
label: "US East (South Carolina)"
|
|
6798
|
+
},
|
|
6799
|
+
{
|
|
6800
|
+
value: "us-east4",
|
|
6801
|
+
label: "US East (Northern Virginia)"
|
|
6802
|
+
},
|
|
6803
|
+
{
|
|
6804
|
+
value: "us-west1",
|
|
6805
|
+
label: "US West (Oregon)"
|
|
6806
|
+
},
|
|
6807
|
+
{
|
|
6808
|
+
value: "us-west2",
|
|
6809
|
+
label: "US West (Los Angeles)"
|
|
6810
|
+
},
|
|
6811
|
+
{
|
|
6812
|
+
value: "us-west3",
|
|
6813
|
+
label: "US West (Salt Lake City)"
|
|
6814
|
+
},
|
|
6815
|
+
{
|
|
6816
|
+
value: "us-west4",
|
|
6817
|
+
label: "US West (Las Vegas)"
|
|
6818
|
+
},
|
|
6819
|
+
{
|
|
6820
|
+
value: "europe-west1",
|
|
6821
|
+
label: "Europe West (Belgium)"
|
|
6822
|
+
},
|
|
6823
|
+
{
|
|
6824
|
+
value: "europe-west2",
|
|
6825
|
+
label: "Europe West (London)"
|
|
6826
|
+
},
|
|
6827
|
+
{
|
|
6828
|
+
value: "europe-west3",
|
|
6829
|
+
label: "Europe West (Frankfurt)"
|
|
6830
|
+
},
|
|
6831
|
+
{
|
|
6832
|
+
value: "europe-west6",
|
|
6833
|
+
label: "Europe West (Zurich)"
|
|
6834
|
+
},
|
|
6835
|
+
{
|
|
6836
|
+
value: "asia-east1",
|
|
6837
|
+
label: "Asia East (Taiwan)"
|
|
6838
|
+
},
|
|
6839
|
+
{
|
|
6840
|
+
value: "asia-east2",
|
|
6841
|
+
label: "Asia East (Hong Kong)"
|
|
6842
|
+
},
|
|
6843
|
+
{
|
|
6844
|
+
value: "asia-northeast1",
|
|
6845
|
+
label: "Asia Northeast (Tokyo)"
|
|
6846
|
+
},
|
|
6847
|
+
{
|
|
6848
|
+
value: "asia-northeast2",
|
|
6849
|
+
label: "Asia Northeast (Osaka)"
|
|
6850
|
+
},
|
|
6851
|
+
{
|
|
6852
|
+
value: "asia-northeast3",
|
|
6853
|
+
label: "Asia Northeast (Seoul)"
|
|
6854
|
+
},
|
|
6855
|
+
{
|
|
6856
|
+
value: "asia-south1",
|
|
6857
|
+
label: "Asia South (Mumbai)"
|
|
6858
|
+
},
|
|
6859
|
+
{
|
|
6860
|
+
value: "asia-southeast1",
|
|
6861
|
+
label: "Asia Southeast (Singapore)"
|
|
6862
|
+
},
|
|
6863
|
+
{
|
|
6864
|
+
value: "asia-southeast2",
|
|
6865
|
+
label: "Asia Southeast (Jakarta)"
|
|
6866
|
+
},
|
|
6867
|
+
{
|
|
6868
|
+
value: "australia-southeast1",
|
|
6869
|
+
label: "Australia Southeast (Sydney)"
|
|
6870
|
+
}
|
|
6871
|
+
];
|
|
6872
|
+
const resolveFirebaseRegion = async ({ cwd, discoverExistingProject = true, nonInteractive, savedRegion, cliEnv }) => {
|
|
6873
|
+
if (nonInteractive) {
|
|
6874
|
+
if (isFirebaseRegion(savedRegion)) return savedRegion;
|
|
6875
|
+
throw new MissingInitInputsError(["HOT_UPDATER_FIREBASE_REGION"]);
|
|
6876
|
+
}
|
|
6877
|
+
let discoveredRegion;
|
|
6878
|
+
if (discoverExistingProject) {
|
|
6879
|
+
const functionsList = await execa("npx", [
|
|
6880
|
+
"firebase",
|
|
6881
|
+
"functions:list",
|
|
6882
|
+
"--json"
|
|
6883
|
+
], {
|
|
6884
|
+
cwd,
|
|
6885
|
+
env: cliEnv,
|
|
6886
|
+
reject: false
|
|
6887
|
+
});
|
|
6888
|
+
if (functionsList.exitCode === 0) {
|
|
6889
|
+
const parsed = JSON.parse(functionsList.stdout);
|
|
6890
|
+
if (typeof parsed === "object" && parsed !== null && "result" in parsed && Array.isArray(parsed.result)) {
|
|
6891
|
+
for (const entry of parsed.result) if (typeof entry === "object" && entry !== null && "id" in entry && entry.id === "hot-updater" && "region" in entry && typeof entry.region === "string") {
|
|
6892
|
+
discoveredRegion = entry.region;
|
|
6893
|
+
break;
|
|
6894
|
+
}
|
|
6895
|
+
}
|
|
6896
|
+
}
|
|
6897
|
+
}
|
|
6898
|
+
const initialRegion = isFirebaseRegion(savedRegion) ? savedRegion : isFirebaseRegion(discoveredRegion) ? discoveredRegion : REGIONS[0].value;
|
|
6899
|
+
const options = REGIONS.some((region) => region.value === initialRegion) ? REGIONS : [{
|
|
6900
|
+
value: initialRegion,
|
|
6901
|
+
label: `Existing (${initialRegion})`
|
|
6902
|
+
}, ...REGIONS];
|
|
6903
|
+
const selectedRegion = await p.select({
|
|
6904
|
+
initialValue: initialRegion,
|
|
6905
|
+
message: initProvider.inputs.region.prompt.message,
|
|
6906
|
+
options
|
|
6907
|
+
});
|
|
6908
|
+
if (p.isCancel(selectedRegion)) {
|
|
6909
|
+
p.cancel("Operation cancelled.");
|
|
6910
|
+
process.exit(1);
|
|
6911
|
+
}
|
|
6912
|
+
return selectedRegion;
|
|
6913
|
+
};
|
|
6914
|
+
//#endregion
|
|
6709
6915
|
//#region iac/prepareTemplate.ts
|
|
6710
6916
|
const ensureExists = async (targetPath, description) => {
|
|
6711
6917
|
try {
|
|
@@ -6778,15 +6984,16 @@ const credential = admin.credential.applicationDefault();`.trim()
|
|
|
6778
6984
|
defaultOrNamespace: "admin"
|
|
6779
6985
|
}).setIntermediateCode(helperStatements.map((statement) => statement.code.trim()).join("\n\n")), { helperStatements });
|
|
6780
6986
|
};
|
|
6781
|
-
const setEnv = async ({ projectId, storageBucket, build }) => {
|
|
6987
|
+
const setEnv = async ({ applicationCredentials, projectId, storageBucket, build, region }) => {
|
|
6782
6988
|
await makeEnv({
|
|
6783
|
-
|
|
6989
|
+
[initProvider.inputs.applicationCredentials.envKey]: {
|
|
6784
6990
|
comment: "Project Settings > Service Accounts > New Private Key > Download JSON",
|
|
6785
|
-
value: "your-credentials.json"
|
|
6991
|
+
value: applicationCredentials ?? "your-credentials.json"
|
|
6786
6992
|
},
|
|
6787
|
-
|
|
6993
|
+
[initProvider.inputs.projectId.envKey]: projectId,
|
|
6994
|
+
[initProvider.inputs.region.envKey]: region,
|
|
6788
6995
|
HOT_UPDATER_FIREBASE_STORAGE_BUCKET: storageBucket
|
|
6789
|
-
}, ".env.hotupdater", { preserveKeys: [
|
|
6996
|
+
}, ".env.hotupdater", { preserveKeys: applicationCredentials ? [] : [initProvider.inputs.applicationCredentials.envKey] });
|
|
6790
6997
|
p.log.success("Firebase credentials have been successfully configured.");
|
|
6791
6998
|
try {
|
|
6792
6999
|
const configWriteResult = await writeHotUpdaterConfig(getConfigScaffold(build));
|
|
@@ -6794,7 +7001,8 @@ const setEnv = async ({ projectId, storageBucket, build }) => {
|
|
|
6794
7001
|
else if (configWriteResult.status === "merged") p.log.success("Configuration file 'hot-updater.config.ts' has been updated.");
|
|
6795
7002
|
else p.log.warn(`Existing 'hot-updater.config.ts' was left unchanged: ${configWriteResult.reason}`);
|
|
6796
7003
|
} catch (error) {
|
|
6797
|
-
|
|
7004
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7005
|
+
console.error("Error writing configuration file:", message);
|
|
6798
7006
|
}
|
|
6799
7007
|
};
|
|
6800
7008
|
const handleError = (err) => {
|
|
@@ -6802,43 +7010,81 @@ const handleError = (err) => {
|
|
|
6802
7010
|
else if (err instanceof Error) p.log.error(`Error occurred: ${err.message}`);
|
|
6803
7011
|
process.exit(1);
|
|
6804
7012
|
};
|
|
6805
|
-
const
|
|
7013
|
+
const createFirebaseProject = async ({ cliEnv, projectId }) => {
|
|
7014
|
+
if (!isFirebaseProjectId(projectId)) throw new Error(`Invalid Firebase project ID: ${projectId}`);
|
|
7015
|
+
try {
|
|
7016
|
+
await execa("npx", [
|
|
7017
|
+
"firebase",
|
|
7018
|
+
"projects:create",
|
|
7019
|
+
`--display-name=${projectId}`,
|
|
7020
|
+
"--non-interactive",
|
|
7021
|
+
"--",
|
|
7022
|
+
projectId
|
|
7023
|
+
], {
|
|
7024
|
+
env: cliEnv,
|
|
7025
|
+
stdio: "inherit"
|
|
7026
|
+
});
|
|
7027
|
+
} catch (error) {
|
|
7028
|
+
handleError(error instanceof Error ? error : new Error(String(error)));
|
|
7029
|
+
}
|
|
7030
|
+
p.log.success("Firebase project created successfully");
|
|
7031
|
+
p.log.step("Enable Firestore, Storage, and Billing before running init again:");
|
|
7032
|
+
p.log.step(link(`https://console.firebase.google.com/project/${projectId}/firestore`));
|
|
7033
|
+
p.log.step(link(`https://console.firebase.google.com/project/${projectId}/storage`));
|
|
7034
|
+
};
|
|
7035
|
+
const listProjects = async (nonInteractive = false, cliEnv) => {
|
|
6806
7036
|
try {
|
|
6807
7037
|
const projects = await execa("npx", [
|
|
6808
7038
|
"firebase",
|
|
6809
7039
|
"projects:list",
|
|
6810
|
-
"--json"
|
|
6811
|
-
|
|
7040
|
+
"--json",
|
|
7041
|
+
...nonInteractive ? ["--non-interactive"] : []
|
|
7042
|
+
], { env: cliEnv });
|
|
6812
7043
|
return JSON.parse(projects.stdout)?.result ?? [];
|
|
6813
|
-
} catch {
|
|
6814
|
-
|
|
7044
|
+
} catch (error) {
|
|
7045
|
+
if (nonInteractive) throw new MissingInitInputsError(["Firebase CLI authentication (`firebase login`)"]);
|
|
7046
|
+
throw error;
|
|
6815
7047
|
}
|
|
6816
7048
|
};
|
|
6817
|
-
const initFirebaseUser = async (cwd) => {
|
|
6818
|
-
try {
|
|
6819
|
-
await execa("npx", ["firebase", "login"], {
|
|
6820
|
-
stdio: "inherit",
|
|
6821
|
-
shell: true
|
|
6822
|
-
});
|
|
6823
|
-
} catch (err) {
|
|
6824
|
-
handleError(err);
|
|
6825
|
-
}
|
|
6826
|
-
try {
|
|
7049
|
+
const initFirebaseUser = async (cwd, preferredProjectId, nonInteractive = false, cliEnv, resolveCliEnv) => {
|
|
7050
|
+
if (!cliEnv) try {
|
|
6827
7051
|
const authList = await execa("gcloud", [
|
|
6828
7052
|
"auth",
|
|
6829
7053
|
"list",
|
|
6830
7054
|
"--format=json"
|
|
6831
|
-
], {
|
|
6832
|
-
if (JSON.parse(authList.stdout).length === 0)
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
7055
|
+
], { env: cliEnv });
|
|
7056
|
+
if (JSON.parse(authList.stdout).length === 0) {
|
|
7057
|
+
if (nonInteractive) throw new MissingInitInputsError(["active gcloud authentication (`gcloud auth login`)"]);
|
|
7058
|
+
await execa("gcloud", ["auth", "login"], {
|
|
7059
|
+
env: cliEnv,
|
|
7060
|
+
stdio: "inherit"
|
|
7061
|
+
});
|
|
7062
|
+
}
|
|
6836
7063
|
} catch (err) {
|
|
7064
|
+
if (err instanceof MissingInitInputsError) throw err;
|
|
6837
7065
|
handleError(err);
|
|
6838
7066
|
}
|
|
6839
|
-
|
|
7067
|
+
let projects;
|
|
7068
|
+
try {
|
|
7069
|
+
projects = await listProjects(nonInteractive, cliEnv);
|
|
7070
|
+
} catch (error) {
|
|
7071
|
+
if (nonInteractive || cliEnv) throw error;
|
|
7072
|
+
try {
|
|
7073
|
+
await execa("npx", ["firebase", "login"], {
|
|
7074
|
+
env: cliEnv,
|
|
7075
|
+
stdio: "inherit"
|
|
7076
|
+
});
|
|
7077
|
+
projects = await listProjects(false, cliEnv);
|
|
7078
|
+
} catch (loginError) {
|
|
7079
|
+
handleError(loginError instanceof Error ? loginError : new Error(String(loginError)));
|
|
7080
|
+
}
|
|
7081
|
+
}
|
|
6840
7082
|
const createKey = `create/${Math.random().toString(36).substring(2, 15)}`;
|
|
6841
|
-
const
|
|
7083
|
+
const preferredProject = projects.find((project) => project.projectId === preferredProjectId);
|
|
7084
|
+
if (preferredProjectId && !preferredProject) p.log.warn("Saved Firebase project was not found. Select a project again.");
|
|
7085
|
+
if (nonInteractive && !preferredProject) throw new MissingInitInputsError(["HOT_UPDATER_FIREBASE_PROJECT_ID"]);
|
|
7086
|
+
const projectId = nonInteractive && preferredProject ? preferredProject.projectId : await p.select({
|
|
7087
|
+
initialValue: preferredProject?.projectId ?? projects[0]?.projectId,
|
|
6842
7088
|
message: "Select a Firebase project",
|
|
6843
7089
|
options: [...projects.map((project) => ({
|
|
6844
7090
|
label: project.displayName,
|
|
@@ -6853,29 +7099,22 @@ const initFirebaseUser = async (cwd) => {
|
|
|
6853
7099
|
process.exit(1);
|
|
6854
7100
|
}
|
|
6855
7101
|
if (projectId === createKey) {
|
|
6856
|
-
const
|
|
7102
|
+
const prompt = initProvider.inputs.projectId.prompt;
|
|
7103
|
+
const newProjectId = await p.text({
|
|
7104
|
+
...getInitProviderTextPromptValues(prompt, preferredProjectId),
|
|
7105
|
+
message: prompt.message,
|
|
7106
|
+
validate: (value) => isFirebaseProjectId(value) ? void 0 : "Use 6-30 lowercase letters, numbers, or hyphens; start with a letter and end with a letter or number."
|
|
7107
|
+
});
|
|
6857
7108
|
if (p.isCancel(newProjectId)) {
|
|
6858
7109
|
p.log.error("Project ID is required");
|
|
6859
7110
|
process.exit(1);
|
|
6860
7111
|
}
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
newProjectId
|
|
6866
|
-
], {
|
|
6867
|
-
stdio: "inherit",
|
|
6868
|
-
shell: true
|
|
6869
|
-
});
|
|
6870
|
-
p.log.success("Firebase project created successfully");
|
|
6871
|
-
p.log.step("Please Go to the following links to enable Firestore and Storage and Billing");
|
|
6872
|
-
p.log.step(link(`https://console.firebase.google.com/project/${newProjectId}/firestore`));
|
|
6873
|
-
p.log.step(link(`https://console.firebase.google.com/project/${newProjectId}/storage`));
|
|
6874
|
-
} catch (err) {
|
|
6875
|
-
handleError(err);
|
|
6876
|
-
}
|
|
6877
|
-
process.exit(0);
|
|
7112
|
+
return {
|
|
7113
|
+
status: "create",
|
|
7114
|
+
projectId: newProjectId
|
|
7115
|
+
};
|
|
6878
7116
|
}
|
|
7117
|
+
const selectedProjectCliEnv = resolveCliEnv ? await resolveCliEnv(projectId) : cliEnv;
|
|
6879
7118
|
await p.tasks([{
|
|
6880
7119
|
title: `Select Firebase project (${projectId})...`,
|
|
6881
7120
|
task: async () => {
|
|
@@ -6883,11 +7122,12 @@ const initFirebaseUser = async (cwd) => {
|
|
|
6883
7122
|
await execa("npx", [
|
|
6884
7123
|
"firebase",
|
|
6885
7124
|
"use",
|
|
6886
|
-
"--add",
|
|
6887
|
-
projectId
|
|
7125
|
+
...nonInteractive ? [] : ["--add"],
|
|
7126
|
+
projectId,
|
|
7127
|
+
...nonInteractive ? ["--non-interactive"] : []
|
|
6888
7128
|
], {
|
|
6889
7129
|
cwd,
|
|
6890
|
-
|
|
7130
|
+
env: selectedProjectCliEnv
|
|
6891
7131
|
});
|
|
6892
7132
|
} catch (error) {
|
|
6893
7133
|
if (error instanceof ExecaError) p.log.error(error.stderr || error.stdout || error.message);
|
|
@@ -6904,7 +7144,7 @@ const initFirebaseUser = async (cwd) => {
|
|
|
6904
7144
|
`--project=${projectId}`,
|
|
6905
7145
|
"--format=json"
|
|
6906
7146
|
], {
|
|
6907
|
-
|
|
7147
|
+
env: selectedProjectCliEnv,
|
|
6908
7148
|
input: "N\n"
|
|
6909
7149
|
});
|
|
6910
7150
|
if (JSON.parse(databases.stdout).length === 0) {
|
|
@@ -6915,7 +7155,7 @@ const initFirebaseUser = async (cwd) => {
|
|
|
6915
7155
|
process.exit(1);
|
|
6916
7156
|
}
|
|
6917
7157
|
} catch (err) {
|
|
6918
|
-
handleError(err);
|
|
7158
|
+
handleError(err instanceof Error ? err : new Error(String(err)));
|
|
6919
7159
|
}
|
|
6920
7160
|
let storageBucket = null;
|
|
6921
7161
|
await p.tasks([{
|
|
@@ -6927,7 +7167,7 @@ const initFirebaseUser = async (cwd) => {
|
|
|
6927
7167
|
"list",
|
|
6928
7168
|
`--project=${projectId}`,
|
|
6929
7169
|
"--format=json"
|
|
6930
|
-
], {
|
|
7170
|
+
], { env: selectedProjectCliEnv });
|
|
6931
7171
|
storageBucket = JSON.parse(buckets.stdout).find((bucket) => bucket.name === `${projectId}.firebasestorage.app` || bucket.name === `${projectId}.appspot.com`)?.name;
|
|
6932
7172
|
if (!storageBucket) {
|
|
6933
7173
|
p.log.error("Storage Bucket not found");
|
|
@@ -6947,7 +7187,7 @@ const initFirebaseUser = async (cwd) => {
|
|
|
6947
7187
|
"describe",
|
|
6948
7188
|
projectId,
|
|
6949
7189
|
"--format=json"
|
|
6950
|
-
], {
|
|
7190
|
+
], { env: selectedProjectCliEnv });
|
|
6951
7191
|
const projectJson = JSON.parse(project.stdout);
|
|
6952
7192
|
const projectNumber = Number(projectJson.projectNumber);
|
|
6953
7193
|
if (Number.isNaN(projectNumber)) {
|
|
@@ -6955,6 +7195,7 @@ const initFirebaseUser = async (cwd) => {
|
|
|
6955
7195
|
process.exit(1);
|
|
6956
7196
|
}
|
|
6957
7197
|
return {
|
|
7198
|
+
status: "ready",
|
|
6958
7199
|
storageBucket,
|
|
6959
7200
|
projectNumber,
|
|
6960
7201
|
projectId
|
|
@@ -6973,88 +7214,6 @@ export default HotUpdater.wrap({
|
|
|
6973
7214
|
baseURL: "%%source%%",
|
|
6974
7215
|
updateStrategy: "appVersion", // or "fingerprint"
|
|
6975
7216
|
})(App);`;
|
|
6976
|
-
const REGIONS = [
|
|
6977
|
-
{
|
|
6978
|
-
value: "us-central1",
|
|
6979
|
-
label: "US Central (Iowa)"
|
|
6980
|
-
},
|
|
6981
|
-
{
|
|
6982
|
-
value: "us-east1",
|
|
6983
|
-
label: "US East (South Carolina)"
|
|
6984
|
-
},
|
|
6985
|
-
{
|
|
6986
|
-
value: "us-east4",
|
|
6987
|
-
label: "US East (Northern Virginia)"
|
|
6988
|
-
},
|
|
6989
|
-
{
|
|
6990
|
-
value: "us-west1",
|
|
6991
|
-
label: "US West (Oregon)"
|
|
6992
|
-
},
|
|
6993
|
-
{
|
|
6994
|
-
value: "us-west2",
|
|
6995
|
-
label: "US West (Los Angeles)"
|
|
6996
|
-
},
|
|
6997
|
-
{
|
|
6998
|
-
value: "us-west3",
|
|
6999
|
-
label: "US West (Salt Lake City)"
|
|
7000
|
-
},
|
|
7001
|
-
{
|
|
7002
|
-
value: "us-west4",
|
|
7003
|
-
label: "US West (Las Vegas)"
|
|
7004
|
-
},
|
|
7005
|
-
{
|
|
7006
|
-
value: "europe-west1",
|
|
7007
|
-
label: "Europe West (Belgium)"
|
|
7008
|
-
},
|
|
7009
|
-
{
|
|
7010
|
-
value: "europe-west2",
|
|
7011
|
-
label: "Europe West (London)"
|
|
7012
|
-
},
|
|
7013
|
-
{
|
|
7014
|
-
value: "europe-west3",
|
|
7015
|
-
label: "Europe West (Frankfurt)"
|
|
7016
|
-
},
|
|
7017
|
-
{
|
|
7018
|
-
value: "europe-west6",
|
|
7019
|
-
label: "Europe West (Zurich)"
|
|
7020
|
-
},
|
|
7021
|
-
{
|
|
7022
|
-
value: "asia-east1",
|
|
7023
|
-
label: "Asia East (Taiwan)"
|
|
7024
|
-
},
|
|
7025
|
-
{
|
|
7026
|
-
value: "asia-east2",
|
|
7027
|
-
label: "Asia East (Hong Kong)"
|
|
7028
|
-
},
|
|
7029
|
-
{
|
|
7030
|
-
value: "asia-northeast1",
|
|
7031
|
-
label: "Asia Northeast (Tokyo)"
|
|
7032
|
-
},
|
|
7033
|
-
{
|
|
7034
|
-
value: "asia-northeast2",
|
|
7035
|
-
label: "Asia Northeast (Osaka)"
|
|
7036
|
-
},
|
|
7037
|
-
{
|
|
7038
|
-
value: "asia-northeast3",
|
|
7039
|
-
label: "Asia Northeast (Seoul)"
|
|
7040
|
-
},
|
|
7041
|
-
{
|
|
7042
|
-
value: "asia-south1",
|
|
7043
|
-
label: "Asia South (Mumbai)"
|
|
7044
|
-
},
|
|
7045
|
-
{
|
|
7046
|
-
value: "asia-southeast1",
|
|
7047
|
-
label: "Asia Southeast (Singapore)"
|
|
7048
|
-
},
|
|
7049
|
-
{
|
|
7050
|
-
value: "asia-southeast2",
|
|
7051
|
-
label: "Asia Southeast (Jakarta)"
|
|
7052
|
-
},
|
|
7053
|
-
{
|
|
7054
|
-
value: "australia-southeast1",
|
|
7055
|
-
label: "Australia Southeast (Sydney)"
|
|
7056
|
-
}
|
|
7057
|
-
];
|
|
7058
7217
|
const getFirebaseRuntimePackageInfo = () => {
|
|
7059
7218
|
const firebasePackageRoot = path.dirname(__require.resolve("@hot-updater/firebase/package.json"));
|
|
7060
7219
|
return {
|
|
@@ -7088,10 +7247,14 @@ const mergeIndexes = (originalIndexes, newIndexes) => {
|
|
|
7088
7247
|
fieldOverrides: merge(originalIndexes.fieldOverrides, newIndexes.fieldOverrides)
|
|
7089
7248
|
};
|
|
7090
7249
|
};
|
|
7091
|
-
const deployFirestore = async (cwd) => {
|
|
7092
|
-
const original = await execa("npx", [
|
|
7250
|
+
const deployFirestore = async (cwd, nonInteractive = false, cliEnv) => {
|
|
7251
|
+
const original = await execa("npx", [
|
|
7252
|
+
"firebase",
|
|
7253
|
+
"firestore:indexes",
|
|
7254
|
+
...nonInteractive ? ["--non-interactive"] : []
|
|
7255
|
+
], {
|
|
7093
7256
|
cwd,
|
|
7094
|
-
|
|
7257
|
+
env: cliEnv
|
|
7095
7258
|
});
|
|
7096
7259
|
let originalIndexes = {
|
|
7097
7260
|
indexes: [],
|
|
@@ -7102,7 +7265,12 @@ const deployFirestore = async (cwd) => {
|
|
|
7102
7265
|
indexes: [],
|
|
7103
7266
|
fieldOverrides: []
|
|
7104
7267
|
};
|
|
7105
|
-
} catch {
|
|
7268
|
+
} catch {
|
|
7269
|
+
originalIndexes = {
|
|
7270
|
+
indexes: [],
|
|
7271
|
+
fieldOverrides: []
|
|
7272
|
+
};
|
|
7273
|
+
}
|
|
7106
7274
|
const newIndexes = JSON.parse(await fs.promises.readFile(path.join(cwd, "firestore.indexes.json"), "utf-8"));
|
|
7107
7275
|
const mergedIndexes = mergeIndexes(originalIndexes, newIndexes);
|
|
7108
7276
|
await fs.promises.writeFile(path.join(cwd, "firestore.indexes.json"), JSON.stringify(mergedIndexes, null, 2));
|
|
@@ -7111,11 +7279,12 @@ const deployFirestore = async (cwd) => {
|
|
|
7111
7279
|
"firebase",
|
|
7112
7280
|
"deploy",
|
|
7113
7281
|
"--only",
|
|
7114
|
-
"firestore"
|
|
7282
|
+
"firestore",
|
|
7283
|
+
...nonInteractive ? ["--non-interactive"] : []
|
|
7115
7284
|
], {
|
|
7116
7285
|
cwd,
|
|
7117
|
-
|
|
7118
|
-
|
|
7286
|
+
env: cliEnv,
|
|
7287
|
+
stdio: "inherit"
|
|
7119
7288
|
});
|
|
7120
7289
|
} catch (e) {
|
|
7121
7290
|
if (e instanceof ExecaError) p.log.error(e.stderr || e.stdout || e.message);
|
|
@@ -7123,17 +7292,18 @@ const deployFirestore = async (cwd) => {
|
|
|
7123
7292
|
process.exit(1);
|
|
7124
7293
|
}
|
|
7125
7294
|
};
|
|
7126
|
-
const deployFunctions = async (cwd) => {
|
|
7295
|
+
const deployFunctions = async (cwd, nonInteractive = false, cliEnv) => {
|
|
7127
7296
|
try {
|
|
7128
7297
|
await execa("npx", [
|
|
7129
7298
|
"firebase",
|
|
7130
7299
|
"deploy",
|
|
7131
7300
|
"--only",
|
|
7132
|
-
"functions"
|
|
7301
|
+
"functions",
|
|
7302
|
+
...nonInteractive ? ["--non-interactive"] : []
|
|
7133
7303
|
], {
|
|
7134
7304
|
cwd,
|
|
7135
|
-
|
|
7136
|
-
|
|
7305
|
+
env: cliEnv,
|
|
7306
|
+
stdio: "inherit"
|
|
7137
7307
|
});
|
|
7138
7308
|
} catch (e) {
|
|
7139
7309
|
if (e instanceof ExecaError) p.log.error(e.stderr || e.stdout || e.message);
|
|
@@ -7141,7 +7311,7 @@ const deployFunctions = async (cwd) => {
|
|
|
7141
7311
|
process.exit(1);
|
|
7142
7312
|
}
|
|
7143
7313
|
};
|
|
7144
|
-
const printTemplate = async (projectId, region) => {
|
|
7314
|
+
const printTemplate = async (projectId, region, cliEnv) => {
|
|
7145
7315
|
try {
|
|
7146
7316
|
const { stdout } = await execa("gcloud", [
|
|
7147
7317
|
"functions",
|
|
@@ -7152,7 +7322,7 @@ const printTemplate = async (projectId, region) => {
|
|
|
7152
7322
|
"--region",
|
|
7153
7323
|
region,
|
|
7154
7324
|
"--format=json"
|
|
7155
|
-
], {
|
|
7325
|
+
], { env: cliEnv });
|
|
7156
7326
|
const parsedData = JSON.parse(stdout);
|
|
7157
7327
|
const functionUrl = `${parsedData?.serviceConfig?.uri ?? parsedData.url}/api/check-update`;
|
|
7158
7328
|
p.note(transformTemplate(SOURCE_TEMPLATE, { source: functionUrl }));
|
|
@@ -7164,13 +7334,20 @@ const printTemplate = async (projectId, region) => {
|
|
|
7164
7334
|
};
|
|
7165
7335
|
const checkIfGcloudCliInstalled = async () => {
|
|
7166
7336
|
try {
|
|
7167
|
-
await execa("gcloud", ["--version"]
|
|
7337
|
+
await execa("gcloud", ["--version"]);
|
|
7168
7338
|
return true;
|
|
7169
7339
|
} catch {
|
|
7170
7340
|
return false;
|
|
7171
7341
|
}
|
|
7172
7342
|
};
|
|
7173
|
-
const runInit = async ({ build }) => {
|
|
7343
|
+
const runInit = async ({ build, envFile }) => {
|
|
7344
|
+
const nonInteractive = envFile !== void 0;
|
|
7345
|
+
const initEnvSources = await readHotUpdaterInitEnv(process.cwd(), envFile);
|
|
7346
|
+
const { managedEnv } = initEnvSources;
|
|
7347
|
+
const savedInputs = resolveFirebaseInitInputs(getHotUpdaterInitInputEnv(initEnvSources, nonInteractive));
|
|
7348
|
+
assertFirebaseNonInteractiveInputs(savedInputs, nonInteractive);
|
|
7349
|
+
let applicationCredentials = savedInputs.applicationCredentials;
|
|
7350
|
+
const cliEnv = nonInteractive ? getFirebaseCliEnv(applicationCredentials) : void 0;
|
|
7174
7351
|
if (!await checkIfGcloudCliInstalled()) {
|
|
7175
7352
|
p.log.error("gcloud CLI is not installed");
|
|
7176
7353
|
p.log.step("Please go to the following link to install the gcloud CLI");
|
|
@@ -7180,22 +7357,61 @@ const runInit = async ({ build }) => {
|
|
|
7180
7357
|
const { tmpDir, removeTmpDir, functionsDir } = await prepareFirebaseTemplate(path.dirname(path.dirname(__require.resolve("@hot-updater/firebase/functions"))));
|
|
7181
7358
|
const functionsIndexPath = path.join(functionsDir, "index.cjs");
|
|
7182
7359
|
const runtimePackageInfo = await syncFunctionsPackageJson(functionsDir);
|
|
7183
|
-
const initializeVariable = await initFirebaseUser(tmpDir)
|
|
7184
|
-
|
|
7360
|
+
const initializeVariable = await initFirebaseUser(tmpDir, savedInputs.projectId, nonInteractive, cliEnv, async (projectId) => {
|
|
7361
|
+
applicationCredentials = await inputFirebaseApplicationCredentials({
|
|
7362
|
+
applicationCredentials,
|
|
7363
|
+
nonInteractive,
|
|
7364
|
+
projectId
|
|
7365
|
+
});
|
|
7366
|
+
return cliEnv;
|
|
7367
|
+
});
|
|
7368
|
+
const currentRegion = await resolveFirebaseRegion({
|
|
7369
|
+
cwd: tmpDir,
|
|
7370
|
+
discoverExistingProject: initializeVariable.status === "ready",
|
|
7371
|
+
nonInteractive,
|
|
7372
|
+
savedRegion: savedInputs.region,
|
|
7373
|
+
cliEnv
|
|
7374
|
+
});
|
|
7375
|
+
const resolvedInputs = {
|
|
7376
|
+
...savedInputs,
|
|
7377
|
+
applicationCredentials: applicationCredentials || void 0,
|
|
7378
|
+
projectId: initializeVariable.projectId,
|
|
7379
|
+
region: currentRegion
|
|
7380
|
+
};
|
|
7381
|
+
const persistedInputs = getInitProviderEnvVars({
|
|
7382
|
+
includeConsentInputs: await confirmInitInputPersistence({
|
|
7383
|
+
existingEnv: managedEnv,
|
|
7384
|
+
inputs: resolvedInputs,
|
|
7385
|
+
nonInteractive,
|
|
7386
|
+
provider: initProvider
|
|
7387
|
+
}),
|
|
7388
|
+
inputs: resolvedInputs,
|
|
7389
|
+
provider: initProvider
|
|
7390
|
+
});
|
|
7391
|
+
if (initializeVariable.status === "create") {
|
|
7392
|
+
await createFirebaseProject({
|
|
7393
|
+
cliEnv,
|
|
7394
|
+
projectId: initializeVariable.projectId
|
|
7395
|
+
});
|
|
7396
|
+
await makeEnv(persistedInputs);
|
|
7397
|
+
await removeTmpDir();
|
|
7398
|
+
return;
|
|
7399
|
+
}
|
|
7400
|
+
const functionsCode = transformEnv(functionsIndexPath, { REGION: currentRegion });
|
|
7401
|
+
await fs.promises.writeFile(functionsIndexPath, functionsCode);
|
|
7185
7402
|
await setEnv({
|
|
7186
7403
|
projectId: initializeVariable.projectId,
|
|
7187
7404
|
storageBucket: initializeVariable.storageBucket,
|
|
7188
|
-
build
|
|
7405
|
+
build,
|
|
7406
|
+
region: currentRegion,
|
|
7407
|
+
applicationCredentials: persistedInputs[initProvider.inputs.applicationCredentials.envKey]
|
|
7189
7408
|
});
|
|
7190
7409
|
if (runtimePackageInfo.serverPackageVersion !== runtimePackageInfo.currentPackageVersion) p.note(`Using ${HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV}=${runtimePackageInfo.serverPackageVersion} for Firebase functions deploy.`);
|
|
7191
7410
|
await p.tasks([{
|
|
7192
7411
|
title: "Installing dependencies...",
|
|
7193
7412
|
task: async () => {
|
|
7194
7413
|
try {
|
|
7195
|
-
await execa("npm", ["install"], {
|
|
7196
|
-
cwd: functionsDir,
|
|
7197
|
-
shell: true
|
|
7198
|
-
});
|
|
7414
|
+
await execa("npm", ["install"], { cwd: functionsDir });
|
|
7199
7415
|
return "Installed dependencies";
|
|
7200
7416
|
} catch (error) {
|
|
7201
7417
|
if (error instanceof ExecaError) p.log.error(error.stderr || error.stdout || error.message);
|
|
@@ -7203,59 +7419,20 @@ const runInit = async ({ build }) => {
|
|
|
7203
7419
|
process.exit(1);
|
|
7204
7420
|
}
|
|
7205
7421
|
}
|
|
7206
|
-
}, {
|
|
7207
|
-
title: "Checking existing functions and setting region",
|
|
7208
|
-
task: async () => {
|
|
7209
|
-
let isFunctionsExist = false;
|
|
7210
|
-
try {
|
|
7211
|
-
const { stdout } = await execa("npx", [
|
|
7212
|
-
"firebase",
|
|
7213
|
-
"functions:list",
|
|
7214
|
-
"--json"
|
|
7215
|
-
], {
|
|
7216
|
-
cwd: tmpDir,
|
|
7217
|
-
shell: true
|
|
7218
|
-
});
|
|
7219
|
-
const hotUpdater = (JSON.parse(stdout).result || []).find((fn) => fn.id === "hot-updater");
|
|
7220
|
-
if (hotUpdater?.region) {
|
|
7221
|
-
currentRegion = hotUpdater.region;
|
|
7222
|
-
isFunctionsExist = true;
|
|
7223
|
-
}
|
|
7224
|
-
} catch {}
|
|
7225
|
-
if (!isFunctionsExist) {
|
|
7226
|
-
const selectedRegion = await p.select({
|
|
7227
|
-
message: "Select Region",
|
|
7228
|
-
options: REGIONS,
|
|
7229
|
-
initialValue: REGIONS[0].value
|
|
7230
|
-
});
|
|
7231
|
-
if (p.isCancel(selectedRegion)) {
|
|
7232
|
-
p.cancel("Operation cancelled.");
|
|
7233
|
-
process.exit(1);
|
|
7234
|
-
}
|
|
7235
|
-
currentRegion = selectedRegion;
|
|
7236
|
-
}
|
|
7237
|
-
if (!currentRegion) {
|
|
7238
|
-
p.log.error("Region is not set");
|
|
7239
|
-
await removeTmpDir();
|
|
7240
|
-
process.exit(1);
|
|
7241
|
-
}
|
|
7242
|
-
const code = transformEnv(functionsIndexPath, { REGION: currentRegion });
|
|
7243
|
-
await fs.promises.writeFile(functionsIndexPath, code);
|
|
7244
|
-
return `Using ${isFunctionsExist ? "existing" : "new"} functions in region: ${currentRegion}`;
|
|
7245
|
-
}
|
|
7246
7422
|
}]);
|
|
7247
|
-
await deployFirestore(tmpDir);
|
|
7248
|
-
await deployFunctions(tmpDir);
|
|
7423
|
+
await deployFirestore(tmpDir, nonInteractive, cliEnv);
|
|
7424
|
+
await deployFunctions(tmpDir, nonInteractive, cliEnv);
|
|
7249
7425
|
await p.tasks([{
|
|
7250
7426
|
title: "Check IAM policy",
|
|
7251
7427
|
async task(message) {
|
|
7252
7428
|
const functionsList = await execa("npx", [
|
|
7253
7429
|
"firebase",
|
|
7254
7430
|
"functions:list",
|
|
7255
|
-
"--json"
|
|
7431
|
+
"--json",
|
|
7432
|
+
...nonInteractive ? ["--non-interactive"] : []
|
|
7256
7433
|
], {
|
|
7257
7434
|
cwd: tmpDir,
|
|
7258
|
-
|
|
7435
|
+
env: cliEnv
|
|
7259
7436
|
});
|
|
7260
7437
|
const account = (JSON.parse(functionsList.stdout).result || []).find((fn) => fn.id === "hot-updater")?.serviceAccount;
|
|
7261
7438
|
if (!account) {
|
|
@@ -7268,7 +7445,7 @@ const runInit = async ({ build }) => {
|
|
|
7268
7445
|
"get-iam-policy",
|
|
7269
7446
|
initializeVariable.projectId,
|
|
7270
7447
|
"--format=json"
|
|
7271
|
-
], {
|
|
7448
|
+
], { env: cliEnv });
|
|
7272
7449
|
if (!JSON.parse(checkIam.stdout).bindings.some((binding) => binding.role === "roles/iam.serviceAccountTokenCreator" && binding.members.includes(`serviceAccount:${account}`))) try {
|
|
7273
7450
|
message("Adding IAM Service Account Token Creator role to the service account");
|
|
7274
7451
|
await execa("gcloud", [
|
|
@@ -7278,8 +7455,8 @@ const runInit = async ({ build }) => {
|
|
|
7278
7455
|
`--member=serviceAccount:${account}`,
|
|
7279
7456
|
"--role=roles/iam.serviceAccountTokenCreator"
|
|
7280
7457
|
], {
|
|
7281
|
-
|
|
7282
|
-
|
|
7458
|
+
env: cliEnv,
|
|
7459
|
+
stdio: "inherit"
|
|
7283
7460
|
});
|
|
7284
7461
|
p.log.success("IAM Service Account Token Creator role has been added to the service account");
|
|
7285
7462
|
} catch {
|
|
@@ -7296,10 +7473,10 @@ const runInit = async ({ build }) => {
|
|
|
7296
7473
|
await removeTmpDir();
|
|
7297
7474
|
process.exit(1);
|
|
7298
7475
|
}
|
|
7299
|
-
await printTemplate(initializeVariable.projectId, currentRegion);
|
|
7476
|
+
await printTemplate(initializeVariable.projectId, currentRegion, cliEnv);
|
|
7300
7477
|
await removeTmpDir();
|
|
7301
7478
|
p.log.message(`Next step: ${link("https://hot-updater.dev/docs/managed/firebase#step-3-generated-configurations")}`);
|
|
7302
|
-
p.log.message("Next step: Change GOOGLE_APPLICATION_CREDENTIALS=your-credentials.json in .env file");
|
|
7479
|
+
if (!applicationCredentials) p.log.message("Next step: Change GOOGLE_APPLICATION_CREDENTIALS=your-credentials.json in .env file");
|
|
7303
7480
|
p.log.success("Done! 🎉");
|
|
7304
7481
|
};
|
|
7305
7482
|
//#endregion
|