firebase-tools 10.1.5 → 10.2.2
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/api.js +1 -0
- package/lib/apiv2.js +3 -0
- package/lib/appdistribution/options-parser-util.js +1 -1
- package/lib/auth.js +62 -25
- package/lib/command.js +1 -1
- package/lib/commands/apps-android-sha-create.js +2 -2
- package/lib/commands/apps-sdkconfig.js +1 -1
- package/lib/commands/auth-import.js +1 -1
- package/lib/commands/database-rules-list.js +2 -2
- package/lib/commands/emulators-start.js +1 -1
- package/lib/commands/ext-configure.js +1 -0
- package/lib/commands/ext-dev-init.js +49 -49
- package/lib/commands/ext-export.js +12 -2
- package/lib/commands/ext-install.js +104 -103
- package/lib/commands/ext-uninstall.js +9 -8
- package/lib/commands/ext-update.js +10 -9
- package/lib/commands/functions-config-clone.js +1 -1
- package/lib/commands/functions-config-export.js +1 -1
- package/lib/commands/functions-secrets-access.js +17 -0
- package/lib/commands/functions-secrets-destroy.js +40 -0
- package/lib/commands/functions-secrets-get.js +21 -0
- package/lib/commands/functions-secrets-prune.js +50 -0
- package/lib/commands/functions-secrets-set.js +46 -0
- package/lib/commands/hosting-clone.js +3 -3
- package/lib/commands/index.js +7 -3
- package/lib/commands/login.js +1 -1
- package/lib/commands/remoteconfig-get.js +1 -1
- package/lib/deploy/extensions/deploymentSummary.js +3 -3
- package/lib/deploy/extensions/params.js +3 -0
- package/lib/deploy/extensions/planner.js +2 -1
- package/lib/deploy/extensions/tasks.js +1 -1
- package/lib/deploy/functions/backend.js +20 -5
- package/lib/deploy/functions/checkIam.js +1 -1
- package/lib/deploy/functions/containerCleaner.js +3 -3
- package/lib/deploy/functions/ensure.js +112 -0
- package/lib/deploy/functions/ensureCloudBuildEnabled.js +0 -49
- package/lib/deploy/functions/functionsDeployHelper.js +2 -2
- package/lib/deploy/functions/prepare.js +15 -20
- package/lib/deploy/functions/pricing.js +1 -1
- package/lib/deploy/functions/prompts.js +2 -2
- package/lib/deploy/functions/release/fabricator.js +3 -3
- package/lib/deploy/functions/release/index.js +1 -1
- package/lib/deploy/functions/release/planner.js +11 -8
- package/lib/deploy/functions/release/reporter.js +3 -0
- package/lib/deploy/functions/runtimes/discovery/index.js +6 -6
- package/lib/deploy/functions/runtimes/discovery/parsing.js +1 -1
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +17 -11
- package/lib/deploy/functions/runtimes/golang/index.js +2 -2
- package/lib/deploy/functions/runtimes/node/index.js +26 -0
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +2 -2
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +40 -7
- package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
- package/lib/deploy/functions/validate.js +58 -3
- package/lib/deploy/hosting/client.js +9 -0
- package/lib/deploy/hosting/convertConfig.js +6 -0
- package/lib/deploy/hosting/deploy.js +2 -2
- package/lib/deploy/hosting/hashcache.js +21 -19
- package/lib/deploy/hosting/index.js +5 -5
- package/lib/deploy/hosting/prepare.js +25 -25
- package/lib/deploy/hosting/release.js +21 -24
- package/lib/deploy/hosting/uploader.js +5 -5
- package/lib/deploy/remoteconfig/functions.js +2 -2
- package/lib/emulator/auth/cloudFunctions.js +1 -1
- package/lib/emulator/auth/operations.js +1 -1
- package/lib/emulator/commandUtils.js +5 -1
- package/lib/emulator/constants.js +3 -0
- package/lib/emulator/controller.js +48 -18
- package/lib/emulator/download.js +18 -1
- package/lib/emulator/downloadableEmulators.js +30 -13
- package/lib/emulator/emulatorLogger.js +19 -1
- package/lib/emulator/extensions/validation.js +35 -0
- package/lib/emulator/extensionsEmulator.js +140 -0
- package/lib/emulator/functionsEmulator.js +175 -86
- package/lib/emulator/functionsEmulatorRuntime.js +108 -83
- package/lib/emulator/functionsEmulatorShared.js +51 -1
- package/lib/emulator/functionsEmulatorShell.js +1 -2
- package/lib/emulator/functionsEmulatorUtils.js +4 -4
- package/lib/emulator/functionsRuntimeWorker.js +3 -3
- package/lib/emulator/hub.js +4 -3
- package/lib/emulator/loggingEmulator.js +1 -1
- package/lib/emulator/pubsubEmulator.js +1 -1
- package/lib/emulator/registry.js +10 -2
- package/lib/emulator/storage/apis/firebase.js +31 -26
- package/lib/emulator/storage/apis/gcloud.js +7 -12
- package/lib/emulator/storage/files.js +36 -34
- package/lib/emulator/storage/index.js +2 -2
- package/lib/emulator/storage/metadata.js +2 -2
- package/lib/emulator/storage/rules/runtime.js +8 -7
- package/lib/emulator/types.js +3 -0
- package/lib/ensureApiEnabled.js +5 -1
- package/lib/error.js +1 -1
- package/lib/extensions/askUserForParam.js +2 -2
- package/lib/extensions/changelog.js +3 -1
- package/lib/extensions/checkProjectBilling.js +1 -1
- package/lib/extensions/diagnose.js +56 -0
- package/lib/extensions/displayExtensionInfo.js +1 -1
- package/lib/extensions/emulator/optionsHelper.js +24 -8
- package/lib/extensions/emulator/specHelper.js +10 -23
- package/lib/extensions/export.js +1 -51
- package/lib/extensions/extensionsApi.js +1 -1
- package/lib/extensions/extensionsHelper.js +23 -10
- package/lib/extensions/listExtensions.js +2 -0
- package/lib/extensions/manifest.js +48 -0
- package/lib/extensions/metricsUtils.js +4 -4
- package/lib/extensions/paramHelper.js +4 -4
- package/lib/extensions/refs.js +1 -1
- package/lib/extensions/secretsUtils.js +4 -4
- package/lib/functional.js +1 -1
- package/lib/functions/env.js +7 -8
- package/lib/functions/secrets.js +112 -0
- package/lib/gcp/cloudfunctions.js +24 -5
- package/lib/gcp/cloudfunctionsv2.js +18 -5
- package/lib/gcp/cloudtasks.js +1 -1
- package/lib/gcp/docker.js +2 -2
- package/lib/gcp/run.js +2 -2
- package/lib/gcp/secretManager.js +128 -46
- package/lib/gcp/storage.js +1 -0
- package/lib/hosting/api.js +1 -1
- package/lib/hosting/functionsProxy.js +15 -5
- package/lib/hosting/proxy.js +2 -2
- package/lib/init/features/account.js +1 -1
- package/lib/management/database.js +1 -1
- package/lib/previews.js +1 -1
- package/lib/responseToError.js +16 -7
- package/lib/serve/functions.js +2 -2
- package/lib/serve/hosting.js +1 -1
- package/lib/utils.js +7 -2
- package/npm-shrinkwrap.json +904 -412
- package/package.json +3 -3
- package/schema/firebase-config.json +32 -0
- package/templates/init/functions/javascript/package.lint.json +3 -3
- package/templates/init/functions/javascript/package.nolint.json +2 -2
- package/templates/init/functions/typescript/package.lint.json +7 -7
- package/templates/init/functions/typescript/package.nolint.json +3 -3
|
@@ -10,7 +10,7 @@ function functionMatchesAnyGroup(func, filterGroups) {
|
|
|
10
10
|
exports.functionMatchesAnyGroup = functionMatchesAnyGroup;
|
|
11
11
|
function functionMatchesGroup(func, groupChunks) {
|
|
12
12
|
const functionNameChunks = func.id.split("-").slice(0, groupChunks.length);
|
|
13
|
-
if (functionNameChunks.length
|
|
13
|
+
if (functionNameChunks.length !== groupChunks.length) {
|
|
14
14
|
return false;
|
|
15
15
|
}
|
|
16
16
|
for (let i = 0; i < groupChunks.length; i += 1) {
|
|
@@ -28,7 +28,7 @@ function getFilterGroups(options) {
|
|
|
28
28
|
const only = options.only.split(",");
|
|
29
29
|
const onlyFunctions = only.filter((filter) => {
|
|
30
30
|
const opts = filter.split(":");
|
|
31
|
-
return opts[0]
|
|
31
|
+
return opts[0] === "functions" && opts[1];
|
|
32
32
|
});
|
|
33
33
|
return onlyFunctions.map((filter) => {
|
|
34
34
|
return filter.split(":")[1].split(/[.-]/);
|
|
@@ -2,20 +2,19 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.inferDetailsFromExisting = exports.prepare = void 0;
|
|
4
4
|
const clc = require("cli-color");
|
|
5
|
-
const ensureCloudBuildEnabled_1 = require("./ensureCloudBuildEnabled");
|
|
6
|
-
const functionsDeployHelper_1 = require("./functionsDeployHelper");
|
|
7
|
-
const utils_1 = require("../../utils");
|
|
8
|
-
const prepareFunctionsUpload_1 = require("./prepareFunctionsUpload");
|
|
9
|
-
const prompts_1 = require("./prompts");
|
|
10
5
|
const backend = require("./backend");
|
|
11
6
|
const ensureApiEnabled = require("../../ensureApiEnabled");
|
|
12
7
|
const functionsConfig = require("../../functionsConfig");
|
|
13
8
|
const functionsEnv = require("../../functions/env");
|
|
14
|
-
const previews_1 = require("../../previews");
|
|
15
|
-
const projectUtils_1 = require("../../projectUtils");
|
|
16
|
-
const track_1 = require("../../track");
|
|
17
9
|
const runtimes = require("./runtimes");
|
|
18
10
|
const validate = require("./validate");
|
|
11
|
+
const ensure = require("./ensure");
|
|
12
|
+
const functionsDeployHelper_1 = require("./functionsDeployHelper");
|
|
13
|
+
const utils_1 = require("../../utils");
|
|
14
|
+
const prepareFunctionsUpload_1 = require("./prepareFunctionsUpload");
|
|
15
|
+
const prompts_1 = require("./prompts");
|
|
16
|
+
const projectUtils_1 = require("../../projectUtils");
|
|
17
|
+
const track_1 = require("../../track");
|
|
19
18
|
const logger_1 = require("../../logger");
|
|
20
19
|
const triggerRegionHelper_1 = require("./triggerRegionHelper");
|
|
21
20
|
const checkIam_1 = require("./checkIam");
|
|
@@ -24,14 +23,7 @@ function hasUserConfig(config) {
|
|
|
24
23
|
return Object.keys(config).length > 1;
|
|
25
24
|
}
|
|
26
25
|
function hasDotenv(opts) {
|
|
27
|
-
return
|
|
28
|
-
}
|
|
29
|
-
async function maybeEnableAR(projectId) {
|
|
30
|
-
if (!previews_1.previews.artifactregistry) {
|
|
31
|
-
return ensureApiEnabled.check(projectId, "artifactregistry.googleapis.com", "functions", true);
|
|
32
|
-
}
|
|
33
|
-
await ensureApiEnabled.ensure(projectId, "artifactregistry.googleapis.com", "functions");
|
|
34
|
-
return true;
|
|
26
|
+
return functionsEnv.hasUserEnvs(opts);
|
|
35
27
|
}
|
|
36
28
|
async function prepare(context, options, payload) {
|
|
37
29
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
@@ -54,8 +46,8 @@ async function prepare(context, options, payload) {
|
|
|
54
46
|
const checkAPIsEnabled = await Promise.all([
|
|
55
47
|
ensureApiEnabled.ensure(projectId, "cloudfunctions.googleapis.com", "functions"),
|
|
56
48
|
ensureApiEnabled.check(projectId, "runtimeconfig.googleapis.com", "runtimeconfig", true),
|
|
57
|
-
|
|
58
|
-
maybeEnableAR(projectId),
|
|
49
|
+
ensure.cloudBuildEnabled(projectId),
|
|
50
|
+
ensure.maybeEnableAR(projectId),
|
|
59
51
|
]);
|
|
60
52
|
context.runtimeConfigEnabled = checkAPIsEnabled[1];
|
|
61
53
|
context.artifactRegistryEnabled = checkAPIsEnabled[3];
|
|
@@ -77,7 +69,7 @@ async function prepare(context, options, payload) {
|
|
|
77
69
|
: usedDotenv
|
|
78
70
|
? "dotenv"
|
|
79
71
|
: "none";
|
|
80
|
-
|
|
72
|
+
void (0, track_1.track)("functions_codebase_deploy_env_method", tag);
|
|
81
73
|
logger_1.logger.debug(`Analyzing ${runtimeDelegate.name} backend spec`);
|
|
82
74
|
const wantBackend = await runtimeDelegate.discoverSpec(runtimeConfig, firebaseEnvs);
|
|
83
75
|
wantBackend.environmentVariables = Object.assign(Object.assign({}, userEnvs), firebaseEnvs);
|
|
@@ -110,7 +102,7 @@ async function prepare(context, options, payload) {
|
|
|
110
102
|
for (const endpoint of backend.allEndpoints(wantBackend)) {
|
|
111
103
|
endpoint.environmentVariables = wantBackend.environmentVariables;
|
|
112
104
|
}
|
|
113
|
-
await Promise.all(Object.values(wantBackend.requiredAPIs).map((api) => {
|
|
105
|
+
await Promise.all(Object.values(wantBackend.requiredAPIs).map(({ api }) => {
|
|
114
106
|
return ensureApiEnabled.ensure(projectId, api, "functions", false);
|
|
115
107
|
}));
|
|
116
108
|
validate.endpointsAreValid(wantBackend);
|
|
@@ -125,6 +117,8 @@ async function prepare(context, options, payload) {
|
|
|
125
117
|
await (0, prompts_1.promptForFailurePolicies)(options, matchingBackend, haveBackend);
|
|
126
118
|
await (0, prompts_1.promptForMinInstances)(options, matchingBackend, haveBackend);
|
|
127
119
|
await backend.checkAvailability(context, wantBackend);
|
|
120
|
+
await validate.secretsAreValid(projectId, matchingBackend);
|
|
121
|
+
await ensure.secretAccess(projectId, matchingBackend, haveBackend);
|
|
128
122
|
}
|
|
129
123
|
exports.prepare = prepare;
|
|
130
124
|
function inferDetailsFromExisting(want, have, usedDotenv) {
|
|
@@ -140,6 +134,7 @@ function inferDetailsFromExisting(want, have, usedDotenv) {
|
|
|
140
134
|
if (!wantE.availableMemoryMb && haveE.availableMemoryMb) {
|
|
141
135
|
wantE.availableMemoryMb = haveE.availableMemoryMb;
|
|
142
136
|
}
|
|
137
|
+
wantE.securityLevel = haveE.securityLevel ? haveE.securityLevel : "SECURE_ALWAYS";
|
|
143
138
|
maybeCopyTriggerRegion(wantE, haveE);
|
|
144
139
|
}
|
|
145
140
|
}
|
|
@@ -106,7 +106,7 @@ function canCalculateMinInstanceCost(endpoint) {
|
|
|
106
106
|
if (!endpoint.minInstances) {
|
|
107
107
|
return true;
|
|
108
108
|
}
|
|
109
|
-
if (endpoint.platform
|
|
109
|
+
if (endpoint.platform === "gcfv1") {
|
|
110
110
|
if (!MB_TO_GHZ[endpoint.availableMemoryMb || 256]) {
|
|
111
111
|
return false;
|
|
112
112
|
}
|
|
@@ -21,7 +21,7 @@ async function promptForFailurePolicies(options, want, have) {
|
|
|
21
21
|
const existing = (_a = have.endpoints[endpoint.region]) === null || _a === void 0 ? void 0 : _a[endpoint.id];
|
|
22
22
|
return !(existing && backend.isEventTriggered(existing) && existing.eventTrigger.retry);
|
|
23
23
|
});
|
|
24
|
-
if (newRetryEndpoints.length
|
|
24
|
+
if (newRetryEndpoints.length === 0) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
const warnMessage = "The following functions will newly be retried in case of failure: " +
|
|
@@ -137,7 +137,7 @@ async function promptForMinInstances(options, want, have) {
|
|
|
137
137
|
costLine = `With these options, your minimum bill will be $${cost} in a 30-day month`;
|
|
138
138
|
}
|
|
139
139
|
let cudAnnotation = "";
|
|
140
|
-
if (backend.someEndpoint(want, (fn) => fn.platform
|
|
140
|
+
if (backend.someEndpoint(want, (fn) => fn.platform === "gcfv2" && !!fn.minInstances)) {
|
|
141
141
|
cudAnnotation =
|
|
142
142
|
"\nThis bill can be lowered with a one year commitment. See https://cloud.google.com/run/cud for more";
|
|
143
143
|
}
|
|
@@ -216,12 +216,12 @@ class Fabricator {
|
|
|
216
216
|
})
|
|
217
217
|
.catch(rethrowAs(endpoint, "create topic"));
|
|
218
218
|
}
|
|
219
|
-
const resultFunction =
|
|
219
|
+
const resultFunction = await this.functionExecutor
|
|
220
220
|
.run(async () => {
|
|
221
221
|
const op = await gcfV2.createFunction(apiFunction);
|
|
222
222
|
return await poller.pollOperation(Object.assign(Object.assign({}, gcfV2PollerOptions), { pollerName: `create-${endpoint.region}-${endpoint.id}`, operationResourceName: op.name }));
|
|
223
223
|
})
|
|
224
|
-
.catch(rethrowAs(endpoint, "create"))
|
|
224
|
+
.catch(rethrowAs(endpoint, "create"));
|
|
225
225
|
endpoint.uri = resultFunction.serviceConfig.uri;
|
|
226
226
|
const serviceName = resultFunction.serviceConfig.service;
|
|
227
227
|
if (backend.isHttpsTriggered(endpoint)) {
|
|
@@ -243,7 +243,7 @@ class Fabricator {
|
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
245
|
const mem = endpoint.availableMemoryMb || backend.DEFAULT_MEMORY;
|
|
246
|
-
if (mem >= backend.MIN_MEMORY_FOR_CONCURRENCY && endpoint.concurrency
|
|
246
|
+
if (mem >= backend.MIN_MEMORY_FOR_CONCURRENCY && endpoint.concurrency !== 1) {
|
|
247
247
|
await this.setConcurrency(endpoint, serviceName, endpoint.concurrency || DEFAULT_GCFV2_CONCURRENCY);
|
|
248
248
|
}
|
|
249
249
|
}
|
|
@@ -56,7 +56,7 @@ async function release(context, options, payload) {
|
|
|
56
56
|
await containerCleaner.cleanupBuildImages(haveEndpoints, deletedEndpoints, opts);
|
|
57
57
|
const allErrors = summary.results.filter((r) => r.error).map((r) => r.error);
|
|
58
58
|
if (allErrors.length) {
|
|
59
|
-
const opts = allErrors.length
|
|
59
|
+
const opts = allErrors.length === 1 ? { original: allErrors[0] } : { children: allErrors };
|
|
60
60
|
throw new error_1.FirebaseError("There was an error deploying functions", Object.assign(Object.assign({}, opts), { exit: 2 }));
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -74,10 +74,10 @@ function upgradedToGCFv2WithoutSettingConcurrency(want, have) {
|
|
|
74
74
|
}
|
|
75
75
|
exports.upgradedToGCFv2WithoutSettingConcurrency = upgradedToGCFv2WithoutSettingConcurrency;
|
|
76
76
|
function changedTriggerRegion(want, have) {
|
|
77
|
-
if (want.platform
|
|
77
|
+
if (want.platform !== "gcfv2") {
|
|
78
78
|
return false;
|
|
79
79
|
}
|
|
80
|
-
if (have.platform
|
|
80
|
+
if (have.platform !== "gcfv2") {
|
|
81
81
|
return false;
|
|
82
82
|
}
|
|
83
83
|
if (!backend.isEventTriggered(want)) {
|
|
@@ -86,7 +86,7 @@ function changedTriggerRegion(want, have) {
|
|
|
86
86
|
if (!backend.isEventTriggered(have)) {
|
|
87
87
|
return false;
|
|
88
88
|
}
|
|
89
|
-
return want.eventTrigger.region
|
|
89
|
+
return want.eventTrigger.region !== have.eventTrigger.region;
|
|
90
90
|
}
|
|
91
91
|
exports.changedTriggerRegion = changedTriggerRegion;
|
|
92
92
|
function changedV2PubSubTopic(want, have) {
|
|
@@ -102,13 +102,13 @@ function changedV2PubSubTopic(want, have) {
|
|
|
102
102
|
if (!backend.isEventTriggered(have)) {
|
|
103
103
|
return false;
|
|
104
104
|
}
|
|
105
|
-
if (want.eventTrigger.eventType
|
|
105
|
+
if (want.eventTrigger.eventType !== gcfv2.PUBSUB_PUBLISH_EVENT) {
|
|
106
106
|
return false;
|
|
107
107
|
}
|
|
108
108
|
if (have.eventTrigger.eventType !== gcfv2.PUBSUB_PUBLISH_EVENT) {
|
|
109
109
|
return false;
|
|
110
110
|
}
|
|
111
|
-
return have.eventTrigger.eventFilters["resource"]
|
|
111
|
+
return have.eventTrigger.eventFilters["resource"] !== want.eventTrigger.eventFilters["resource"];
|
|
112
112
|
}
|
|
113
113
|
exports.changedV2PubSubTopic = changedV2PubSubTopic;
|
|
114
114
|
function upgradedScheduleFromV1ToV2(want, have) {
|
|
@@ -132,6 +132,9 @@ function checkForIllegalUpdate(want, have) {
|
|
|
132
132
|
if (backend.isHttpsTriggered(e)) {
|
|
133
133
|
return "an HTTPS";
|
|
134
134
|
}
|
|
135
|
+
else if (backend.isCallableTriggered(e)) {
|
|
136
|
+
return "a callable";
|
|
137
|
+
}
|
|
135
138
|
else if (backend.isEventTriggered(e)) {
|
|
136
139
|
return "a background triggered";
|
|
137
140
|
}
|
|
@@ -145,17 +148,17 @@ function checkForIllegalUpdate(want, have) {
|
|
|
145
148
|
};
|
|
146
149
|
const wantType = triggerType(want);
|
|
147
150
|
const haveType = triggerType(have);
|
|
148
|
-
if (wantType
|
|
151
|
+
if (wantType !== haveType) {
|
|
149
152
|
throw new error_1.FirebaseError(`[${(0, functionsDeployHelper_2.getFunctionLabel)(want)}] Changing from ${haveType} function to ${wantType} function is not allowed. Please delete your function and create a new one instead.`);
|
|
150
153
|
}
|
|
151
|
-
if (want.platform
|
|
154
|
+
if (want.platform === "gcfv1" && have.platform === "gcfv2") {
|
|
152
155
|
throw new error_1.FirebaseError(`[${(0, functionsDeployHelper_2.getFunctionLabel)(want)}] Functions cannot be downgraded from GCFv2 to GCFv1`);
|
|
153
156
|
}
|
|
154
157
|
exports.checkForV2Upgrade(want, have);
|
|
155
158
|
}
|
|
156
159
|
exports.checkForIllegalUpdate = checkForIllegalUpdate;
|
|
157
160
|
function checkForV2Upgrade(want, have) {
|
|
158
|
-
if (want.platform
|
|
161
|
+
if (want.platform === "gcfv2" && have.platform === "gcfv1") {
|
|
159
162
|
throw new error_1.FirebaseError(`[${(0, functionsDeployHelper_2.getFunctionLabel)(have)}] Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.`);
|
|
160
163
|
}
|
|
161
164
|
}
|
|
@@ -162,6 +162,9 @@ function triggerTag(endpoint) {
|
|
|
162
162
|
if (backend.isTaskQueueTriggered(endpoint)) {
|
|
163
163
|
return `${prefix}.taskQueue`;
|
|
164
164
|
}
|
|
165
|
+
if (backend.isCallableTriggered(endpoint)) {
|
|
166
|
+
return `${prefix}.callable`;
|
|
167
|
+
}
|
|
165
168
|
if (backend.isHttpsTriggered(endpoint)) {
|
|
166
169
|
if ((_a = endpoint.labels) === null || _a === void 0 ? void 0 : _a["deployment-callable"]) {
|
|
167
170
|
return `${prefix}.callable`;
|
|
@@ -29,18 +29,18 @@ exports.yamlToBackend = yamlToBackend;
|
|
|
29
29
|
async function detectFromYaml(directory, project, runtime) {
|
|
30
30
|
let text;
|
|
31
31
|
try {
|
|
32
|
-
text = await exports.readFileAsync(path.join(directory, "
|
|
32
|
+
text = await exports.readFileAsync(path.join(directory, "functions.yaml"), "utf8");
|
|
33
33
|
}
|
|
34
34
|
catch (err) {
|
|
35
35
|
if (err.code === "ENOENT") {
|
|
36
|
-
logger_1.logger.debug("Could not find
|
|
36
|
+
logger_1.logger.debug("Could not find functions.yaml. Must use http discovery");
|
|
37
37
|
}
|
|
38
38
|
else {
|
|
39
|
-
logger_1.logger.debug("Unexpected error looking for
|
|
39
|
+
logger_1.logger.debug("Unexpected error looking for functions.yaml file:", err);
|
|
40
40
|
}
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
|
-
logger_1.logger.debug("Found
|
|
43
|
+
logger_1.logger.debug("Found functions.yaml. Got spec:", text);
|
|
44
44
|
const parsed = yaml.load(text);
|
|
45
45
|
return yamlToBackend(parsed, project, api.functionsDefaultRegion, runtime);
|
|
46
46
|
}
|
|
@@ -54,7 +54,7 @@ async function detectFromPort(port, project, runtime, timeout = 30000) {
|
|
|
54
54
|
});
|
|
55
55
|
while (true) {
|
|
56
56
|
try {
|
|
57
|
-
res = await Promise.race([(0, node_fetch_1.default)(`http://localhost:${port}/
|
|
57
|
+
res = await Promise.race([(0, node_fetch_1.default)(`http://localhost:${port}/__/functions.yaml`), timedOut]);
|
|
58
58
|
break;
|
|
59
59
|
}
|
|
60
60
|
catch (err) {
|
|
@@ -65,7 +65,7 @@ async function detectFromPort(port, project, runtime, timeout = 30000) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
const text = await res.text();
|
|
68
|
-
logger_1.logger.debug("Got response from /
|
|
68
|
+
logger_1.logger.debug("Got response from /__/functions.yaml", text);
|
|
69
69
|
let parsed;
|
|
70
70
|
try {
|
|
71
71
|
parsed = yaml.load(text);
|
|
@@ -21,7 +21,7 @@ function assertKeyTypes(prefix, yaml, schema) {
|
|
|
21
21
|
const key = keyAsString;
|
|
22
22
|
const fullKey = prefix ? prefix + "." + key : key;
|
|
23
23
|
if (!schema[key] || schema[key] === "omit") {
|
|
24
|
-
throw new error_1.FirebaseError(`Unexpected key ${fullKey}. You may need to install a newer version of the Firebase CLI
|
|
24
|
+
throw new error_1.FirebaseError(`Unexpected key ${fullKey}. You may need to install a newer version of the Firebase CLI.`);
|
|
25
25
|
}
|
|
26
26
|
if (schema[key] === "string") {
|
|
27
27
|
if (typeof value !== "string") {
|
|
@@ -12,7 +12,7 @@ function backendFromV1Alpha1(yaml, project, region, runtime) {
|
|
|
12
12
|
(0, parsing_1.requireKeys)("", manifest, "endpoints");
|
|
13
13
|
(0, parsing_1.assertKeyTypes)("", manifest, {
|
|
14
14
|
specVersion: "string",
|
|
15
|
-
requiredAPIs: "
|
|
15
|
+
requiredAPIs: "array",
|
|
16
16
|
endpoints: "object",
|
|
17
17
|
});
|
|
18
18
|
for (const id of Object.keys(manifest.endpoints)) {
|
|
@@ -25,15 +25,14 @@ function backendFromV1Alpha1(yaml, project, region, runtime) {
|
|
|
25
25
|
}
|
|
26
26
|
exports.backendFromV1Alpha1 = backendFromV1Alpha1;
|
|
27
27
|
function parseRequiredAPIs(manifest) {
|
|
28
|
-
const requiredAPIs =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
const requiredAPIs = manifest.requiredAPIs || [];
|
|
29
|
+
for (const { api, reason } of requiredAPIs) {
|
|
30
|
+
if (typeof api !== "string") {
|
|
31
|
+
throw new error_1.FirebaseError(`Invalid api "${JSON.stringify(api)}. Expected string`);
|
|
32
|
+
}
|
|
33
33
|
if (typeof reason !== "string") {
|
|
34
34
|
throw new error_1.FirebaseError(`Invalid reason "${JSON.stringify(reason)} for API ${api}. Expected string`);
|
|
35
35
|
}
|
|
36
|
-
requiredAPIs[api] = reason;
|
|
37
36
|
}
|
|
38
37
|
return requiredAPIs;
|
|
39
38
|
}
|
|
@@ -51,12 +50,13 @@ function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
|
|
|
51
50
|
concurrency: "number",
|
|
52
51
|
serviceAccountEmail: "string",
|
|
53
52
|
timeout: "string",
|
|
54
|
-
|
|
55
|
-
vpcConnectorEgressSettings: "string",
|
|
53
|
+
vpc: "object",
|
|
56
54
|
labels: "object",
|
|
57
55
|
ingressSettings: "string",
|
|
58
56
|
environmentVariables: "object",
|
|
57
|
+
secretEnvironmentVariables: "array",
|
|
59
58
|
httpsTrigger: "object",
|
|
59
|
+
callableTrigger: "object",
|
|
60
60
|
eventTrigger: "object",
|
|
61
61
|
scheduleTrigger: "object",
|
|
62
62
|
taskQueueTrigger: "object",
|
|
@@ -65,6 +65,9 @@ function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
|
|
|
65
65
|
if (ep.httpsTrigger) {
|
|
66
66
|
triggerCount++;
|
|
67
67
|
}
|
|
68
|
+
if (ep.callableTrigger) {
|
|
69
|
+
triggerCount++;
|
|
70
|
+
}
|
|
68
71
|
if (ep.eventTrigger) {
|
|
69
72
|
triggerCount++;
|
|
70
73
|
}
|
|
@@ -75,7 +78,7 @@ function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
|
|
|
75
78
|
triggerCount++;
|
|
76
79
|
}
|
|
77
80
|
if (!triggerCount) {
|
|
78
|
-
throw new error_1.FirebaseError("Expected trigger in endpoint" + id);
|
|
81
|
+
throw new error_1.FirebaseError("Expected trigger in endpoint " + id);
|
|
79
82
|
}
|
|
80
83
|
if (triggerCount > 1) {
|
|
81
84
|
throw new error_1.FirebaseError("Multiple triggers defined for endpoint" + id);
|
|
@@ -100,6 +103,9 @@ function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
|
|
|
100
103
|
triggered = { httpsTrigger: {} };
|
|
101
104
|
(0, proto_1.copyIfPresent)(triggered.httpsTrigger, ep.httpsTrigger, "invoker");
|
|
102
105
|
}
|
|
106
|
+
else if (backend.isCallableTriggered(ep)) {
|
|
107
|
+
triggered = { callableTrigger: {} };
|
|
108
|
+
}
|
|
103
109
|
else if (backend.isScheduleTriggered(ep)) {
|
|
104
110
|
(0, parsing_1.assertKeyTypes)(prefix + ".scheduleTrigger", ep.scheduleTrigger, {
|
|
105
111
|
schedule: "string",
|
|
@@ -148,7 +154,7 @@ function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
|
|
|
148
154
|
region,
|
|
149
155
|
project,
|
|
150
156
|
runtime, entryPoint: ep.entryPoint }, triggered);
|
|
151
|
-
(0, proto_1.copyIfPresent)(parsed, ep, "availableMemoryMb", "maxInstances", "minInstances", "concurrency", "serviceAccountEmail", "timeout", "
|
|
157
|
+
(0, proto_1.copyIfPresent)(parsed, ep, "availableMemoryMb", "maxInstances", "minInstances", "concurrency", "serviceAccountEmail", "timeout", "vpc", "labels", "ingressSettings", "environmentVariables");
|
|
152
158
|
allParsed.push(parsed);
|
|
153
159
|
}
|
|
154
160
|
return allParsed;
|
|
@@ -71,7 +71,7 @@ class Delegate {
|
|
|
71
71
|
},
|
|
72
72
|
stdio: ["ignore", "pipe", "pipe"],
|
|
73
73
|
});
|
|
74
|
-
if (genBinary.status
|
|
74
|
+
if (genBinary.status !== 0) {
|
|
75
75
|
throw new error_1.FirebaseError("Failed to run codegen", {
|
|
76
76
|
children: [new Error(genBinary.stderr.toString())],
|
|
77
77
|
});
|
|
@@ -96,7 +96,7 @@ class Delegate {
|
|
|
96
96
|
childProcess.once("exit", resolve);
|
|
97
97
|
childProcess.once("error", reject);
|
|
98
98
|
});
|
|
99
|
-
await (0, node_fetch_1.default)(`http://localhost:${adminPort}/quitquitquit`);
|
|
99
|
+
await (0, node_fetch_1.default)(`http://localhost:${adminPort}/__/quitquitquit`);
|
|
100
100
|
setTimeout(() => {
|
|
101
101
|
if (!childProcess.killed) {
|
|
102
102
|
childProcess.kill("SIGKILL");
|
|
@@ -4,6 +4,8 @@ exports.Delegate = exports.tryCreateDelegate = void 0;
|
|
|
4
4
|
const util_1 = require("util");
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const path = require("path");
|
|
7
|
+
const spawn = require("cross-spawn");
|
|
8
|
+
const node_fetch_1 = require("node-fetch");
|
|
7
9
|
const error_1 = require("../../../../error");
|
|
8
10
|
const parseRuntimeAndValidateSDK_1 = require("./parseRuntimeAndValidateSDK");
|
|
9
11
|
const logger_1 = require("../../../../logger");
|
|
@@ -50,6 +52,30 @@ class Delegate {
|
|
|
50
52
|
watch() {
|
|
51
53
|
return Promise.resolve(() => Promise.resolve());
|
|
52
54
|
}
|
|
55
|
+
serve(port, envs) {
|
|
56
|
+
var _a;
|
|
57
|
+
const childProcess = spawn("./node_modules/.bin/firebase-functions", [this.sourceDir], {
|
|
58
|
+
env: Object.assign(Object.assign({}, envs), { PORT: port.toString(), FUNCTIONS_CONTROL_API: "true", HOME: process.env.HOME, PATH: process.env.PATH }),
|
|
59
|
+
cwd: this.sourceDir,
|
|
60
|
+
stdio: ["ignore", "pipe", "inherit"],
|
|
61
|
+
});
|
|
62
|
+
(_a = childProcess.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (chunk) => {
|
|
63
|
+
logger_1.logger.debug(chunk.toString());
|
|
64
|
+
});
|
|
65
|
+
return Promise.resolve(async () => {
|
|
66
|
+
const p = new Promise((resolve, reject) => {
|
|
67
|
+
childProcess.once("exit", resolve);
|
|
68
|
+
childProcess.once("error", reject);
|
|
69
|
+
});
|
|
70
|
+
await (0, node_fetch_1.default)(`http://localhost:${port}/__/quitquitquit`);
|
|
71
|
+
setTimeout(() => {
|
|
72
|
+
if (!childProcess.killed) {
|
|
73
|
+
childProcess.kill("SIGKILL");
|
|
74
|
+
}
|
|
75
|
+
}, 10000);
|
|
76
|
+
return p;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
53
79
|
async discoverSpec(config, env) {
|
|
54
80
|
return parseTriggers.discoverBackend(this.projectId, this.sourceDir, this.runtime, config, env);
|
|
55
81
|
}
|
|
@@ -46,11 +46,11 @@ function getRuntimeChoice(sourceDir, runtimeFromConfig) {
|
|
|
46
46
|
? exports.UNSUPPORTED_NODE_VERSION_FIREBASE_JSON_MSG
|
|
47
47
|
: exports.UNSUPPORTED_NODE_VERSION_PACKAGE_JSON_MSG) + exports.DEPRECATED_NODE_VERSION_INFO;
|
|
48
48
|
if (!runtime || !ENGINE_RUNTIMES_NAMES.includes(runtime)) {
|
|
49
|
-
track("functions_runtime_notices", "package_missing_runtime");
|
|
49
|
+
void track("functions_runtime_notices", "package_missing_runtime");
|
|
50
50
|
throw new error_1.FirebaseError(errorMessage, { exit: 1 });
|
|
51
51
|
}
|
|
52
52
|
if (runtimes.isDeprecatedRuntime(runtime) || !runtimes.isValidRuntime(runtime)) {
|
|
53
|
-
track("functions_runtime_notices", `${runtime}_deploy_prohibited`);
|
|
53
|
+
void track("functions_runtime_notices", `${runtime}_deploy_prohibited`);
|
|
54
54
|
throw new error_1.FirebaseError(errorMessage, { exit: 1 });
|
|
55
55
|
}
|
|
56
56
|
return runtime;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.addResourcesToBackend = exports.discoverBackend = exports.useStrategy = void 0;
|
|
3
|
+
exports.addResourcesToBackend = exports.mergeRequiredAPIs = exports.discoverBackend = exports.useStrategy = void 0;
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const _ = require("lodash");
|
|
6
6
|
const child_process_1 = require("child_process");
|
|
@@ -58,17 +58,34 @@ async function discoverBackend(projectId, sourceDir, runtime, configValues, envs
|
|
|
58
58
|
return want;
|
|
59
59
|
}
|
|
60
60
|
exports.discoverBackend = discoverBackend;
|
|
61
|
+
function mergeRequiredAPIs(backend) {
|
|
62
|
+
const apiToReasons = {};
|
|
63
|
+
for (const { api, reason } of backend.requiredAPIs) {
|
|
64
|
+
const reasons = apiToReasons[api] || new Set();
|
|
65
|
+
reasons.add(reason);
|
|
66
|
+
apiToReasons[api] = reasons;
|
|
67
|
+
}
|
|
68
|
+
const merged = [];
|
|
69
|
+
for (const [api, reasons] of Object.entries(apiToReasons)) {
|
|
70
|
+
merged.push({ api, reason: Array.from(reasons).join(" ") });
|
|
71
|
+
}
|
|
72
|
+
backend.requiredAPIs = merged;
|
|
73
|
+
}
|
|
74
|
+
exports.mergeRequiredAPIs = mergeRequiredAPIs;
|
|
61
75
|
function addResourcesToBackend(projectId, runtime, annotation, want) {
|
|
62
76
|
Object.freeze(annotation);
|
|
63
77
|
for (const region of annotation.regions || [api.functionsDefaultRegion]) {
|
|
64
78
|
let triggered;
|
|
65
79
|
const triggerCount = +!!annotation.httpsTrigger + +!!annotation.eventTrigger + +!!annotation.taskQueueTrigger;
|
|
66
|
-
if (triggerCount
|
|
80
|
+
if (triggerCount !== 1) {
|
|
67
81
|
throw new error_1.FirebaseError("Unexpected annotation generated by the Firebase Functions SDK. This should never happen.");
|
|
68
82
|
}
|
|
69
83
|
if (annotation.taskQueueTrigger) {
|
|
70
84
|
triggered = { taskQueueTrigger: annotation.taskQueueTrigger };
|
|
71
|
-
want.requiredAPIs
|
|
85
|
+
want.requiredAPIs.push({
|
|
86
|
+
api: "cloudtasks.googleapis.com",
|
|
87
|
+
reason: "Needed for task queue functions.",
|
|
88
|
+
});
|
|
72
89
|
}
|
|
73
90
|
else if (annotation.httpsTrigger) {
|
|
74
91
|
const trigger = {};
|
|
@@ -79,8 +96,10 @@ function addResourcesToBackend(projectId, runtime, annotation, want) {
|
|
|
79
96
|
triggered = { httpsTrigger: trigger };
|
|
80
97
|
}
|
|
81
98
|
else if (annotation.schedule) {
|
|
82
|
-
want.requiredAPIs
|
|
83
|
-
|
|
99
|
+
want.requiredAPIs.push({
|
|
100
|
+
api: "cloudscheduler.googleapis.com",
|
|
101
|
+
reason: "Needed for scheduled functions.",
|
|
102
|
+
});
|
|
84
103
|
triggered = { scheduleTrigger: annotation.schedule };
|
|
85
104
|
}
|
|
86
105
|
else {
|
|
@@ -105,11 +124,25 @@ function addResourcesToBackend(projectId, runtime, annotation, want) {
|
|
|
105
124
|
if (maybeId && !maybeId.includes("/")) {
|
|
106
125
|
maybeId = `projects/${projectId}/locations/${region}/connectors/${maybeId}`;
|
|
107
126
|
}
|
|
108
|
-
endpoint.
|
|
127
|
+
endpoint.vpc = { connector: maybeId };
|
|
128
|
+
proto.renameIfPresent(endpoint.vpc, annotation, "egressSettings", "vpcConnectorEgressSettings");
|
|
129
|
+
}
|
|
130
|
+
if (annotation.secrets) {
|
|
131
|
+
const secretEnvs = [];
|
|
132
|
+
for (const secret of annotation.secrets) {
|
|
133
|
+
const secretEnv = {
|
|
134
|
+
secret,
|
|
135
|
+
projectId,
|
|
136
|
+
key: secret,
|
|
137
|
+
};
|
|
138
|
+
secretEnvs.push(secretEnv);
|
|
139
|
+
}
|
|
140
|
+
endpoint.secretEnvironmentVariables = secretEnvs;
|
|
109
141
|
}
|
|
110
|
-
proto.copyIfPresent(endpoint, annotation, "concurrency", "serviceAccountEmail", "labels", "
|
|
142
|
+
proto.copyIfPresent(endpoint, annotation, "concurrency", "serviceAccountEmail", "labels", "ingressSettings", "timeout", "maxInstances", "minInstances", "availableMemoryMb");
|
|
111
143
|
want.endpoints[region] = want.endpoints[region] || {};
|
|
112
144
|
want.endpoints[region][endpoint.id] = endpoint;
|
|
145
|
+
mergeRequiredAPIs(want);
|
|
113
146
|
}
|
|
114
147
|
}
|
|
115
148
|
exports.addResourcesToBackend = addResourcesToBackend;
|
|
@@ -52,7 +52,7 @@ exports.getLatestSDKVersion = getLatestSDKVersion;
|
|
|
52
52
|
function checkFunctionsSDKVersion(currentVersion) {
|
|
53
53
|
try {
|
|
54
54
|
if (semver.lt(currentVersion, MIN_SDK_VERSION)) {
|
|
55
|
-
track("functions_runtime_notices", "functions_sdk_too_old");
|
|
55
|
+
void track("functions_runtime_notices", "functions_sdk_too_old");
|
|
56
56
|
utils.logWarning(exports.FUNCTIONS_SDK_VERSION_TOO_OLD_WARNING);
|
|
57
57
|
}
|
|
58
58
|
const latest = exports.getLatestSDKVersion();
|
|
@@ -63,7 +63,7 @@ function checkFunctionsSDKVersion(currentVersion) {
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
utils.logWarning(clc.bold.yellow("functions: ") +
|
|
66
|
-
"package.json indicates an outdated version of firebase-functions
|
|
66
|
+
"package.json indicates an outdated version of firebase-functions. Please upgrade using " +
|
|
67
67
|
clc.bold("npm install --save firebase-functions@latest") +
|
|
68
68
|
" in your functions directory.");
|
|
69
69
|
if (semver.major(currentVersion) < semver.major(latest)) {
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.functionIdsAreValid = exports.functionsDirectoryExists = exports.endpointsAreValid = void 0;
|
|
3
|
+
exports.secretsAreValid = exports.functionIdsAreValid = exports.functionsDirectoryExists = exports.endpointsAreValid = void 0;
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const clc = require("cli-color");
|
|
6
6
|
const error_1 = require("../../error");
|
|
7
|
+
const secretManager_1 = require("../../gcp/secretManager");
|
|
8
|
+
const logger_1 = require("../../logger");
|
|
7
9
|
const fsutils = require("../../fsutils");
|
|
8
10
|
const backend = require("./backend");
|
|
11
|
+
const utils = require("../../utils");
|
|
12
|
+
const secrets = require("../../functions/secrets");
|
|
9
13
|
function endpointsAreValid(wantBackend) {
|
|
10
14
|
functionIdsAreValid(backend.allEndpoints(wantBackend));
|
|
11
15
|
const gcfV1WithConcurrency = backend
|
|
12
16
|
.allEndpoints(wantBackend)
|
|
13
|
-
.filter((endpoint) => (endpoint.concurrency || 1)
|
|
17
|
+
.filter((endpoint) => (endpoint.concurrency || 1) !== 1 && endpoint.platform === "gcfv1")
|
|
14
18
|
.map((endpoint) => endpoint.id);
|
|
15
19
|
if (gcfV1WithConcurrency.length) {
|
|
16
20
|
const msg = `Cannot set concurrency on the functions ${gcfV1WithConcurrency.join(",")} because they are GCF gen 1`;
|
|
@@ -19,7 +23,7 @@ function endpointsAreValid(wantBackend) {
|
|
|
19
23
|
const tooSmallForConcurrency = backend
|
|
20
24
|
.allEndpoints(wantBackend)
|
|
21
25
|
.filter((endpoint) => {
|
|
22
|
-
if ((endpoint.concurrency || 1)
|
|
26
|
+
if ((endpoint.concurrency || 1) === 1) {
|
|
23
27
|
return false;
|
|
24
28
|
}
|
|
25
29
|
const mem = endpoint.availableMemoryMb || backend.DEFAULT_MEMORY;
|
|
@@ -62,3 +66,54 @@ function functionIdsAreValid(functions) {
|
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
68
|
exports.functionIdsAreValid = functionIdsAreValid;
|
|
69
|
+
async function secretsAreValid(projectId, wantBackend) {
|
|
70
|
+
const endpoints = backend
|
|
71
|
+
.allEndpoints(wantBackend)
|
|
72
|
+
.filter((e) => e.secretEnvironmentVariables && e.secretEnvironmentVariables.length > 0);
|
|
73
|
+
validatePlatformTargets(endpoints);
|
|
74
|
+
await validateSecretVersions(projectId, endpoints);
|
|
75
|
+
}
|
|
76
|
+
exports.secretsAreValid = secretsAreValid;
|
|
77
|
+
function validatePlatformTargets(endpoints) {
|
|
78
|
+
const supportedPlatforms = ["gcfv1"];
|
|
79
|
+
const unsupported = endpoints.filter((e) => !supportedPlatforms.includes(e.platform));
|
|
80
|
+
if (unsupported.length > 0) {
|
|
81
|
+
const errs = unsupported.map((e) => `${e.id}[platform=${e.platform}]`);
|
|
82
|
+
throw new error_1.FirebaseError(`Tried to set secret environment variables on ${errs.join(", ")}. ` +
|
|
83
|
+
`Only ${supportedPlatforms.join(", ")} support secret environments.`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async function validateSecretVersions(projectId, endpoints) {
|
|
87
|
+
const toResolve = new Set();
|
|
88
|
+
for (const s of secrets.of(endpoints)) {
|
|
89
|
+
toResolve.add(s.secret);
|
|
90
|
+
}
|
|
91
|
+
const results = await utils.allSettled(Array.from(toResolve).map(async (secret) => {
|
|
92
|
+
const sv = await (0, secretManager_1.getSecretVersion)(projectId, secret, "latest");
|
|
93
|
+
logger_1.logger.debug(`Resolved secret version of ${clc.bold(secret)} to ${clc.bold(sv.versionId)}.`);
|
|
94
|
+
return sv;
|
|
95
|
+
}));
|
|
96
|
+
const secretVersions = {};
|
|
97
|
+
const errs = [];
|
|
98
|
+
for (const result of results) {
|
|
99
|
+
if (result.status === "fulfilled") {
|
|
100
|
+
const sv = result.value;
|
|
101
|
+
if (sv.state !== "ENABLED") {
|
|
102
|
+
errs.push(new error_1.FirebaseError(`Expected secret ${sv.secret.name}@${sv.versionId} to be in state ENABLED not ${sv.state}.`));
|
|
103
|
+
}
|
|
104
|
+
secretVersions[sv.secret.name] = sv;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
errs.push(new error_1.FirebaseError(result.reason.message));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (errs.length) {
|
|
111
|
+
throw new error_1.FirebaseError("Failed to validate secret versions", { children: errs });
|
|
112
|
+
}
|
|
113
|
+
for (const s of secrets.of(endpoints)) {
|
|
114
|
+
s.version = secretVersions[s.secret].versionId;
|
|
115
|
+
if (!s.version) {
|
|
116
|
+
throw new error_1.FirebaseError("Secret version is unexpectedly undefined. This should never happen.");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|