firebase-tools 13.35.1 → 14.0.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/appdistribution/client.js +4 -2
- package/lib/apphosting/backend.js +65 -11
- package/lib/apphosting/config.js +130 -101
- package/lib/apphosting/rollout.js +3 -9
- package/lib/apphosting/secrets/dialogs.js +5 -2
- package/lib/apphosting/secrets/index.js +45 -3
- package/lib/apphosting/yaml.js +19 -8
- package/lib/commands/appdistribution-groups-create.js +1 -1
- package/lib/commands/appdistribution-groups-delete.js +1 -1
- package/lib/commands/appdistribution-groups-list.js +1 -1
- package/lib/commands/appdistribution-testers-add.js +1 -1
- package/lib/commands/appdistribution-testers-remove.js +1 -1
- package/lib/commands/apphosting-backends-create.js +1 -8
- package/lib/commands/apphosting-backends-delete.js +16 -26
- package/lib/commands/apphosting-backends-get.js +10 -16
- package/lib/commands/apphosting-backends-list.js +4 -10
- package/lib/commands/apphosting-rollouts-create.js +1 -8
- package/lib/commands/apphosting-secrets-access.js +1 -1
- package/lib/commands/apphosting-secrets-describe.js +1 -1
- package/lib/commands/apphosting-secrets-grantaccess.js +19 -9
- package/lib/commands/apphosting-secrets-set.js +31 -1
- package/lib/commands/apps-android-sha-create.js +1 -1
- package/lib/commands/apps-android-sha-delete.js +1 -1
- package/lib/commands/apps-android-sha-list.js +1 -1
- package/lib/commands/apps-create.js +1 -1
- package/lib/commands/apps-init.js +1 -1
- package/lib/commands/auth-export.js +1 -1
- package/lib/commands/auth-import.js +1 -1
- package/lib/commands/database-instances-create.js +1 -1
- package/lib/commands/database-profile.js +1 -2
- package/lib/commands/database-settings-set.js +1 -1
- package/lib/commands/database-update.js +1 -1
- package/lib/commands/dataconnect-sdk-generate.js +1 -1
- package/lib/commands/dataconnect-services-list.js +1 -1
- package/lib/commands/dataconnect-sql-diff.js +1 -1
- package/lib/commands/dataconnect-sql-grant.js +1 -1
- package/lib/commands/dataconnect-sql-migrate.js +2 -2
- package/lib/commands/dataconnect-sql-setup.js +1 -1
- package/lib/commands/dataconnect-sql-shell.js +1 -1
- package/lib/commands/deploy.js +3 -3
- package/lib/commands/emulators-exec.js +1 -1
- package/lib/commands/ext-dev-register.js +1 -1
- package/lib/commands/ext-dev-usage.js +2 -2
- package/lib/commands/ext-install.js +2 -3
- package/lib/commands/firestore-backups-delete.js +2 -2
- package/lib/commands/firestore-backups-get.js +1 -1
- package/lib/commands/firestore-backups-list.js +2 -2
- package/lib/commands/firestore-backups-schedules-create.js +4 -4
- package/lib/commands/firestore-backups-schedules-delete.js +2 -2
- package/lib/commands/firestore-backups-schedules-list.js +2 -2
- package/lib/commands/firestore-backups-schedules-update.js +1 -1
- package/lib/commands/firestore-databases-create.js +6 -6
- package/lib/commands/firestore-databases-delete.js +2 -2
- package/lib/commands/firestore-databases-get.js +1 -1
- package/lib/commands/firestore-databases-list.js +1 -1
- package/lib/commands/firestore-databases-restore.js +5 -5
- package/lib/commands/firestore-databases-update.js +4 -4
- package/lib/commands/firestore-delete.js +7 -8
- package/lib/commands/firestore-indexes-list.js +4 -4
- package/lib/commands/firestore-locations.js +1 -1
- package/lib/commands/functions-artifacts-setpolicy.js +7 -7
- package/lib/commands/functions-config-export.js +1 -1
- package/lib/commands/functions-deletegcfartifacts.js +1 -1
- package/lib/commands/functions-secrets-access.js +1 -1
- package/lib/commands/functions-secrets-describe.js +1 -1
- package/lib/commands/functions-secrets-destroy.js +2 -2
- package/lib/commands/functions-secrets-get.js +1 -1
- package/lib/commands/functions-secrets-prune.js +2 -2
- package/lib/commands/functions-secrets-set.js +3 -3
- package/lib/commands/index.js +0 -4
- package/lib/commands/init.js +3 -2
- package/lib/commands/internaltesting-frameworks-compose.js +1 -1
- package/lib/commands/remoteconfig-versions-list.js +1 -1
- package/lib/commands/setup-emulators-database.js +1 -1
- package/lib/commands/setup-emulators-dataconnect.js +1 -1
- package/lib/commands/setup-emulators-firestore.js +1 -1
- package/lib/commands/setup-emulators-pubsub.js +1 -1
- package/lib/commands/setup-emulators-storage.js +1 -1
- package/lib/commands/setup-emulators-ui.js +1 -1
- package/lib/config.js +16 -18
- package/lib/dataconnect/dataplaneClient.js +3 -1
- package/lib/deploy/functions/build.js +1 -0
- package/lib/deploy/functions/prompts.js +30 -1
- package/lib/deploy/functions/release/index.js +27 -9
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +4 -4
- package/lib/emulator/apphosting/config.js +15 -14
- package/lib/emulator/auth/operations.js +2 -1
- package/lib/emulator/constants.js +1 -1
- package/lib/emulator/dataconnect/pgliteServer.js +2 -1
- package/lib/emulator/dataconnectEmulator.js +2 -0
- package/lib/emulator/downloadableEmulators.js +9 -9
- package/lib/emulator/env.js +2 -1
- package/lib/emulator/initEmulators.js +29 -4
- package/lib/experiments.js +1 -13
- package/lib/functions/artifacts.js +88 -1
- package/lib/gcp/cloudfunctions.js +1 -1
- package/lib/gcp/cloudfunctionsv2.js +3 -3
- package/lib/gcp/cloudsql/permissions.js +2 -1
- package/lib/gcp/cloudsql/permissions_setup.js +8 -5
- package/lib/gcp/proto.js +4 -3
- package/lib/init/features/dataconnect/sdk.js +4 -5
- package/package.json +2 -2
- package/standalone/package.json +1 -1
- package/templates/init/dataconnect/dataconnect.yaml +1 -1
- package/lib/commands/apphosting-config-export.js +0 -29
- package/lib/commands/experimental-functions-shell.js +0 -13
|
@@ -4,19 +4,19 @@ exports.printTriggerUrls = exports.release = void 0;
|
|
|
4
4
|
const clc = require("colorette");
|
|
5
5
|
const logger_1 = require("../../../logger");
|
|
6
6
|
const functional_1 = require("../../../functional");
|
|
7
|
+
const utils = require("../../../utils");
|
|
7
8
|
const backend = require("../backend");
|
|
8
|
-
const containerCleaner = require("../containerCleaner");
|
|
9
9
|
const planner = require("./planner");
|
|
10
10
|
const fabricator = require("./fabricator");
|
|
11
11
|
const reporter = require("./reporter");
|
|
12
12
|
const executor = require("./executor");
|
|
13
13
|
const prompts = require("../prompts");
|
|
14
|
-
const experiments = require("../../../experiments");
|
|
15
14
|
const functionsConfig_1 = require("../../../functionsConfig");
|
|
16
15
|
const functionsDeployHelper_1 = require("../functionsDeployHelper");
|
|
17
16
|
const error_1 = require("../../../error");
|
|
18
17
|
const getProjectNumber_1 = require("../../../getProjectNumber");
|
|
19
18
|
const extensions_1 = require("../../extensions");
|
|
19
|
+
const artifacts = require("../../../functions/artifacts");
|
|
20
20
|
async function release(context, options, payload) {
|
|
21
21
|
if (context.extensions && payload.extensions) {
|
|
22
22
|
await (0, extensions_1.release)(context.extensions, options, payload.extensions);
|
|
@@ -78,13 +78,7 @@ async function release(context, options, payload) {
|
|
|
78
78
|
reporter.printErrors(summary);
|
|
79
79
|
const wantBackend = backend.merge(...Object.values(payload.functions).map((p) => p.wantBackend));
|
|
80
80
|
printTriggerUrls(wantBackend);
|
|
81
|
-
|
|
82
|
-
const deletedEndpoints = Object.values(plan)
|
|
83
|
-
.map((r) => r.endpointsToDelete)
|
|
84
|
-
.reduce(functional_1.reduceFlat, []);
|
|
85
|
-
if (experiments.isEnabled("automaticallydeletegcfartifacts")) {
|
|
86
|
-
await containerCleaner.cleanupBuildImages(haveEndpoints, deletedEndpoints);
|
|
87
|
-
}
|
|
81
|
+
await setupArtifactCleanupPolicies(options, options.projectId, Object.keys(wantBackend.endpoints));
|
|
88
82
|
const allErrors = summary.results.filter((r) => r.error).map((r) => r.error);
|
|
89
83
|
if (allErrors.length) {
|
|
90
84
|
const opts = allErrors.length === 1 ? { original: allErrors[0] } : { children: allErrors };
|
|
@@ -110,3 +104,27 @@ function printTriggerUrls(results) {
|
|
|
110
104
|
}
|
|
111
105
|
}
|
|
112
106
|
exports.printTriggerUrls = printTriggerUrls;
|
|
107
|
+
async function setupArtifactCleanupPolicies(options, projectId, locations) {
|
|
108
|
+
if (locations.length === 0) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const { locationsToSetup, locationsWithErrors: locationsWithCheckErrors } = await artifacts.checkCleanupPolicy(projectId, locations);
|
|
112
|
+
if (locationsToSetup.length === 0) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const daysToKeep = await prompts.promptForCleanupPolicyDays(options, locationsToSetup);
|
|
116
|
+
utils.logLabeledBullet("functions", `Configuring cleanup policy for ${locationsToSetup.length > 1 ? "repositories" : "repository"} in ${locationsToSetup.join(", ")}. ` +
|
|
117
|
+
`Images older than ${daysToKeep} days will be automatically deleted.`);
|
|
118
|
+
const { locationsWithPolicy, locationsWithErrors: locationsWithSetupErrors } = await artifacts.setCleanupPolicies(projectId, locationsToSetup, daysToKeep);
|
|
119
|
+
utils.logLabeledBullet("functions", `Configured cleanup policy for ${locationsWithPolicy.length > 1 ? "repositories" : "repository"} in ${locationsToSetup.join(", ")}.`);
|
|
120
|
+
const locationsWithErrors = [...locationsWithCheckErrors, ...locationsWithSetupErrors];
|
|
121
|
+
if (locationsWithErrors.length > 0) {
|
|
122
|
+
utils.logLabeledWarning("functions", `Failed to set up cleanup policy for repositories in ${locationsWithErrors.length > 1 ? "regions" : "region"} ` +
|
|
123
|
+
`${locationsWithErrors.join(", ")}.` +
|
|
124
|
+
"This could result in a small monthly bill as container images accumulate over time.");
|
|
125
|
+
throw new error_1.FirebaseError(`Functions successfully deployed but could not set up cleanup policy in ` +
|
|
126
|
+
`${locationsWithErrors.length > 1 ? "regions" : "region"} ${locationsWithErrors.join(", ")}.` +
|
|
127
|
+
`Pass the --force option to automatically set up a cleanup policy or` +
|
|
128
|
+
"run 'firebase functions:artifacts:setpolicy' to set up a cleanup policy to automatically delete old images.");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -67,8 +67,8 @@ function assertBuildEndpoint(ep, id) {
|
|
|
67
67
|
maxInstances: "Field<number>?",
|
|
68
68
|
minInstances: "Field<number>?",
|
|
69
69
|
concurrency: "Field<number>?",
|
|
70
|
-
serviceAccount: "string
|
|
71
|
-
serviceAccountEmail: "string
|
|
70
|
+
serviceAccount: "Field<string>?",
|
|
71
|
+
serviceAccountEmail: "Field<string>?",
|
|
72
72
|
timeoutSeconds: "Field<number>?",
|
|
73
73
|
vpc: "object?",
|
|
74
74
|
labels: "object?",
|
|
@@ -123,8 +123,8 @@ function assertBuildEndpoint(ep, id) {
|
|
|
123
123
|
eventType: "string",
|
|
124
124
|
retry: "Field<boolean>",
|
|
125
125
|
region: "Field<string>",
|
|
126
|
-
serviceAccount: "string
|
|
127
|
-
serviceAccountEmail: "string
|
|
126
|
+
serviceAccount: "Field<string>?",
|
|
127
|
+
serviceAccountEmail: "Field<string>?",
|
|
128
128
|
channel: "string",
|
|
129
129
|
});
|
|
130
130
|
}
|
|
@@ -6,22 +6,23 @@ const config_1 = require("../../apphosting/config");
|
|
|
6
6
|
const yaml_1 = require("../../apphosting/yaml");
|
|
7
7
|
async function getLocalAppHostingConfiguration(backendDir) {
|
|
8
8
|
const appHostingConfigPaths = (0, config_1.listAppHostingFilesInPath)(backendDir);
|
|
9
|
-
const fileNameToPathMap =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
const fileNameToPathMap = Object.fromEntries(appHostingConfigPaths.map((path) => [(0, path_1.basename)(path), path]));
|
|
10
|
+
const output = yaml_1.AppHostingYamlConfig.empty();
|
|
11
|
+
const baseFilePath = fileNameToPathMap[config_1.APPHOSTING_BASE_YAML_FILE];
|
|
12
|
+
const emulatorsFilePath = fileNameToPathMap[config_1.APPHOSTING_EMULATORS_YAML_FILE];
|
|
13
|
+
const localFilePath = fileNameToPathMap[config_1.APPHOSTING_LOCAL_YAML_FILE];
|
|
14
|
+
if (baseFilePath) {
|
|
15
|
+
const baseFile = await yaml_1.AppHostingYamlConfig.loadFromFile(baseFilePath);
|
|
16
|
+
output.merge(baseFile, false);
|
|
13
17
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return yaml_1.AppHostingYamlConfig.empty();
|
|
18
|
+
if (emulatorsFilePath) {
|
|
19
|
+
const emulatorsConfig = await yaml_1.AppHostingYamlConfig.loadFromFile(emulatorsFilePath);
|
|
20
|
+
output.merge(emulatorsConfig, false);
|
|
18
21
|
}
|
|
19
|
-
if (
|
|
20
|
-
|
|
22
|
+
if (localFilePath) {
|
|
23
|
+
const localYamlConfig = await yaml_1.AppHostingYamlConfig.loadFromFile(localFilePath);
|
|
24
|
+
output.merge(localYamlConfig, true);
|
|
21
25
|
}
|
|
22
|
-
|
|
23
|
-
const baseConfig = await yaml_1.AppHostingYamlConfig.loadFromFile(baseFilePath);
|
|
24
|
-
baseConfig.merge(localYamlConfig);
|
|
25
|
-
return baseConfig;
|
|
26
|
+
return output;
|
|
26
27
|
}
|
|
27
28
|
exports.getLocalAppHostingConfiguration = getLocalAppHostingConfiguration;
|
|
@@ -216,7 +216,8 @@ function lookup(state, reqBody, ctx) {
|
|
|
216
216
|
tryAddUser(state.getUserByLocalId(localId));
|
|
217
217
|
}
|
|
218
218
|
for (const email of (_c = reqBody.email) !== null && _c !== void 0 ? _c : []) {
|
|
219
|
-
|
|
219
|
+
const canonicalizedEmail = (0, utils_1.canonicalizeEmailAddress)(email);
|
|
220
|
+
tryAddUser(state.getUserByEmail(canonicalizedEmail));
|
|
220
221
|
}
|
|
221
222
|
for (const phoneNumber of (_d = reqBody.phoneNumber) !== null && _d !== void 0 ? _d : []) {
|
|
222
223
|
tryAddUser(state.getUserByPhoneNumber(phoneNumber));
|
|
@@ -103,7 +103,7 @@ Constants.FIREBASE_ENABLED_EXPERIMENTS = "FIREBASE_ENABLED_EXPERIMENTS";
|
|
|
103
103
|
Constants.FIRESTORE_EMULATOR_HOST = "FIRESTORE_EMULATOR_HOST";
|
|
104
104
|
Constants.FIRESTORE_EMULATOR_ENV_ALT = "FIREBASE_FIRESTORE_EMULATOR_ADDRESS";
|
|
105
105
|
Constants.FIREBASE_DATABASE_EMULATOR_HOST = "FIREBASE_DATABASE_EMULATOR_HOST";
|
|
106
|
-
Constants.FIREBASE_DATACONNECT_EMULATOR_HOST = "
|
|
106
|
+
Constants.FIREBASE_DATACONNECT_EMULATOR_HOST = "FIREBASE_DATA_CONNECT_EMULATOR_HOST";
|
|
107
107
|
Constants.FIREBASE_AUTH_EMULATOR_HOST = "FIREBASE_AUTH_EMULATOR_HOST";
|
|
108
108
|
Constants.FIREBASE_STORAGE_EMULATOR_HOST = "FIREBASE_STORAGE_EMULATOR_HOST";
|
|
109
109
|
Constants.CLOUD_STORAGE_EMULATOR_HOST = "STORAGE_EMULATOR_HOST";
|
|
@@ -124,7 +124,8 @@ class PostgresServer {
|
|
|
124
124
|
const db = await pglite_1.PGlite.create(pgliteArgs);
|
|
125
125
|
return db;
|
|
126
126
|
}
|
|
127
|
-
|
|
127
|
+
logger_1.logger.debug(`Error from pglite: ${err}`);
|
|
128
|
+
throw new error_1.FirebaseError("Unexpected error starting up Postgres.");
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
async stop() {
|
|
@@ -21,6 +21,7 @@ const pgliteServer_1 = require("./dataconnect/pgliteServer");
|
|
|
21
21
|
const controller_1 = require("./controller");
|
|
22
22
|
const utils_1 = require("../utils");
|
|
23
23
|
const env_1 = require("./env");
|
|
24
|
+
const ensureApiEnabled_1 = require("../ensureApiEnabled");
|
|
24
25
|
exports.dataConnectEmulatorEvents = new events_1.EventEmitter();
|
|
25
26
|
class DataConnectEmulator {
|
|
26
27
|
constructor(args) {
|
|
@@ -43,6 +44,7 @@ class DataConnectEmulator {
|
|
|
43
44
|
this.logger.logLabeled("WARN", "dataconnect", "Detected a 'demo-' project, but vector embeddings require a real project. Operations that use vector_embed will fail.");
|
|
44
45
|
}
|
|
45
46
|
else {
|
|
47
|
+
await (0, ensureApiEnabled_1.ensure)(this.args.projectId, (0, api_1.vertexAIOrigin)(), "dataconnect", true);
|
|
46
48
|
this.logger.logLabeled("WARN", "dataconnect", "Operations that use vector_embed will make calls to production Vertex AI");
|
|
47
49
|
}
|
|
48
50
|
}
|
|
@@ -48,20 +48,20 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
48
48
|
},
|
|
49
49
|
dataconnect: process.platform === "darwin"
|
|
50
50
|
? {
|
|
51
|
-
version: "
|
|
52
|
-
expectedSize:
|
|
53
|
-
expectedChecksum: "
|
|
51
|
+
version: "2.0.0",
|
|
52
|
+
expectedSize: 26440448,
|
|
53
|
+
expectedChecksum: "64fd9ad182e59a46b9462757db6d5aac",
|
|
54
54
|
}
|
|
55
55
|
: process.platform === "win32"
|
|
56
56
|
? {
|
|
57
|
-
version: "
|
|
58
|
-
expectedSize:
|
|
59
|
-
expectedChecksum: "
|
|
57
|
+
version: "2.0.0",
|
|
58
|
+
expectedSize: 26884096,
|
|
59
|
+
expectedChecksum: "92d654dfbb07fee4e1db2328ba6e00a7",
|
|
60
60
|
}
|
|
61
61
|
: {
|
|
62
|
-
version: "
|
|
63
|
-
expectedSize:
|
|
64
|
-
expectedChecksum: "
|
|
62
|
+
version: "2.0.0",
|
|
63
|
+
expectedSize: 26353816,
|
|
64
|
+
expectedChecksum: "29c7a57a00cb11f44f9b0ffb4710bbd2",
|
|
65
65
|
},
|
|
66
66
|
};
|
|
67
67
|
exports.DownloadDetails = {
|
package/lib/emulator/env.js
CHANGED
|
@@ -36,7 +36,8 @@ function setEnvVarsForEmulators(env, emulators) {
|
|
|
36
36
|
env[constants_1.Constants.CLOUD_TASKS_EMULATOR_HOST] = host;
|
|
37
37
|
break;
|
|
38
38
|
case types_1.Emulators.DATACONNECT:
|
|
39
|
-
env[constants_1.Constants.FIREBASE_DATACONNECT_EMULATOR_HOST] = host
|
|
39
|
+
env[constants_1.Constants.FIREBASE_DATACONNECT_EMULATOR_HOST] = `http://${host}`;
|
|
40
|
+
env["FIREBASE_DATACONNECT_EMULATOR_HOST"] = host;
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AdditionalInitFns = void 0;
|
|
4
|
+
const clc = require("colorette");
|
|
4
5
|
const path_1 = require("path");
|
|
5
6
|
const prompt_1 = require("../prompt");
|
|
6
7
|
const developmentServer_1 = require("./apphosting/developmentServer");
|
|
@@ -8,9 +9,11 @@ const emulatorLogger_1 = require("./emulatorLogger");
|
|
|
8
9
|
const types_1 = require("./types");
|
|
9
10
|
const config_1 = require("../apphosting/config");
|
|
10
11
|
const detectProjectRoot_1 = require("../detectProjectRoot");
|
|
12
|
+
const projectUtils_1 = require("../projectUtils");
|
|
13
|
+
const secrets_1 = require("../apphosting/secrets");
|
|
11
14
|
exports.AdditionalInitFns = {
|
|
12
|
-
[types_1.Emulators.APPHOSTING]: async () => {
|
|
13
|
-
var _a;
|
|
15
|
+
[types_1.Emulators.APPHOSTING]: async (config) => {
|
|
16
|
+
var _a, _b;
|
|
14
17
|
const cwd = process.cwd();
|
|
15
18
|
const additionalConfigs = new Map();
|
|
16
19
|
const logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.APPHOSTING);
|
|
@@ -30,13 +33,35 @@ exports.AdditionalInitFns = {
|
|
|
30
33
|
catch (e) {
|
|
31
34
|
logger.log("WARN", "Failed to auto-detect your project's start command. Consider manually setting the start command by setting `firebase.json#emulators.apphosting.startCommand`");
|
|
32
35
|
}
|
|
36
|
+
const projectId = (0, projectUtils_1.getProjectId)(config.options);
|
|
37
|
+
let env = [];
|
|
33
38
|
try {
|
|
34
|
-
const projectRoot = (_a = (0, detectProjectRoot_1.detectProjectRoot)({})) !== null && _a !== void 0 ? _a : backendRoot;
|
|
35
|
-
await (0, config_1.
|
|
39
|
+
const projectRoot = (_a = (0, detectProjectRoot_1.detectProjectRoot)({ cwd: config.options.cwd })) !== null && _a !== void 0 ? _a : backendRoot;
|
|
40
|
+
env = await (0, config_1.maybeGenerateEmulatorYaml)(projectId, projectRoot);
|
|
36
41
|
}
|
|
37
42
|
catch (e) {
|
|
38
43
|
logger.log("WARN", "failed to export app hosting configs");
|
|
39
44
|
}
|
|
45
|
+
const secretIds = (_b = env === null || env === void 0 ? void 0 : env.filter((e) => "secret" in e)) === null || _b === void 0 ? void 0 : _b.map((e) => e.secret);
|
|
46
|
+
if (secretIds === null || secretIds === void 0 ? void 0 : secretIds.length) {
|
|
47
|
+
if (!projectId) {
|
|
48
|
+
logger.log("WARN", "Cannot grant developers access to secrets for local development without knowing what project the secret is in. " +
|
|
49
|
+
`Run ${clc.bold(`firebase apphosting:secrets:grantaccess ${secretIds.join(",")} --project [project] --emails [email list]`)}`);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const users = await (0, prompt_1.promptOnce)({
|
|
53
|
+
type: "input",
|
|
54
|
+
message: "Your config has secret values. Please provide a comma-separated list of users or groups who should have access to secrets for local development:",
|
|
55
|
+
});
|
|
56
|
+
if (users.length) {
|
|
57
|
+
await (0, secrets_1.grantEmailsSecretAccess)(projectId, secretIds, users.split(",").map((u) => u.trim()));
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
logger.log("INFO", "Skipping granting developers access to secrets for local development. To grant access in the future, run " +
|
|
61
|
+
`Run ${clc.bold(`firebase apphosting:secrets:grantaccess ${secretIds.join(",")} --emails [email list]`)}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
40
65
|
return mapToObject(additionalConfigs);
|
|
41
66
|
},
|
|
42
67
|
[types_1.Emulators.DATACONNECT]: async (config) => {
|
package/lib/experiments.js
CHANGED
|
@@ -41,18 +41,6 @@ exports.ALL_EXPERIMENTS = experiments({
|
|
|
41
41
|
"of how that image was created.",
|
|
42
42
|
public: true,
|
|
43
43
|
},
|
|
44
|
-
automaticallydeletegcfartifacts: {
|
|
45
|
-
shortDescription: "Control whether functions cleans up images after deploys",
|
|
46
|
-
fullDescription: "To control costs, Firebase defaults to automatically deleting containers " +
|
|
47
|
-
"created during the build process. This has the side-effect of preventing " +
|
|
48
|
-
"users from rolling back to previous revisions using the Run API. To change " +
|
|
49
|
-
`this behavior, call ${(0, colorette_1.bold)("experiments:disable deletegcfartifactsondeploy")} ` +
|
|
50
|
-
`consider also calling ${(0, colorette_1.bold)("experiments:enable deletegcfartifacts")} ` +
|
|
51
|
-
`to enable the new command ${(0, colorette_1.bold)("functions:deletegcfartifacts")} which` +
|
|
52
|
-
"lets you clean up images manually",
|
|
53
|
-
public: true,
|
|
54
|
-
default: true,
|
|
55
|
-
},
|
|
56
44
|
emulatoruisnapshot: {
|
|
57
45
|
shortDescription: "Load pre-release versions of the emulator UI",
|
|
58
46
|
},
|
|
@@ -115,7 +103,7 @@ exports.ALL_EXPERIMENTS = experiments({
|
|
|
115
103
|
fdcconnectorevolution: {
|
|
116
104
|
shortDescription: "Enable Data Connect connector evolution warnings.",
|
|
117
105
|
fullDescription: "Enable Data Connect connector evolution warnings.",
|
|
118
|
-
default:
|
|
106
|
+
default: true,
|
|
119
107
|
public: false,
|
|
120
108
|
},
|
|
121
109
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.hasCleanupOptOut = exports.hasSameCleanupPolicy = exports.setCleanupPolicy = exports.optOutRepository = exports.updateRepository = exports.generateCleanupPolicy = exports.parseDaysFromPolicy = exports.daysToSeconds = exports.findExistingPolicy = exports.makeRepoPath = exports.DEFAULT_CLEANUP_DAYS = exports.OPT_OUT_LABEL_KEY = exports.CLEANUP_POLICY_ID = exports.GCF_REPO_ID = void 0;
|
|
3
|
+
exports.setCleanupPolicies = exports.checkCleanupPolicy = exports.hasCleanupOptOut = exports.hasSameCleanupPolicy = exports.setCleanupPolicy = exports.optOutRepository = exports.updateRepository = exports.generateCleanupPolicy = exports.parseDaysFromPolicy = exports.daysToSeconds = exports.findExistingPolicy = exports.getRepo = exports.getRepoCache = exports.makeRepoPath = exports.DEFAULT_CLEANUP_DAYS = exports.OPT_OUT_LABEL_KEY = exports.CLEANUP_POLICY_ID = exports.GCF_REPO_ID = void 0;
|
|
4
4
|
const artifactregistry = require("../gcp/artifactregistry");
|
|
5
|
+
const logger_1 = require("../logger");
|
|
5
6
|
const error_1 = require("../error");
|
|
6
7
|
exports.GCF_REPO_ID = "gcf-artifacts";
|
|
7
8
|
exports.CLEANUP_POLICY_ID = "firebase-functions-cleanup";
|
|
@@ -12,6 +13,17 @@ function makeRepoPath(projectId, location, repoName = exports.GCF_REPO_ID) {
|
|
|
12
13
|
return `projects/${projectId}/locations/${location}/repositories/${repoName}`;
|
|
13
14
|
}
|
|
14
15
|
exports.makeRepoPath = makeRepoPath;
|
|
16
|
+
exports.getRepoCache = new Map();
|
|
17
|
+
async function getRepo(projectId, location, forceRefresh = false, repoName = exports.GCF_REPO_ID) {
|
|
18
|
+
const repoPath = makeRepoPath(projectId, location, repoName);
|
|
19
|
+
if (!forceRefresh && exports.getRepoCache.has(repoPath)) {
|
|
20
|
+
return exports.getRepoCache.get(repoPath);
|
|
21
|
+
}
|
|
22
|
+
const repo = await artifactregistry.getRepository(repoPath);
|
|
23
|
+
exports.getRepoCache.set(repoPath, repo);
|
|
24
|
+
return repo;
|
|
25
|
+
}
|
|
26
|
+
exports.getRepo = getRepo;
|
|
15
27
|
function findExistingPolicy(repository) {
|
|
16
28
|
var _a;
|
|
17
29
|
return (_a = repository === null || repository === void 0 ? void 0 : repository.cleanupPolicies) === null || _a === void 0 ? void 0 : _a[exports.CLEANUP_POLICY_ID];
|
|
@@ -103,3 +115,78 @@ function hasCleanupOptOut(repo) {
|
|
|
103
115
|
return !!(repo.labels && repo.labels[exports.OPT_OUT_LABEL_KEY] === "true");
|
|
104
116
|
}
|
|
105
117
|
exports.hasCleanupOptOut = hasCleanupOptOut;
|
|
118
|
+
async function checkCleanupPolicy(projectId, locations) {
|
|
119
|
+
if (locations.length === 0) {
|
|
120
|
+
return { locationsToSetup: [], locationsWithErrors: [] };
|
|
121
|
+
}
|
|
122
|
+
const checkRepos = await Promise.allSettled(locations.map(async (location) => {
|
|
123
|
+
try {
|
|
124
|
+
const repository = await exports.getRepo(projectId, location);
|
|
125
|
+
const hasPolicy = !!findExistingPolicy(repository);
|
|
126
|
+
const hasOptOut = hasCleanupOptOut(repository);
|
|
127
|
+
const hasOtherPolicies = repository.cleanupPolicies &&
|
|
128
|
+
Object.keys(repository.cleanupPolicies).some((key) => key !== exports.CLEANUP_POLICY_ID);
|
|
129
|
+
return {
|
|
130
|
+
location,
|
|
131
|
+
repository,
|
|
132
|
+
hasPolicy,
|
|
133
|
+
hasOptOut,
|
|
134
|
+
hasOtherPolicies,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
logger_1.logger.debug(`Failed to check artifact cleanup policy for region ${location}:`, err);
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
}));
|
|
142
|
+
const locationsToSetup = [];
|
|
143
|
+
const locationsWithErrors = [];
|
|
144
|
+
for (let i = 0; i < checkRepos.length; i++) {
|
|
145
|
+
const result = checkRepos[i];
|
|
146
|
+
if (result.status === "fulfilled") {
|
|
147
|
+
if (!(result.value.hasPolicy || result.value.hasOptOut || result.value.hasOtherPolicies)) {
|
|
148
|
+
locationsToSetup.push(result.value.location);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
locationsWithErrors.push(locations[i]);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return { locationsToSetup, locationsWithErrors };
|
|
156
|
+
}
|
|
157
|
+
exports.checkCleanupPolicy = checkCleanupPolicy;
|
|
158
|
+
async function setCleanupPolicies(projectId, locations, daysToKeep) {
|
|
159
|
+
if (locations.length === 0)
|
|
160
|
+
return { locationsWithPolicy: [], locationsWithErrors: [] };
|
|
161
|
+
const locationsWithPolicy = [];
|
|
162
|
+
const locationsWithErrors = [];
|
|
163
|
+
const setupRepos = await Promise.allSettled(locations.map(async (location) => {
|
|
164
|
+
try {
|
|
165
|
+
logger_1.logger.debug(`Setting up artifact cleanup policy for region ${location}`);
|
|
166
|
+
const repo = await exports.getRepo(projectId, location);
|
|
167
|
+
await exports.setCleanupPolicy(repo, daysToKeep);
|
|
168
|
+
return location;
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
throw new error_1.FirebaseError("Failed to set up artifact cleanup policy", {
|
|
172
|
+
original: err,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}));
|
|
176
|
+
for (let i = 0; i < locations.length; i++) {
|
|
177
|
+
const location = locations[i];
|
|
178
|
+
const result = setupRepos[i];
|
|
179
|
+
if (result.status === "rejected") {
|
|
180
|
+
logger_1.logger.debug(`Failed to set up artifact cleanup policy for region ${location}:`, result.reason);
|
|
181
|
+
locationsWithErrors.push(location);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
locationsWithPolicy.push(location);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
locationsWithPolicy,
|
|
189
|
+
locationsWithErrors,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
exports.setCleanupPolicies = setCleanupPolicies;
|
|
@@ -340,7 +340,7 @@ function functionFromEndpoint(endpoint, sourceUploadUrl) {
|
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
342
|
proto.copyIfPresent(gcfFunction, endpoint, "minInstances", "maxInstances", "ingressSettings", "environmentVariables", "secretEnvironmentVariables");
|
|
343
|
-
proto.
|
|
343
|
+
proto.convertIfPresent(gcfFunction, endpoint, "serviceAccountEmail", "serviceAccount", (from) => proto.formatServiceAccount(from, endpoint.project, true));
|
|
344
344
|
proto.convertIfPresent(gcfFunction, endpoint, "availableMemoryMb", (mem) => mem);
|
|
345
345
|
proto.convertIfPresent(gcfFunction, endpoint, "timeout", "timeoutSeconds", (sec) => sec ? proto.durationFromSeconds(sec) : null);
|
|
346
346
|
if (endpoint.vpc) {
|
|
@@ -193,7 +193,7 @@ function functionFromEndpoint(endpoint) {
|
|
|
193
193
|
};
|
|
194
194
|
proto.copyIfPresent(gcfFunction, endpoint, "labels");
|
|
195
195
|
proto.copyIfPresent(gcfFunction.serviceConfig, endpoint, "environmentVariables", "secretEnvironmentVariables", "ingressSettings", "timeoutSeconds");
|
|
196
|
-
proto.
|
|
196
|
+
proto.convertIfPresent(gcfFunction.serviceConfig, endpoint, "serviceAccountEmail", "serviceAccount", (from) => proto.formatServiceAccount(from, endpoint.project, true));
|
|
197
197
|
const mem = endpoint.availableMemoryMb || backend.DEFAULT_MEMORY;
|
|
198
198
|
gcfFunction.serviceConfig.availableMemory = mem > 1024 ? `${mem / 1024}Gi` : `${mem}Mi`;
|
|
199
199
|
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "minInstanceCount", "minInstances");
|
|
@@ -215,8 +215,8 @@ function functionFromEndpoint(endpoint) {
|
|
|
215
215
|
eventType: endpoint.eventTrigger.eventType,
|
|
216
216
|
retryPolicy: "RETRY_POLICY_UNSPECIFIED",
|
|
217
217
|
};
|
|
218
|
-
if (
|
|
219
|
-
gcfFunction.eventTrigger.serviceAccountEmail =
|
|
218
|
+
if (gcfFunction.serviceConfig.serviceAccountEmail) {
|
|
219
|
+
gcfFunction.eventTrigger.serviceAccountEmail = gcfFunction.serviceConfig.serviceAccountEmail;
|
|
220
220
|
}
|
|
221
221
|
if (gcfFunction.eventTrigger.eventType === v2_1.PUBSUB_PUBLISH_EVENT) {
|
|
222
222
|
if (!((_b = endpoint.eventTrigger.eventFilters) === null || _b === void 0 ? void 0 : _b.topic)) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.defaultPermissions = exports.readerRolePermissions = exports.writerRolePermissions = exports.ownerRolePermissions = exports.firebasewriter = exports.firebasereader = exports.firebaseowner = exports.FIREBASE_SUPER_USER = exports.DEFAULT_SCHEMA = void 0;
|
|
3
|
+
exports.defaultPermissions = exports.readerRolePermissions = exports.writerRolePermissions = exports.ownerRolePermissions = exports.firebasewriter = exports.firebasereader = exports.firebaseowner = exports.CLOUDSQL_SUPER_USER = exports.FIREBASE_SUPER_USER = exports.DEFAULT_SCHEMA = void 0;
|
|
4
4
|
exports.DEFAULT_SCHEMA = "public";
|
|
5
5
|
exports.FIREBASE_SUPER_USER = "firebasesuperuser";
|
|
6
|
+
exports.CLOUDSQL_SUPER_USER = "cloudsqlsuperuser";
|
|
6
7
|
function firebaseowner(databaseId, schema = exports.DEFAULT_SCHEMA) {
|
|
7
8
|
return `firebaseowner_${databaseId}_${schema}`;
|
|
8
9
|
}
|
|
@@ -173,14 +173,17 @@ async function getSchemaMetadata(instanceId, databaseId, schema, options) {
|
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
175
|
exports.getSchemaMetadata = getSchemaMetadata;
|
|
176
|
+
function filterTableOwners(schemaInfo, databaseId) {
|
|
177
|
+
return [...new Set(schemaInfo.tables.map((t) => t.owner))].filter((owner) => owner !== permissions_1.CLOUDSQL_SUPER_USER && owner !== (0, permissions_1.firebaseowner)(databaseId, schemaInfo.name));
|
|
178
|
+
}
|
|
176
179
|
async function setupBrownfieldAsGreenfield(instanceId, databaseId, schemaInfo, options, silent = false) {
|
|
177
180
|
const schema = schemaInfo.name;
|
|
178
181
|
const firebaseOwnerRole = (0, permissions_1.firebaseowner)(databaseId, schema);
|
|
179
|
-
const
|
|
180
|
-
const grantOwnersToSuperuserCmds =
|
|
181
|
-
const revokeOwnersFromSuperuserCmds =
|
|
182
|
+
const uniqueTablesOwners = filterTableOwners(schemaInfo, databaseId);
|
|
183
|
+
const grantOwnersToSuperuserCmds = uniqueTablesOwners.map((owner) => `GRANT "${owner}" TO "${permissions_1.FIREBASE_SUPER_USER}"`);
|
|
184
|
+
const revokeOwnersFromSuperuserCmds = uniqueTablesOwners.map((owner) => `REVOKE "${owner}" FROM "${permissions_1.FIREBASE_SUPER_USER}"`);
|
|
182
185
|
const greenfieldSetupCmds = await greenFieldSchemaSetup(instanceId, databaseId, schema, options);
|
|
183
|
-
const grantCmds =
|
|
186
|
+
const grantCmds = uniqueTablesOwners.map((owner) => `GRANT "${(0, permissions_1.firebasewriter)(databaseId, schema)}" TO "${owner}"`);
|
|
184
187
|
const alterTableCmds = schemaInfo.tables.map((table) => `ALTER TABLE "${schema}"."${table.name}" OWNER TO "${firebaseOwnerRole}";`);
|
|
185
188
|
const setupCmds = [
|
|
186
189
|
...grantOwnersToSuperuserCmds,
|
|
@@ -194,7 +197,7 @@ async function setupBrownfieldAsGreenfield(instanceId, databaseId, schemaInfo, o
|
|
|
194
197
|
exports.setupBrownfieldAsGreenfield = setupBrownfieldAsGreenfield;
|
|
195
198
|
async function brownfieldSqlSetup(instanceId, databaseId, schemaInfo, options, silent = false) {
|
|
196
199
|
const schema = schemaInfo.name;
|
|
197
|
-
const uniqueTablesOwners =
|
|
200
|
+
const uniqueTablesOwners = filterTableOwners(schemaInfo, databaseId);
|
|
198
201
|
const grantOwnersToFirebasesuperuser = uniqueTablesOwners.map((owner) => `GRANT "${owner}" TO "${permissions_1.FIREBASE_SUPER_USER}"`);
|
|
199
202
|
const revokeOwnersFromFirebasesuperuser = uniqueTablesOwners.map((owner) => `REVOKE "${owner}" FROM "${permissions_1.FIREBASE_SUPER_USER}"`);
|
|
200
203
|
const iamUser = (await (0, connect_2.getIAMUser)(options)).user;
|
package/lib/gcp/proto.js
CHANGED
|
@@ -91,18 +91,19 @@ function getInvokerMembers(invoker, projectId) {
|
|
|
91
91
|
return invoker.map((inv) => formatServiceAccount(inv, projectId));
|
|
92
92
|
}
|
|
93
93
|
exports.getInvokerMembers = getInvokerMembers;
|
|
94
|
-
function formatServiceAccount(serviceAccount, projectId) {
|
|
94
|
+
function formatServiceAccount(serviceAccount, projectId, removeTypePrefix = false) {
|
|
95
95
|
if (serviceAccount.length === 0) {
|
|
96
96
|
throw new error_1.FirebaseError("Service account cannot be an empty string");
|
|
97
97
|
}
|
|
98
98
|
if (!serviceAccount.includes("@")) {
|
|
99
99
|
throw new error_1.FirebaseError("Service account must be of the form 'service-account@' or 'service-account@{project-id}.iam.gserviceaccount.com'");
|
|
100
100
|
}
|
|
101
|
+
const prefix = removeTypePrefix ? "" : "serviceAccount:";
|
|
101
102
|
if (serviceAccount.endsWith("@")) {
|
|
102
103
|
const suffix = `${projectId}.iam.gserviceaccount.com`;
|
|
103
|
-
return
|
|
104
|
+
return `${prefix}${serviceAccount}${suffix}`;
|
|
104
105
|
}
|
|
105
|
-
return
|
|
106
|
+
return `${prefix}${serviceAccount}`;
|
|
106
107
|
}
|
|
107
108
|
exports.formatServiceAccount = formatServiceAccount;
|
|
108
109
|
function pruneUndefiends(obj) {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.actuate = exports.generateSdkYaml = exports.doSetup = exports.FDC_APP_FOLDER = void 0;
|
|
4
4
|
const yaml = require("yaml");
|
|
5
|
-
const fs = require("fs");
|
|
6
5
|
const clc = require("colorette");
|
|
7
6
|
const path = require("path");
|
|
8
7
|
const fsutils_1 = require("../../../fsutils");
|
|
@@ -18,7 +17,7 @@ const auth_1 = require("../../../auth");
|
|
|
18
17
|
exports.FDC_APP_FOLDER = "_FDC_APP_FOLDER";
|
|
19
18
|
async function doSetup(setup, config) {
|
|
20
19
|
const sdkInfo = await askQuestions(setup, config);
|
|
21
|
-
await actuate(sdkInfo);
|
|
20
|
+
await actuate(sdkInfo, config);
|
|
22
21
|
(0, utils_1.logSuccess)(`If you'd like to add more generated SDKs to your app your later, run ${clc.bold("firebase init dataconnect:sdk")} again`);
|
|
23
22
|
}
|
|
24
23
|
exports.doSetup = doSetup;
|
|
@@ -157,11 +156,11 @@ async function generateSdkYaml(targetPlatform, connectorYaml, connectorDir, appD
|
|
|
157
156
|
return connectorYaml;
|
|
158
157
|
}
|
|
159
158
|
exports.generateSdkYaml = generateSdkYaml;
|
|
160
|
-
async function actuate(sdkInfo) {
|
|
159
|
+
async function actuate(sdkInfo, config) {
|
|
161
160
|
var _a, _b;
|
|
162
161
|
const connectorYamlPath = `${sdkInfo.connectorInfo.directory}/connector.yaml`;
|
|
163
|
-
|
|
164
|
-
|
|
162
|
+
(0, utils_1.logBullet)(`Writing your new SDK configuration to ${connectorYamlPath}`);
|
|
163
|
+
await config.askWriteProjectFile(path.relative(config.projectDir, connectorYamlPath), sdkInfo.connectorYamlContents);
|
|
165
164
|
const account = (0, auth_1.getGlobalDefaultAccount)();
|
|
166
165
|
await dataconnectEmulator_1.DataConnectEmulator.generate({
|
|
167
166
|
configDir: sdkInfo.connectorInfo.directory,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firebase-tools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "14.0.0",
|
|
4
4
|
"description": "Command-Line Interface for Firebase",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
],
|
|
30
30
|
"preferGlobal": true,
|
|
31
31
|
"engines": {
|
|
32
|
-
"node": ">=
|
|
32
|
+
"node": ">=20.0.0 || >=22.0.0"
|
|
33
33
|
},
|
|
34
34
|
"author": "Firebase (https://firebase.google.com/)",
|
|
35
35
|
"license": "MIT",
|
package/standalone/package.json
CHANGED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.command = void 0;
|
|
4
|
-
const command_1 = require("../command");
|
|
5
|
-
const projectUtils_1 = require("../projectUtils");
|
|
6
|
-
const requireAuth_1 = require("../requireAuth");
|
|
7
|
-
const secretManager = require("../gcp/secretManager");
|
|
8
|
-
const requirePermissions_1 = require("../requirePermissions");
|
|
9
|
-
const config_1 = require("../apphosting/config");
|
|
10
|
-
const error_1 = require("../error");
|
|
11
|
-
const detectProjectRoot_1 = require("../detectProjectRoot");
|
|
12
|
-
exports.command = new command_1.Command("apphosting:config:export")
|
|
13
|
-
.description("Export App Hosting configurations such as secrets into an apphosting.local.yaml file")
|
|
14
|
-
.option("-s, --secrets <apphosting.yaml or apphosting.<environment>.yaml file to export secrets from>", "This command combines the base apphosting.yaml with the specified environment-specific file (e.g., apphosting.staging.yaml). If keys conflict, the environment-specific file takes precedence.")
|
|
15
|
-
.before(requireAuth_1.requireAuth)
|
|
16
|
-
.before(secretManager.ensureApi)
|
|
17
|
-
.before(requirePermissions_1.requirePermissions, ["secretmanager.versions.access"])
|
|
18
|
-
.action(async (options) => {
|
|
19
|
-
var _a;
|
|
20
|
-
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
21
|
-
const environmentConfigFile = options.secrets;
|
|
22
|
-
const cwd = process.cwd();
|
|
23
|
-
const backendRoot = (0, config_1.discoverBackendRoot)(cwd);
|
|
24
|
-
if (!backendRoot) {
|
|
25
|
-
throw new error_1.FirebaseError("Missing apphosting.yaml: This command requires an apphosting.yaml configuration file. Please run 'firebase init apphosting' and try again.");
|
|
26
|
-
}
|
|
27
|
-
const projectRoot = (_a = (0, detectProjectRoot_1.detectProjectRoot)({})) !== null && _a !== void 0 ? _a : backendRoot;
|
|
28
|
-
await (0, config_1.exportConfig)(cwd, projectRoot, backendRoot, projectId, environmentConfigFile);
|
|
29
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.command = void 0;
|
|
4
|
-
const functionsShellCommandAction_1 = require("../functionsShellCommandAction");
|
|
5
|
-
const command_1 = require("../command");
|
|
6
|
-
const requireConfig_1 = require("../requireConfig");
|
|
7
|
-
const requirePermissions_1 = require("../requirePermissions");
|
|
8
|
-
exports.command = new command_1.Command("experimental:functions:shell")
|
|
9
|
-
.description("launch full Node shell with emulated functions. (Alias for `firebase functions:shell.)")
|
|
10
|
-
.option("-p, --port <port>", "the port on which to emulate functions (default: 5000)", 5000)
|
|
11
|
-
.before(requireConfig_1.requireConfig)
|
|
12
|
-
.before(requirePermissions_1.requirePermissions)
|
|
13
|
-
.action(functionsShellCommandAction_1.actionFunction);
|